4266 lines
177 KiB
HTML
4266 lines
177 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||
<meta name="generator" content="pdoc 0.10.0" />
|
||
<title>database API documentation</title>
|
||
<meta name="description" content="" />
|
||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||
</head>
|
||
<body>
|
||
<main>
|
||
<article id="content">
|
||
<header>
|
||
<h1 class="title">Module <code>database</code></h1>
|
||
</header>
|
||
<section id="section-intro">
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">import datetime
|
||
import os
|
||
import re
|
||
import sqlite3 as sql
|
||
import tempfile
|
||
from src.logic.log import MyLogger
|
||
from icecream import ic
|
||
from typing import List, Tuple, Dict, Any, Optional, Union
|
||
from pathlib import Path
|
||
from omegaconf import OmegaConf
|
||
from src.backend.db import CREATE_TABLE_APPARAT, CREATE_TABLE_MESSAGES, CREATE_TABLE_MEDIA, CREATE_TABLE_APPKONTOS, CREATE_TABLE_FILES, CREATE_TABLE_PROF, CREATE_TABLE_USER, CREATE_TABLE_SUBJECTS
|
||
from src.logic.constants import SEMAP_MEDIA_ACCOUNTS
|
||
from src.logic.dataclass import ApparatData, BookData
|
||
from src.errors import NoResultError, AppPresentError
|
||
from src.utils import load_pickle, dump_pickle,create_blob
|
||
config = OmegaConf.load("config.yaml")
|
||
logger = MyLogger(__name__)
|
||
|
||
|
||
class Database:
|
||
"""
|
||
Initialize the database and create the tables if they do not exist.
|
||
"""
|
||
def __init__(self, db_path: str = None):
|
||
"""
|
||
Default constructor for the database class
|
||
|
||
Args:
|
||
db_path (str, optional): Optional Path for testing / specific purposes. Defaults to None.
|
||
"""
|
||
if db_path is None:
|
||
self.db_path = config.database.path + config.database.name
|
||
self.db_path = self.db_path.replace("~", str(Path.home()))
|
||
else:
|
||
self.db_path = db_path
|
||
if self.get_db_contents() is None:
|
||
logger.log_critical("Database does not exist, creating tables")
|
||
self.create_tables()
|
||
def get_db_contents(self)->Union[List[Tuple], None]:
|
||
"""
|
||
Get the contents of the
|
||
|
||
Returns:
|
||
Union[List[Tuple], None]: _description_
|
||
"""
|
||
try:
|
||
with sql.connect(self.db_path) as conn:
|
||
cursor = conn.cursor()
|
||
cursor.execute("SELECT * FROM sqlite_master WHERE type='table'")
|
||
return cursor.fetchall()
|
||
except sql.OperationalError:
|
||
return None
|
||
def connect(self)->sql.Connection:
|
||
"""
|
||
Connect to the database
|
||
|
||
Returns:
|
||
sql.Connection: The active connection to the database
|
||
"""
|
||
return sql.connect(self.db_path)
|
||
def close_connection(self, conn: sql.Connection):
|
||
"""
|
||
closes the connection to the database
|
||
|
||
Args:
|
||
----
|
||
- conn (sql.Connection): the connection to be closed
|
||
"""
|
||
conn.close()
|
||
def create_tables(self):
|
||
"""
|
||
Create the tables in the database
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
cursor.execute(CREATE_TABLE_APPARAT)
|
||
cursor.execute(CREATE_TABLE_MESSAGES)
|
||
cursor.execute(CREATE_TABLE_MEDIA)
|
||
cursor.execute(CREATE_TABLE_APPKONTOS)
|
||
cursor.execute(CREATE_TABLE_FILES)
|
||
cursor.execute(CREATE_TABLE_PROF)
|
||
cursor.execute(CREATE_TABLE_USER)
|
||
cursor.execute(CREATE_TABLE_SUBJECTS)
|
||
conn.commit()
|
||
self.close_connection(conn)
|
||
def insertInto(self, query:str, params:Tuple) -> None:
|
||
"""
|
||
Insert sent data into the database
|
||
|
||
Args:
|
||
query (str): The query to be executed
|
||
params (Tuple): the parameters to be inserted into the database
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
logger.log_info(f"Inserting {params} into database with query {query}")
|
||
cursor.execute(query, params)
|
||
conn.commit()
|
||
self.close_connection(conn)
|
||
def query_db(self, query: str, args: Tuple = (), one: bool = False)->Union[Tuple, List[Tuple]]:
|
||
"""
|
||
Query the Database for the sent query.
|
||
|
||
Args:
|
||
query (str): The query to be executed
|
||
args (Tuple, optional): The arguments for the query. Defaults to ().
|
||
one (bool, optional): Return the first result only. Defaults to False.
|
||
|
||
Returns:
|
||
Union[Typle|List[Tuple]]: Returns the result of the query
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
logger.log_info(f"Querying database with query {query}, args: {args}")
|
||
cursor.execute(query, args)
|
||
rv = cursor.fetchall()
|
||
conn.commit()
|
||
self.close_connection(conn)
|
||
return (rv[0] if rv else None) if one else rv
|
||
|
||
# Books
|
||
def addBookToDatabase(self, bookdata:BookData,app_id:Union[str,int], prof_id:Union[str,int]):
|
||
"""
|
||
Add books to the database. Both app_id and prof_id are required to add the book to the database, as the app_id and prof_id are used to select the books later on.
|
||
|
||
Args:
|
||
bookdata (BookData): The metadata of the book to be added
|
||
app_id (str): The apparat id where the book should be added to
|
||
prof_id (str): The id of the professor where the book should be added to.
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
t_query = (
|
||
f"SELECT bookdata FROM media WHERE app_id={app_id} AND prof_id={prof_id}"
|
||
)
|
||
# print(t_query)
|
||
result = cursor.execute(t_query).fetchall()
|
||
result = [load_pickle(i[0]) for i in result]
|
||
if bookdata in result:
|
||
print("Bookdata already in database")
|
||
# check if the book was deleted in the apparat
|
||
query = (
|
||
"SELECT deleted FROM media WHERE app_id=? AND prof_id=? AND bookdata=?"
|
||
)
|
||
params = (app_id, prof_id, dump_pickle(bookdata))
|
||
result = cursor.execute(query, params).fetchone()
|
||
if result[0] == 1:
|
||
print("Book was deleted, updating bookdata")
|
||
query = "UPDATE media SET deleted=0 WHERE app_id=? AND prof_id=? AND bookdata=?"
|
||
params = (app_id, prof_id, dump_pickle(bookdata))
|
||
cursor.execute(query, params)
|
||
conn.commit()
|
||
return
|
||
|
||
query = (
|
||
"INSERT INTO media (bookdata, app_id, prof_id,deleted) VALUES (?, ?, ?,?)"
|
||
)
|
||
converted = dump_pickle(bookdata)
|
||
params = (converted, app_id, prof_id, 0)
|
||
cursor.execute(query, params)
|
||
conn.commit()
|
||
self.close_connection(conn)
|
||
def getBookIdBasedOnSignature(self, app_id:Union[str,int], prof_id:Union[str,int],signature:str)->int:
|
||
"""
|
||
Get a book id based on the signature of the book.
|
||
|
||
Args:
|
||
app_id (str): The apparat id the book should be associated with
|
||
prof_id (str): The professor id the book should be associated with
|
||
signature (str): The signature of the book
|
||
|
||
Returns:
|
||
int: The id of the book
|
||
"""
|
||
result = self.query_db("SELECT bookdata, id FROM media WHERE app_id=? AND prof_id=?", (app_id,prof_id))
|
||
books = [(load_pickle(i[0]),i[1]) for i in result]
|
||
book = [i for i in books if i[0].signature == signature][0][1]
|
||
return book
|
||
def getBookBasedOnSignature(self, app_id:Union[str,int], prof_id:Union[str,int],signature:str)->BookData:
|
||
"""
|
||
Get the book based on the signature of the book.
|
||
|
||
Args:
|
||
app_id (str): The apparat id the book should be associated with
|
||
prof_id (str): The professor id the book should be associated with
|
||
signature (str): The signature of the book
|
||
|
||
Returns:
|
||
BookData: The total metadata of the book wrapped in a BookData object
|
||
"""
|
||
result = self.query_db("SELECT bookdata FROM media WHERE app_id=? AND prof_id=?", (app_id,prof_id))
|
||
books = [load_pickle(i[0]) for i in result]
|
||
book = [i for i in books if i.signature == signature][0]
|
||
return book
|
||
def getLastBookId(self)->int:
|
||
"""
|
||
Get the last book id in the database
|
||
|
||
Returns:
|
||
int: ID of the last book in the database
|
||
"""
|
||
return self.query_db("SELECT id FROM media ORDER BY id DESC", one=True)[0]
|
||
def searchBook(self, data:dict[str, str])->list[tuple[BookData, int]]:
|
||
"""
|
||
Search a book in the database based on the sent data.
|
||
|
||
Args:
|
||
data (dict[str, str]): A dictionary containing the data to be searched for. The dictionary can contain the following:
|
||
- signature: The signature of the book
|
||
- title: The title of the book
|
||
|
||
Returns:
|
||
list[tuple[BookData, int]]: A list of tuples containing the wrapped Metadata and the id of the book
|
||
"""
|
||
rdata = self.query_db("SELECT * FROM media WHERE deleted=0")
|
||
ic(rdata, len(rdata))
|
||
mode = 0
|
||
if len(data)== 1:
|
||
if "signature" in data.keys():
|
||
mode = 1
|
||
elif "title" in data.keys():
|
||
mode = 2
|
||
elif len(data) == 2:
|
||
mode = 3
|
||
else:
|
||
return None
|
||
ret = []
|
||
for book in rdata:
|
||
bookdata = load_pickle(book[1])
|
||
app_id = book[2]
|
||
prof_id = book[3]
|
||
if mode == 1:
|
||
if data["signature"] in bookdata.signature:
|
||
ret.append((bookdata,app_id,prof_id))
|
||
elif mode == 2:
|
||
if data["title"] in bookdata.title:
|
||
ret.append((bookdata,app_id,prof_id))
|
||
elif mode == 3:
|
||
if data["signature"] in bookdata.signature and data["title"] in bookdata.title:
|
||
ret.append((bookdata,app_id,prof_id))
|
||
ic(ret)
|
||
return ret
|
||
def setAvailability(self, book_id:str, available:str):
|
||
"""
|
||
Set the availability of a book in the database
|
||
|
||
Args:
|
||
book_id (str): The id of the book
|
||
available (str): The availability of the book
|
||
"""
|
||
self.query_db("UPDATE media SET available=? WHERE id=?", (available,book_id))
|
||
def getBookId(self, bookdata:BookData, app_id:Union[str,int], prof_id:Union[str,int])->int:
|
||
"""
|
||
Get the id of a book based on the metadata of the book
|
||
|
||
Args:
|
||
bookdata (BookData): The wrapped metadata of the book
|
||
app_id (str): The apparat id the book should be associated with
|
||
prof_id (str): The professor id the book should be associated with
|
||
|
||
Returns:
|
||
int: ID of the book
|
||
"""
|
||
result = self.query_db("SELECT id FROM media WHERE bookdata=? AND app_id=? AND prof_id=?", (dump_pickle(bookdata),app_id,prof_id), one=True)
|
||
return result[0]
|
||
def getBook(self,book_id:int)->BookData:
|
||
"""
|
||
Get the book based on the id in the database
|
||
|
||
Args:
|
||
book_id (int): The id of the book
|
||
|
||
Returns:
|
||
BookData: The metadata of the book wrapped in a BookData object
|
||
"""
|
||
return load_pickle(self.query_db("SELECT bookdata FROM media WHERE id=?", (book_id,), one=True)[0])
|
||
def getBooks(self, app_id:Union[str,int], prof_id:Union[str,int], deleted=0)->list[dict[int, BookData, int]]:
|
||
"""
|
||
Get the Books based on the apparat id and the professor id
|
||
|
||
Args:
|
||
app_id (str): The ID of the apparat
|
||
prof_id (str): The ID of the professor
|
||
deleted (int, optional): The state of the book. Set to 1 to include deleted ones. Defaults to 0.
|
||
|
||
Returns:
|
||
list[dict[int, BookData, int]]: A list of dictionaries containing the id, the metadata of the book and the availability of the book
|
||
"""
|
||
qdata = self.query_db(f"SELECT id,bookdata,available FROM media WHERE (app_id={app_id} AND prof_id={prof_id}) AND (deleted={deleted if deleted == 0 else '1 OR deleted=0'})")
|
||
ret_result = []
|
||
for result_a in qdata:
|
||
data = {"id": int, "bookdata": BookData, "available": int}
|
||
data["id"] = result_a[0]
|
||
data["bookdata"] = load_pickle(result_a[1])
|
||
data["available"] = result_a[2]
|
||
ret_result.append(data)
|
||
return ret_result
|
||
def updateBookdata(self, book_id, bookdata:BookData):
|
||
"""
|
||
Update the bookdata in the database
|
||
|
||
Args:
|
||
book_id (str): The id of the book
|
||
bookdata (BookData): The new metadata of the book
|
||
"""
|
||
self.query_db("UPDATE media SET bookdata=? WHERE id=?", (dump_pickle(bookdata),book_id))
|
||
def deleteBook(self, book_id):
|
||
"""
|
||
Delete a book from the database
|
||
|
||
Args:
|
||
book_id (str): ID of the book
|
||
"""
|
||
self.query_db("UPDATE media SET deleted=1 WHERE id=?", (book_id,))
|
||
|
||
# File Interactions
|
||
def getBlob(self, filename, app_id:Union[str,int]):
|
||
"""
|
||
Get a blob from the database
|
||
|
||
Args:
|
||
filename (str): The name of the file
|
||
app_id (str): ID of the apparat
|
||
|
||
Returns:
|
||
bytes: The file stored in
|
||
"""
|
||
return self.query_db("SELECT fileblob FROM files WHERE filename=? AND app_id=?", (filename,app_id), one=True)[0]
|
||
def insertFile(self, file: list[dict], app_id:Union[str,int], prof_id:Union[str,int]):
|
||
"""Instert a list of files into the database
|
||
|
||
Args:
|
||
file (list[dict]): a list containing all the files to be inserted
|
||
Structured: [{"name": "filename", "path": "path", "type": "filetype"}]
|
||
app_id (int): the id of the apparat
|
||
prof_id (str): the id of the professor
|
||
"""
|
||
for f in file:
|
||
filename = f["name"]
|
||
path = f["path"]
|
||
filetyp = f["type"]
|
||
if path == "Database":
|
||
continue
|
||
blob = create_blob(path)
|
||
query = "INSERT OR IGNORE INTO files (filename, fileblob, app_id, filetyp,prof_id) VALUES (?, ?, ?, ?,?)"
|
||
self.query_db(query, (filename, blob, app_id, filetyp,prof_id))
|
||
def recreateFile(self, filename:str, app_id:Union[str,int],filetype:str)->str:
|
||
"""Recreate a file from the database
|
||
|
||
Args:
|
||
filename (str): the name of the file
|
||
app_id (Union[str,int]): the id of the apparat
|
||
filetype (str): the extension of the file to be created
|
||
|
||
Returns:
|
||
str: The filename of the recreated file
|
||
"""
|
||
blob = self.getBlob(filename, app_id)
|
||
tempdir = config.database.tempdir
|
||
tempdir = tempdir.replace("~", str(Path.home()))
|
||
tempdir_path = Path(tempdir)
|
||
if not os.path.exists(tempdir_path):
|
||
os.mkdir(tempdir_path)
|
||
file = tempfile.NamedTemporaryFile(
|
||
delete=False, dir=tempdir_path, mode="wb", suffix=f".{filetype}"
|
||
)
|
||
file.write(blob)
|
||
print("file created")
|
||
return file.name
|
||
def getFiles(self, app_id:Union[str,int], prof_id:int)->list[tuple]:
|
||
"""Get all the files associated with the apparat and the professor
|
||
|
||
Args:
|
||
app_id (Union[str,int]): The id of the apparat
|
||
prof_id (Union[str,int]): the id of the professor
|
||
|
||
Returns:
|
||
list[tuple]: a list of tuples containing the filename and the filetype for the corresponding apparat and professor
|
||
"""
|
||
return self.query_db("SELECT filename, filetyp FROM files WHERE app_id=? AND prof_id=?", (app_id,prof_id))
|
||
|
||
def getSemersters(self)->list[str]:
|
||
"""Return all the unique semesters in the database
|
||
|
||
Returns:
|
||
list: a list of strings containing the semesters
|
||
"""
|
||
data = self.query_db("SELECT DISTINCT erstellsemester FROM semesterapparat")
|
||
return [i[0] for i in data]
|
||
|
||
def getSubjects(self):
|
||
"""Get all the subjects in the database
|
||
|
||
Returns:
|
||
list[tuple]: a list of tuples containing the subjects
|
||
"""
|
||
return self.query_db("SELECT * FROM subjects")
|
||
|
||
# Messages
|
||
def addMessage(self, message:dict,user:str, app_id:Union[str,int]):
|
||
"""add a Message to the database
|
||
|
||
Args:
|
||
message (dict): the message to be added
|
||
user (str): the user who added the message
|
||
app_id (Union[str,int]): the id of the apparat
|
||
"""
|
||
def __getUserId(user):
|
||
return self.query_db("SELECT id FROM user WHERE username=?", (user,), one=True)[0]
|
||
user_id = __getUserId(user)
|
||
self.query_db("INSERT INTO messages (message, user_id, remind_at,appnr) VALUES (?,?,?,?)", (message["message"],user_id,message["remind_at"],app_id))
|
||
def getMessages(self, date:str)->list[dict[str, str, str, str]]:
|
||
"""Get all the messages for a specific date
|
||
|
||
Args:
|
||
date (str): a date.datetime object formatted as a string in the format "YYYY-MM-DD"
|
||
|
||
Returns:
|
||
list[dict[str, str, str, str]]: a list of dictionaries containing the message, the user who added the message, the apparat id and the id of the message
|
||
"""
|
||
def __get_user_name(user_id):
|
||
return self.query_db("SELECT username FROM user WHERE id=?", (user_id,), one=True)[0]
|
||
messages = self.query_db("SELECT * FROM messages WHERE remind_at=?", (date,))
|
||
ret = [
|
||
{
|
||
"message": i[2],
|
||
"user": __get_user_name(i[4]),
|
||
"appnr": i[5],
|
||
"id": i[0]
|
||
}
|
||
for i in messages
|
||
]
|
||
return ret
|
||
def deleteMessage(self, message_id):
|
||
"""Delete a message from the database
|
||
|
||
Args:
|
||
message_id (str): the id of the message
|
||
"""
|
||
self.query_db("DELETE FROM messages WHERE id=?", (message_id,))
|
||
|
||
# Prof data
|
||
def getProfNameById(self, prof_id:Union[str,int],add_title:bool=False)->str:
|
||
"""Get a professor name based on the id
|
||
|
||
Args:
|
||
prof_id (Union[str,int]): The id of the professor
|
||
add_title (bool, optional): wether to add the title or no. Defaults to False.
|
||
|
||
Returns:
|
||
str: The name of the professor
|
||
"""
|
||
prof = self.query_db("SELECT fullname FROM prof WHERE id=?", (prof_id,), one=True)
|
||
if add_title:
|
||
return f"{self.getTitleById(prof_id)}{prof[0]}"
|
||
else:
|
||
return prof[0]
|
||
def getTitleById(self, prof_id:Union[str,int])->str:
|
||
"""get the title of a professor based on the id
|
||
|
||
Args:
|
||
prof_id (Union[str,int]): the id of the professor
|
||
|
||
Returns:
|
||
str: the title of the professor, with an added whitespace at the end, if no title is present, an empty string is returned
|
||
"""
|
||
title = self.query_db("SELECT titel FROM prof WHERE id=?", (prof_id,), one=True)[0]
|
||
return f"{title} " if title is not None else ""
|
||
def getProfByName(self, prof_name:str)->tuple:
|
||
"""get all the data of a professor based on the name
|
||
|
||
Args:
|
||
prof_name (str): the name of the professor
|
||
|
||
Returns:
|
||
tuple: the data of the professor
|
||
"""
|
||
return self.query_db("SELECT * FROM prof WHERE fullname=?", (prof_name,), one=True)
|
||
def getProfId(self, prof_name:str)->Optional[int]:
|
||
"""Get the id of a professor based on the name
|
||
|
||
Args:
|
||
prof_name (str): the name of the professor
|
||
|
||
Returns:
|
||
Optional[int]: the id of the professor, if the professor is not found, None is returned
|
||
"""
|
||
|
||
data = self.getProfByName(prof_name.replace(",", ""))
|
||
if data is None:
|
||
return None
|
||
else:
|
||
return data[0]
|
||
def getSpecificProfData(self, prof_id:Union[str,int], fields:List[str])->tuple:
|
||
"""A customisable function to get specific data of a professor based on the id
|
||
|
||
Args:
|
||
prof_id (Union[str,int]): the id of the professor
|
||
fields (List[str]): a list of fields to be returned
|
||
|
||
Returns:
|
||
tuple: a tuple containing the requested data
|
||
"""
|
||
query = "SELECT "
|
||
for field in fields:
|
||
query += f"{field},"
|
||
query = query[:-1]
|
||
query += " FROM prof WHERE id=?"
|
||
return self.query_db(query, (prof_id,), one=True)[0]
|
||
def getProfData(self, profname:str):
|
||
"""Get mail, telephone number and title of a professor based on the name
|
||
|
||
Args:
|
||
profname (str): name of the professor
|
||
|
||
Returns:
|
||
tuple: the mail, telephone number and title of the professor
|
||
"""
|
||
data = self.query_db("SELECT mail, telnr, titel FROM prof WHERE fullname=?", (profname.replace(",",""),), one=True)
|
||
return data
|
||
def createProf(self, prof_details:dict):
|
||
"""Create a professor in the database
|
||
|
||
Args:
|
||
prof_details (dict): a dictionary containing the details of the professor
|
||
"""
|
||
prof_title = prof_details["prof_title"]
|
||
prof_fname = prof_details["profname"].split(",")[1]
|
||
prof_fname = prof_fname.strip()
|
||
prof_lname = prof_details["profname"].split(",")[0]
|
||
prof_lname = prof_lname.strip()
|
||
prof_fullname = prof_details["profname"].replace(",", "")
|
||
prof_mail = prof_details["prof_mail"]
|
||
prof_tel = prof_details["prof_tel"]
|
||
params = (prof_title, prof_fname, prof_lname, prof_mail, prof_tel, prof_fullname)
|
||
query = "INSERT OR IGNORE INTO prof (titel, fname, lname, mail, telnr, fullname) VALUES (?, ?, ?, ?, ?, ?)"
|
||
self.insertInto(query=query, params=params)
|
||
def getProfs(self)->list[tuple]:
|
||
"""Return all the professors in the database
|
||
|
||
Returns:
|
||
list[tuple]: a list containing all the professors in individual tuples
|
||
"""
|
||
return self.query_db("SELECT * FROM prof")
|
||
|
||
# Apparat
|
||
def getAllAparats(self,deleted=0)->list[tuple]:
|
||
"""Get all the apparats in the database
|
||
|
||
Args:
|
||
deleted (int, optional): Switch the result to use . Defaults to 0.
|
||
|
||
Returns:
|
||
list[tuple]: a list of tuples containing the apparats
|
||
"""
|
||
return self.query_db("SELECT * FROM semesterapparat WHERE deletion_status=?", (deleted,))
|
||
def getApparatData(self, appnr, appname)->ApparatData:
|
||
"""Get the Apparat data based on the apparat number and the name
|
||
|
||
Args:
|
||
appnr (str): the apparat number
|
||
appname (str): the name of the apparat
|
||
|
||
Raises:
|
||
NoResultError: an error is raised if no result is found
|
||
|
||
Returns:
|
||
ApparatData: the appended data of the apparat wrapped in an ApparatData object
|
||
"""
|
||
result = self.query_db("SELECT * FROM semesterapparat WHERE appnr=? AND name=?", (appnr,appname), one=True)
|
||
if result is None:
|
||
raise NoResultError("No result found")
|
||
apparat = ApparatData()
|
||
apparat.appname = result[1]
|
||
apparat.appnr = result[4]
|
||
apparat.dauerapp = True if result[7] == 1 else False
|
||
prof_data = self.getProfData(self.getProfNameById(result[2]))
|
||
apparat.profname = self.getProfNameById(result[2])
|
||
apparat.prof_mail = prof_data[0]
|
||
apparat.prof_tel = prof_data[1]
|
||
apparat.prof_title = prof_data[2]
|
||
apparat.app_fach = result[3]
|
||
apparat.erstellsemester = result[5]
|
||
apparat.semester = result[8]
|
||
apparat.deleted = result[9]
|
||
apparat.apparat_adis_id = result[11]
|
||
apparat.prof_adis_id = result[12]
|
||
return apparat
|
||
def getUnavailableApparatNumbers(self)->List[int]:
|
||
"""Get a list of all the apparat numbers in the database that are currently in use
|
||
|
||
Returns:
|
||
List[int]: the list of used apparat numbers
|
||
"""
|
||
numbers = self.query_db("SELECT appnr FROM semesterapparat WHERE deletion_status=0")
|
||
numbers = [i[0] for i in numbers]
|
||
logger.log_info(f"Currently used apparat numbers: {numbers}")
|
||
return numbers
|
||
def setNewSemesterDate(self, app_id:Union[str,int], newDate, dauerapp=False):
|
||
"""Set the new semester date for an apparat
|
||
|
||
Args:
|
||
app_id (Union[str,int]): the id of the apparat
|
||
newDate (str): the new date
|
||
dauerapp (bool, optional): if the apparat was changed to dauerapparat. Defaults to False.
|
||
"""
|
||
date = datetime.datetime.strptime(newDate, "%d.%m.%Y").strftime("%Y-%m-%d")
|
||
if dauerapp:
|
||
self.query_db("UPDATE semesterapparat SET verlängerung_bis=?, dauerapp=? WHERE appnr=?", (date,dauerapp,app_id))
|
||
else:
|
||
self.query_db("UPDATE semesterapparat SET endsemester=? WHERE appnr=?", (date,app_id))
|
||
def getApparatId(self, apparat_name)->Optional[int]:
|
||
"""get the id of an apparat based on the name
|
||
|
||
Args:
|
||
apparat_name (str): the name of the apparat e.g. "Semesterapparat 1"
|
||
|
||
Returns:
|
||
Optional[int]: the id of the apparat, if the apparat is not found, None is returned
|
||
"""
|
||
data = self.query_db("SELECT appnr FROM semesterapparat WHERE name=?", (apparat_name,), one=True)
|
||
if data is None:
|
||
return None
|
||
else:
|
||
return data[0]
|
||
def createApparat(self, apparat:ApparatData)->int:
|
||
"""create the apparat in the database
|
||
|
||
Args:
|
||
apparat (ApparatData): the wrapped metadata of the apparat
|
||
|
||
Raises:
|
||
AppPresentError: an error describing that the apparats chosen id is already present in the database
|
||
|
||
Returns:
|
||
Optional[int]: the id of the apparat
|
||
"""
|
||
|
||
prof_id = self.getProfId(apparat.profname)
|
||
app_id = self.getApparatId(apparat.appname)
|
||
if app_id:
|
||
raise AppPresentError(app_id)
|
||
|
||
self.createProf(apparat.get_prof_details())
|
||
prof_id = self.getProfId(apparat.profname)
|
||
ic(prof_id)
|
||
query = f"INSERT OR IGNORE INTO semesterapparat (appnr, name, erstellsemester, dauer, prof_id, fach,deletion_status,konto) VALUES ('{apparat.appnr}', '{apparat.appname}', '{apparat.semester}', '{apparat.dauerapp}', {prof_id}, '{apparat.app_fach}', '{0}', '{SEMAP_MEDIA_ACCOUNTS[apparat.appnr]}')"
|
||
logger.log_info(query)
|
||
self.query_db(query)
|
||
return self.getApparatId(apparat.appname)
|
||
def getApparatsByProf(self, prof_id:Union[str,int])->list[tuple]:
|
||
"""Get all apparats based on the professor id
|
||
|
||
Args:
|
||
prof_id (Union[str,int]): the id of the professor
|
||
|
||
Returns:
|
||
list[tuple]: a list of tuples containing the apparats
|
||
"""
|
||
return self.query_db("SELECT * FROM semesterapparat WHERE prof_id=?", (prof_id,))
|
||
def getApparatsBySemester(self, semester:str)->dict[list]:
|
||
"""get all apparats based on the semester
|
||
|
||
Args:
|
||
semester (str): the selected semester
|
||
|
||
Returns:
|
||
dict[list]: a list off all created and deleted apparats for the selected semester
|
||
"""
|
||
data = self.query_db("SELECT name, prof_id FROM semesterapparat WHERE erstellsemester=?", (semester,))
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
c_tmp = []
|
||
for i in data:
|
||
c_tmp.append((i[0], self.getProfNameById(i[1])))
|
||
query = (
|
||
f"SELECT name,prof_id FROM semesterapparat WHERE deleted_date='{semester}'"
|
||
)
|
||
result = cursor.execute(query).fetchall()
|
||
d_tmp = []
|
||
for i in result:
|
||
d_tmp.append((i[0], self.getProfNameById(i[1])))
|
||
# group the apparats by prof
|
||
c_ret = {}
|
||
for i in c_tmp:
|
||
if i[1] not in c_ret.keys():
|
||
c_ret[i[1]] = [i[0]]
|
||
else:
|
||
c_ret[i[1]].append(i[0])
|
||
d_ret = {}
|
||
for i in d_tmp:
|
||
if i[1] not in d_ret.keys():
|
||
d_ret[i[1]] = [i[0]]
|
||
else:
|
||
d_ret[i[1]].append(i[0])
|
||
self.close_connection(conn)
|
||
return {"created": c_ret, "deleted": d_ret}
|
||
def getApparatCountBySemester(self)->tuple[list[str],list[int]]:
|
||
"""get a list of all apparats created and deleted by semester
|
||
|
||
Returns:
|
||
tuple[list[str],list[int]]: a tuple containing two lists, the first list contains the semesters, the second list contains the amount of apparats created and deleted for the corresponding semester
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
semesters = self.getSemersters()
|
||
created = []
|
||
deleted = []
|
||
for semester in semesters:
|
||
query = f"SELECT COUNT(*) FROM semesterapparat WHERE erstellsemester='{semester}'"
|
||
result = cursor.execute(query).fetchone()
|
||
created.append(result[0])
|
||
query = f"SELECT COUNT(*) FROM semesterapparat WHERE deletion_status=1 AND deleted_date='{semester}'"
|
||
result = cursor.execute(query).fetchone()
|
||
deleted.append(result[0])
|
||
# store data in a tuple
|
||
ret = []
|
||
e_tuple = ()
|
||
for sem in semesters:
|
||
e_tuple = (
|
||
sem,
|
||
created[semesters.index(sem)],
|
||
deleted[semesters.index(sem)],
|
||
)
|
||
ret.append(e_tuple)
|
||
self.close_connection(conn)
|
||
return ret
|
||
def deleteApparat(self, app_id:Union[str,int], semester:str):
|
||
"""Delete an apparat from the database
|
||
|
||
Args:
|
||
app_id (Union[str, int]): the id of the apparat
|
||
semester (str): the semester the apparat should be deleted from
|
||
"""
|
||
self.query_db("UPDATE semesterapparat SET deletion_status=1, deleted_date=? WHERE appnr=?", (semester,app_id))
|
||
def isEternal(self, id):
|
||
"""check if the apparat is eternal (dauerapparat)
|
||
|
||
Args:
|
||
id (int): the id of the apparat to be checked
|
||
|
||
Returns:
|
||
int: the state of the apparat
|
||
"""
|
||
return self.query_db("SELECT dauer FROM semesterapparat WHERE appnr=?", (id,), one=True)
|
||
def getApparatName(self, app_id:Union[str,int], prof_id:Union[str,int]):
|
||
"""get the name of the apparat based on the id
|
||
|
||
Args:
|
||
app_id (Union[str,int]): the id of the apparat
|
||
prof_id (Union[str,int]): the id of the professor
|
||
|
||
Returns:
|
||
str: the name of the apparat
|
||
"""
|
||
return self.query_db("SELECT name FROM semesterapparat WHERE appnr=? AND prof_id=?", (app_id,prof_id), one=True)[0]
|
||
def updateApparat(self, apparat_data:ApparatData):
|
||
"""Update an apparat in the database
|
||
|
||
Args:
|
||
apparat_data (ApparatData): the new metadata of the apparat
|
||
"""
|
||
query = f"UPDATE semesterapparat SET name = ?, fach = ?, dauer = ?, prof_id = ? WHERE appnr = ?"
|
||
params = (
|
||
apparat_data.appname,
|
||
apparat_data.app_fach,
|
||
apparat_data.dauerapp,
|
||
self.getProfId(apparat_data.profname),
|
||
apparat_data.appnr,
|
||
)
|
||
self.query_db(query, params)
|
||
def checkApparatExists(self, apparat_name:str):
|
||
"""check if the apparat is already present in the database based on the name
|
||
|
||
Args:
|
||
apparat_name (str): the name of the apparat
|
||
|
||
Returns:
|
||
bool: True if the apparat is present, False if not
|
||
"""
|
||
return True if self.query_db("SELECT appnr FROM semesterapparat WHERE name=?", (apparat_name,), one=True) else False
|
||
def checkApparatExistsById(self, app_id:Union[str,int])->bool:
|
||
"""a check to see if the apparat is already present in the database, based on the id
|
||
|
||
Args:
|
||
app_id (Union[str, int]): the id of the apparat
|
||
|
||
Returns:
|
||
bool: True if the apparat is present, False if not
|
||
"""
|
||
return True if self.query_db("SELECT appnr FROM semesterapparat WHERE appnr=?", (app_id,), one=True) else False
|
||
# Statistics
|
||
def statistic_request(self, **kwargs: Any):
|
||
"""Take n amount of kwargs and return the result of the query
|
||
"""
|
||
def __query(query):
|
||
"""execute the query and return the result
|
||
|
||
Args:
|
||
query (str): the constructed query
|
||
|
||
Returns:
|
||
list: the result of the query
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
result = cursor.execute(query).fetchall()
|
||
for result_a in result:
|
||
orig_value = result_a
|
||
prof_name = self.getProfNameById(result_a[2])
|
||
# replace the prof_id with the prof_name
|
||
result_a = list(result_a)
|
||
result_a[2] = prof_name
|
||
result_a = tuple(result_a)
|
||
result[result.index(orig_value)] = result_a
|
||
self.close_connection(conn)
|
||
return result
|
||
if "deletable" in kwargs.keys():
|
||
query = f"SELECT * FROM semesterapparat WHERE deletion_status=0 AND dauer=0 AND (erstellsemester!='{kwargs['deletesemester']}' OR verlängerung_bis!='{kwargs['deletesemester']}')"
|
||
return __query(query)
|
||
if "dauer" in kwargs.keys():
|
||
kwargs["dauer"] = kwargs["dauer"].replace("Ja", "1").replace("Nein", "0")
|
||
query = "SELECT * FROM semesterapparat WHERE "
|
||
for key, value in kwargs.items() if kwargs.items() is not None else {}:
|
||
print(key, value)
|
||
query += f"{key}='{value}' AND "
|
||
print(query)
|
||
# remove deletesemester part from normal query, as this will be added to the database upon deleting the apparat
|
||
if "deletesemester" in kwargs.keys():
|
||
query = query.replace(
|
||
f"deletesemester='{kwargs['deletesemester']}' AND ", ""
|
||
)
|
||
if "endsemester" in kwargs.keys():
|
||
if "erstellsemester" in kwargs.keys():
|
||
query = query.replace(f"endsemester='{kwargs['endsemester']}' AND ", "")
|
||
query = query.replace(
|
||
f"erstellsemester='{kwargs['erstellsemester']} AND ", "xyz"
|
||
)
|
||
else:
|
||
query = query.replace(
|
||
f"endsemester='{kwargs['endsemester']}' AND ", "xyz"
|
||
)
|
||
print("replaced")
|
||
query = query.replace(
|
||
"xyz",
|
||
f"(erstellsemester='{kwargs['endsemester']}' OR verlängerung_bis='{kwargs['endsemester']}') AND ",
|
||
)
|
||
# remove all x="" parts from the query where x is a key in kwargs
|
||
query = query[:-5]
|
||
print(query)
|
||
return __query(query)
|
||
|
||
# Admin data
|
||
def getUser(self):
|
||
"""Get a single user from the database"""
|
||
return self.query_db("SELECT * FROM user", one=True)
|
||
def getUsers(self)->list[tuple]:
|
||
"""Return a list of tuples of all the users in the database"""
|
||
return self.query_db("SELECT * FROM user")
|
||
|
||
def login(self, user, hashed_password):
|
||
"""try to login the user.
|
||
The salt for the user will be requested from the database and then added to the hashed password. The password will then be compared to the password in the database
|
||
|
||
Args:
|
||
user (str): username that tries to login
|
||
hashed_password (str): the password the user tries to login with
|
||
|
||
Returns:
|
||
bool: True if the login was successful, False if not
|
||
"""
|
||
salt = self.query_db("SELECT salt FROM user WHERE username=?", (user,), one=True)[0]
|
||
if salt is None:
|
||
return False
|
||
hashed_password = salt + hashed_password
|
||
password = self.query_db("SELECT password FROM user WHERE username=?", (user,), one=True)[0]
|
||
if password == hashed_password:
|
||
return True
|
||
else:
|
||
return False
|
||
def changePassword(self, user, new_password):
|
||
"""change the password of a user.
|
||
The password will be added with the salt and then committed to the database
|
||
|
||
Args:
|
||
user (str): username
|
||
new_password (str): the hashed password
|
||
"""
|
||
salt = self.query_db("SELECT salt FROM user WHERE username=?", (user,), one=True)[0]
|
||
new_password = salt + new_password
|
||
self.query_db("UPDATE user SET password=? WHERE username=?", (new_password,user))
|
||
def getRole(self, user):
|
||
"""get the role of the user
|
||
|
||
Args:
|
||
user (str): username
|
||
|
||
Returns:
|
||
str: the name of the role
|
||
"""
|
||
return self.query_db("SELECT role FROM user WHERE username=?", (user,), one=True)[0]
|
||
def getRoles(self)->list[tuple]:
|
||
"""get all the roles in the database
|
||
|
||
Returns:
|
||
list[str]: a list of all the roles
|
||
"""
|
||
return self.query_db("SELECT role FROM user")
|
||
def checkUsername(self, user)->bool:
|
||
"""a check to see if the username is already present in the database
|
||
|
||
Args:
|
||
user (str): the username
|
||
|
||
Returns:
|
||
bool: True if the username is present, False if not
|
||
"""
|
||
data = self.query_db("SELECT username FROM user WHERE username=?", (user,), one=True)
|
||
return True if data is not None else False
|
||
def createUser(self, user, password, role, salt):
|
||
"""create an user from the AdminCommands class.
|
||
|
||
Args:
|
||
user (str): the username of the user
|
||
password (str): a hashed password
|
||
role (str): the role of the user
|
||
salt (str): a salt for the password
|
||
"""
|
||
self.query_db("INSERT OR IGNORE INTO user (username, password, role, salt) VALUES (?,?,?,?)", (user,password,role,salt))
|
||
def deleteUser(self, user):
|
||
"""delete an unser
|
||
|
||
Args:
|
||
user (str): username of the user
|
||
"""
|
||
self.query_db("DELETE FROM user WHERE username=?", (user,))
|
||
def updateUser(self, username, data:dict[str, str]):
|
||
"""changge the data of a user
|
||
|
||
Args:
|
||
username (str): the username of the user
|
||
data (dict[str, str]): the data to be changed
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
query = "UPDATE user SET "
|
||
for key,value in data.items():
|
||
if key == "username":
|
||
continue
|
||
query += f"{key}='{value}',"
|
||
query = query[:-1]
|
||
query += " WHERE username=?"
|
||
params = (username,)
|
||
cursor.execute(query, params)
|
||
conn.commit()
|
||
self.close_connection(conn)
|
||
def getFacultyMember(self, name:str)->tuple:
|
||
"""get a faculty member based on the name
|
||
|
||
Args:
|
||
name (str): the name to be searched for
|
||
|
||
Returns:
|
||
tuple: a tuple containing the data of the faculty member
|
||
"""
|
||
return self.query_db("SELECT titel, fname,lname,mail,telnr,fullname FROM prof WHERE fullname=?", (name,), one=True)
|
||
def updateFacultyMember(self, data:dict, oldlname:str, oldfname:str):
|
||
"""update the data of a faculty member
|
||
|
||
Args:
|
||
data (dict): a dictionary containing the data to be updated
|
||
oldlname (str): the old last name of the faculty member
|
||
oldfname (str): the old first name of the faculty member
|
||
"""
|
||
placeholders = ", ".join([f"{i}=:{i} " for i in data.keys()])
|
||
query = f"UPDATE prof SET {placeholders} WHERE lname = :oldlname AND fname = :oldfname"
|
||
data["oldlname"] = oldlname
|
||
data["oldfname"] = oldfname
|
||
self.query_db(query, data)
|
||
def getFacultyMembers(self):
|
||
"""get a list of all faculty members
|
||
|
||
Returns:
|
||
list[tuple]: a list of tuples containing the faculty members
|
||
"""
|
||
return self.query_db("SELECT titel, fname,lname,mail,telnr,fullname FROM prof")</code></pre>
|
||
</details>
|
||
</section>
|
||
<section>
|
||
</section>
|
||
<section>
|
||
</section>
|
||
<section>
|
||
</section>
|
||
<section>
|
||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||
<dl>
|
||
<dt id="database.Database"><code class="flex name class">
|
||
<span>class <span class="ident">Database</span></span>
|
||
<span>(</span><span>db_path: str = None)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Initialize the database and create the tables if they do not exist.</p>
|
||
<p>Default constructor for the database class</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>db_path</code></strong> : <code>str</code>, optional</dt>
|
||
<dd>Optional Path for testing / specific purposes. Defaults to None.</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">class Database:
|
||
"""
|
||
Initialize the database and create the tables if they do not exist.
|
||
"""
|
||
def __init__(self, db_path: str = None):
|
||
"""
|
||
Default constructor for the database class
|
||
|
||
Args:
|
||
db_path (str, optional): Optional Path for testing / specific purposes. Defaults to None.
|
||
"""
|
||
if db_path is None:
|
||
self.db_path = config.database.path + config.database.name
|
||
self.db_path = self.db_path.replace("~", str(Path.home()))
|
||
else:
|
||
self.db_path = db_path
|
||
if self.get_db_contents() is None:
|
||
logger.log_critical("Database does not exist, creating tables")
|
||
self.create_tables()
|
||
def get_db_contents(self)->Union[List[Tuple], None]:
|
||
"""
|
||
Get the contents of the
|
||
|
||
Returns:
|
||
Union[List[Tuple], None]: _description_
|
||
"""
|
||
try:
|
||
with sql.connect(self.db_path) as conn:
|
||
cursor = conn.cursor()
|
||
cursor.execute("SELECT * FROM sqlite_master WHERE type='table'")
|
||
return cursor.fetchall()
|
||
except sql.OperationalError:
|
||
return None
|
||
def connect(self)->sql.Connection:
|
||
"""
|
||
Connect to the database
|
||
|
||
Returns:
|
||
sql.Connection: The active connection to the database
|
||
"""
|
||
return sql.connect(self.db_path)
|
||
def close_connection(self, conn: sql.Connection):
|
||
"""
|
||
closes the connection to the database
|
||
|
||
Args:
|
||
----
|
||
- conn (sql.Connection): the connection to be closed
|
||
"""
|
||
conn.close()
|
||
def create_tables(self):
|
||
"""
|
||
Create the tables in the database
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
cursor.execute(CREATE_TABLE_APPARAT)
|
||
cursor.execute(CREATE_TABLE_MESSAGES)
|
||
cursor.execute(CREATE_TABLE_MEDIA)
|
||
cursor.execute(CREATE_TABLE_APPKONTOS)
|
||
cursor.execute(CREATE_TABLE_FILES)
|
||
cursor.execute(CREATE_TABLE_PROF)
|
||
cursor.execute(CREATE_TABLE_USER)
|
||
cursor.execute(CREATE_TABLE_SUBJECTS)
|
||
conn.commit()
|
||
self.close_connection(conn)
|
||
def insertInto(self, query:str, params:Tuple) -> None:
|
||
"""
|
||
Insert sent data into the database
|
||
|
||
Args:
|
||
query (str): The query to be executed
|
||
params (Tuple): the parameters to be inserted into the database
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
logger.log_info(f"Inserting {params} into database with query {query}")
|
||
cursor.execute(query, params)
|
||
conn.commit()
|
||
self.close_connection(conn)
|
||
def query_db(self, query: str, args: Tuple = (), one: bool = False)->Union[Tuple, List[Tuple]]:
|
||
"""
|
||
Query the Database for the sent query.
|
||
|
||
Args:
|
||
query (str): The query to be executed
|
||
args (Tuple, optional): The arguments for the query. Defaults to ().
|
||
one (bool, optional): Return the first result only. Defaults to False.
|
||
|
||
Returns:
|
||
Union[Typle|List[Tuple]]: Returns the result of the query
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
logger.log_info(f"Querying database with query {query}, args: {args}")
|
||
cursor.execute(query, args)
|
||
rv = cursor.fetchall()
|
||
conn.commit()
|
||
self.close_connection(conn)
|
||
return (rv[0] if rv else None) if one else rv
|
||
|
||
# Books
|
||
def addBookToDatabase(self, bookdata:BookData,app_id:Union[str,int], prof_id:Union[str,int]):
|
||
"""
|
||
Add books to the database. Both app_id and prof_id are required to add the book to the database, as the app_id and prof_id are used to select the books later on.
|
||
|
||
Args:
|
||
bookdata (BookData): The metadata of the book to be added
|
||
app_id (str): The apparat id where the book should be added to
|
||
prof_id (str): The id of the professor where the book should be added to.
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
t_query = (
|
||
f"SELECT bookdata FROM media WHERE app_id={app_id} AND prof_id={prof_id}"
|
||
)
|
||
# print(t_query)
|
||
result = cursor.execute(t_query).fetchall()
|
||
result = [load_pickle(i[0]) for i in result]
|
||
if bookdata in result:
|
||
print("Bookdata already in database")
|
||
# check if the book was deleted in the apparat
|
||
query = (
|
||
"SELECT deleted FROM media WHERE app_id=? AND prof_id=? AND bookdata=?"
|
||
)
|
||
params = (app_id, prof_id, dump_pickle(bookdata))
|
||
result = cursor.execute(query, params).fetchone()
|
||
if result[0] == 1:
|
||
print("Book was deleted, updating bookdata")
|
||
query = "UPDATE media SET deleted=0 WHERE app_id=? AND prof_id=? AND bookdata=?"
|
||
params = (app_id, prof_id, dump_pickle(bookdata))
|
||
cursor.execute(query, params)
|
||
conn.commit()
|
||
return
|
||
|
||
query = (
|
||
"INSERT INTO media (bookdata, app_id, prof_id,deleted) VALUES (?, ?, ?,?)"
|
||
)
|
||
converted = dump_pickle(bookdata)
|
||
params = (converted, app_id, prof_id, 0)
|
||
cursor.execute(query, params)
|
||
conn.commit()
|
||
self.close_connection(conn)
|
||
def getBookIdBasedOnSignature(self, app_id:Union[str,int], prof_id:Union[str,int],signature:str)->int:
|
||
"""
|
||
Get a book id based on the signature of the book.
|
||
|
||
Args:
|
||
app_id (str): The apparat id the book should be associated with
|
||
prof_id (str): The professor id the book should be associated with
|
||
signature (str): The signature of the book
|
||
|
||
Returns:
|
||
int: The id of the book
|
||
"""
|
||
result = self.query_db("SELECT bookdata, id FROM media WHERE app_id=? AND prof_id=?", (app_id,prof_id))
|
||
books = [(load_pickle(i[0]),i[1]) for i in result]
|
||
book = [i for i in books if i[0].signature == signature][0][1]
|
||
return book
|
||
def getBookBasedOnSignature(self, app_id:Union[str,int], prof_id:Union[str,int],signature:str)->BookData:
|
||
"""
|
||
Get the book based on the signature of the book.
|
||
|
||
Args:
|
||
app_id (str): The apparat id the book should be associated with
|
||
prof_id (str): The professor id the book should be associated with
|
||
signature (str): The signature of the book
|
||
|
||
Returns:
|
||
BookData: The total metadata of the book wrapped in a BookData object
|
||
"""
|
||
result = self.query_db("SELECT bookdata FROM media WHERE app_id=? AND prof_id=?", (app_id,prof_id))
|
||
books = [load_pickle(i[0]) for i in result]
|
||
book = [i for i in books if i.signature == signature][0]
|
||
return book
|
||
def getLastBookId(self)->int:
|
||
"""
|
||
Get the last book id in the database
|
||
|
||
Returns:
|
||
int: ID of the last book in the database
|
||
"""
|
||
return self.query_db("SELECT id FROM media ORDER BY id DESC", one=True)[0]
|
||
def searchBook(self, data:dict[str, str])->list[tuple[BookData, int]]:
|
||
"""
|
||
Search a book in the database based on the sent data.
|
||
|
||
Args:
|
||
data (dict[str, str]): A dictionary containing the data to be searched for. The dictionary can contain the following:
|
||
- signature: The signature of the book
|
||
- title: The title of the book
|
||
|
||
Returns:
|
||
list[tuple[BookData, int]]: A list of tuples containing the wrapped Metadata and the id of the book
|
||
"""
|
||
rdata = self.query_db("SELECT * FROM media WHERE deleted=0")
|
||
ic(rdata, len(rdata))
|
||
mode = 0
|
||
if len(data)== 1:
|
||
if "signature" in data.keys():
|
||
mode = 1
|
||
elif "title" in data.keys():
|
||
mode = 2
|
||
elif len(data) == 2:
|
||
mode = 3
|
||
else:
|
||
return None
|
||
ret = []
|
||
for book in rdata:
|
||
bookdata = load_pickle(book[1])
|
||
app_id = book[2]
|
||
prof_id = book[3]
|
||
if mode == 1:
|
||
if data["signature"] in bookdata.signature:
|
||
ret.append((bookdata,app_id,prof_id))
|
||
elif mode == 2:
|
||
if data["title"] in bookdata.title:
|
||
ret.append((bookdata,app_id,prof_id))
|
||
elif mode == 3:
|
||
if data["signature"] in bookdata.signature and data["title"] in bookdata.title:
|
||
ret.append((bookdata,app_id,prof_id))
|
||
ic(ret)
|
||
return ret
|
||
def setAvailability(self, book_id:str, available:str):
|
||
"""
|
||
Set the availability of a book in the database
|
||
|
||
Args:
|
||
book_id (str): The id of the book
|
||
available (str): The availability of the book
|
||
"""
|
||
self.query_db("UPDATE media SET available=? WHERE id=?", (available,book_id))
|
||
def getBookId(self, bookdata:BookData, app_id:Union[str,int], prof_id:Union[str,int])->int:
|
||
"""
|
||
Get the id of a book based on the metadata of the book
|
||
|
||
Args:
|
||
bookdata (BookData): The wrapped metadata of the book
|
||
app_id (str): The apparat id the book should be associated with
|
||
prof_id (str): The professor id the book should be associated with
|
||
|
||
Returns:
|
||
int: ID of the book
|
||
"""
|
||
result = self.query_db("SELECT id FROM media WHERE bookdata=? AND app_id=? AND prof_id=?", (dump_pickle(bookdata),app_id,prof_id), one=True)
|
||
return result[0]
|
||
def getBook(self,book_id:int)->BookData:
|
||
"""
|
||
Get the book based on the id in the database
|
||
|
||
Args:
|
||
book_id (int): The id of the book
|
||
|
||
Returns:
|
||
BookData: The metadata of the book wrapped in a BookData object
|
||
"""
|
||
return load_pickle(self.query_db("SELECT bookdata FROM media WHERE id=?", (book_id,), one=True)[0])
|
||
def getBooks(self, app_id:Union[str,int], prof_id:Union[str,int], deleted=0)->list[dict[int, BookData, int]]:
|
||
"""
|
||
Get the Books based on the apparat id and the professor id
|
||
|
||
Args:
|
||
app_id (str): The ID of the apparat
|
||
prof_id (str): The ID of the professor
|
||
deleted (int, optional): The state of the book. Set to 1 to include deleted ones. Defaults to 0.
|
||
|
||
Returns:
|
||
list[dict[int, BookData, int]]: A list of dictionaries containing the id, the metadata of the book and the availability of the book
|
||
"""
|
||
qdata = self.query_db(f"SELECT id,bookdata,available FROM media WHERE (app_id={app_id} AND prof_id={prof_id}) AND (deleted={deleted if deleted == 0 else '1 OR deleted=0'})")
|
||
ret_result = []
|
||
for result_a in qdata:
|
||
data = {"id": int, "bookdata": BookData, "available": int}
|
||
data["id"] = result_a[0]
|
||
data["bookdata"] = load_pickle(result_a[1])
|
||
data["available"] = result_a[2]
|
||
ret_result.append(data)
|
||
return ret_result
|
||
def updateBookdata(self, book_id, bookdata:BookData):
|
||
"""
|
||
Update the bookdata in the database
|
||
|
||
Args:
|
||
book_id (str): The id of the book
|
||
bookdata (BookData): The new metadata of the book
|
||
"""
|
||
self.query_db("UPDATE media SET bookdata=? WHERE id=?", (dump_pickle(bookdata),book_id))
|
||
def deleteBook(self, book_id):
|
||
"""
|
||
Delete a book from the database
|
||
|
||
Args:
|
||
book_id (str): ID of the book
|
||
"""
|
||
self.query_db("UPDATE media SET deleted=1 WHERE id=?", (book_id,))
|
||
|
||
# File Interactions
|
||
def getBlob(self, filename, app_id:Union[str,int]):
|
||
"""
|
||
Get a blob from the database
|
||
|
||
Args:
|
||
filename (str): The name of the file
|
||
app_id (str): ID of the apparat
|
||
|
||
Returns:
|
||
bytes: The file stored in
|
||
"""
|
||
return self.query_db("SELECT fileblob FROM files WHERE filename=? AND app_id=?", (filename,app_id), one=True)[0]
|
||
def insertFile(self, file: list[dict], app_id:Union[str,int], prof_id:Union[str,int]):
|
||
"""Instert a list of files into the database
|
||
|
||
Args:
|
||
file (list[dict]): a list containing all the files to be inserted
|
||
Structured: [{"name": "filename", "path": "path", "type": "filetype"}]
|
||
app_id (int): the id of the apparat
|
||
prof_id (str): the id of the professor
|
||
"""
|
||
for f in file:
|
||
filename = f["name"]
|
||
path = f["path"]
|
||
filetyp = f["type"]
|
||
if path == "Database":
|
||
continue
|
||
blob = create_blob(path)
|
||
query = "INSERT OR IGNORE INTO files (filename, fileblob, app_id, filetyp,prof_id) VALUES (?, ?, ?, ?,?)"
|
||
self.query_db(query, (filename, blob, app_id, filetyp,prof_id))
|
||
def recreateFile(self, filename:str, app_id:Union[str,int],filetype:str)->str:
|
||
"""Recreate a file from the database
|
||
|
||
Args:
|
||
filename (str): the name of the file
|
||
app_id (Union[str,int]): the id of the apparat
|
||
filetype (str): the extension of the file to be created
|
||
|
||
Returns:
|
||
str: The filename of the recreated file
|
||
"""
|
||
blob = self.getBlob(filename, app_id)
|
||
tempdir = config.database.tempdir
|
||
tempdir = tempdir.replace("~", str(Path.home()))
|
||
tempdir_path = Path(tempdir)
|
||
if not os.path.exists(tempdir_path):
|
||
os.mkdir(tempdir_path)
|
||
file = tempfile.NamedTemporaryFile(
|
||
delete=False, dir=tempdir_path, mode="wb", suffix=f".{filetype}"
|
||
)
|
||
file.write(blob)
|
||
print("file created")
|
||
return file.name
|
||
def getFiles(self, app_id:Union[str,int], prof_id:int)->list[tuple]:
|
||
"""Get all the files associated with the apparat and the professor
|
||
|
||
Args:
|
||
app_id (Union[str,int]): The id of the apparat
|
||
prof_id (Union[str,int]): the id of the professor
|
||
|
||
Returns:
|
||
list[tuple]: a list of tuples containing the filename and the filetype for the corresponding apparat and professor
|
||
"""
|
||
return self.query_db("SELECT filename, filetyp FROM files WHERE app_id=? AND prof_id=?", (app_id,prof_id))
|
||
|
||
def getSemersters(self)->list[str]:
|
||
"""Return all the unique semesters in the database
|
||
|
||
Returns:
|
||
list: a list of strings containing the semesters
|
||
"""
|
||
data = self.query_db("SELECT DISTINCT erstellsemester FROM semesterapparat")
|
||
return [i[0] for i in data]
|
||
|
||
def getSubjects(self):
|
||
"""Get all the subjects in the database
|
||
|
||
Returns:
|
||
list[tuple]: a list of tuples containing the subjects
|
||
"""
|
||
return self.query_db("SELECT * FROM subjects")
|
||
|
||
# Messages
|
||
def addMessage(self, message:dict,user:str, app_id:Union[str,int]):
|
||
"""add a Message to the database
|
||
|
||
Args:
|
||
message (dict): the message to be added
|
||
user (str): the user who added the message
|
||
app_id (Union[str,int]): the id of the apparat
|
||
"""
|
||
def __getUserId(user):
|
||
return self.query_db("SELECT id FROM user WHERE username=?", (user,), one=True)[0]
|
||
user_id = __getUserId(user)
|
||
self.query_db("INSERT INTO messages (message, user_id, remind_at,appnr) VALUES (?,?,?,?)", (message["message"],user_id,message["remind_at"],app_id))
|
||
def getMessages(self, date:str)->list[dict[str, str, str, str]]:
|
||
"""Get all the messages for a specific date
|
||
|
||
Args:
|
||
date (str): a date.datetime object formatted as a string in the format "YYYY-MM-DD"
|
||
|
||
Returns:
|
||
list[dict[str, str, str, str]]: a list of dictionaries containing the message, the user who added the message, the apparat id and the id of the message
|
||
"""
|
||
def __get_user_name(user_id):
|
||
return self.query_db("SELECT username FROM user WHERE id=?", (user_id,), one=True)[0]
|
||
messages = self.query_db("SELECT * FROM messages WHERE remind_at=?", (date,))
|
||
ret = [
|
||
{
|
||
"message": i[2],
|
||
"user": __get_user_name(i[4]),
|
||
"appnr": i[5],
|
||
"id": i[0]
|
||
}
|
||
for i in messages
|
||
]
|
||
return ret
|
||
def deleteMessage(self, message_id):
|
||
"""Delete a message from the database
|
||
|
||
Args:
|
||
message_id (str): the id of the message
|
||
"""
|
||
self.query_db("DELETE FROM messages WHERE id=?", (message_id,))
|
||
|
||
# Prof data
|
||
def getProfNameById(self, prof_id:Union[str,int],add_title:bool=False)->str:
|
||
"""Get a professor name based on the id
|
||
|
||
Args:
|
||
prof_id (Union[str,int]): The id of the professor
|
||
add_title (bool, optional): wether to add the title or no. Defaults to False.
|
||
|
||
Returns:
|
||
str: The name of the professor
|
||
"""
|
||
prof = self.query_db("SELECT fullname FROM prof WHERE id=?", (prof_id,), one=True)
|
||
if add_title:
|
||
return f"{self.getTitleById(prof_id)}{prof[0]}"
|
||
else:
|
||
return prof[0]
|
||
def getTitleById(self, prof_id:Union[str,int])->str:
|
||
"""get the title of a professor based on the id
|
||
|
||
Args:
|
||
prof_id (Union[str,int]): the id of the professor
|
||
|
||
Returns:
|
||
str: the title of the professor, with an added whitespace at the end, if no title is present, an empty string is returned
|
||
"""
|
||
title = self.query_db("SELECT titel FROM prof WHERE id=?", (prof_id,), one=True)[0]
|
||
return f"{title} " if title is not None else ""
|
||
def getProfByName(self, prof_name:str)->tuple:
|
||
"""get all the data of a professor based on the name
|
||
|
||
Args:
|
||
prof_name (str): the name of the professor
|
||
|
||
Returns:
|
||
tuple: the data of the professor
|
||
"""
|
||
return self.query_db("SELECT * FROM prof WHERE fullname=?", (prof_name,), one=True)
|
||
def getProfId(self, prof_name:str)->Optional[int]:
|
||
"""Get the id of a professor based on the name
|
||
|
||
Args:
|
||
prof_name (str): the name of the professor
|
||
|
||
Returns:
|
||
Optional[int]: the id of the professor, if the professor is not found, None is returned
|
||
"""
|
||
|
||
data = self.getProfByName(prof_name.replace(",", ""))
|
||
if data is None:
|
||
return None
|
||
else:
|
||
return data[0]
|
||
def getSpecificProfData(self, prof_id:Union[str,int], fields:List[str])->tuple:
|
||
"""A customisable function to get specific data of a professor based on the id
|
||
|
||
Args:
|
||
prof_id (Union[str,int]): the id of the professor
|
||
fields (List[str]): a list of fields to be returned
|
||
|
||
Returns:
|
||
tuple: a tuple containing the requested data
|
||
"""
|
||
query = "SELECT "
|
||
for field in fields:
|
||
query += f"{field},"
|
||
query = query[:-1]
|
||
query += " FROM prof WHERE id=?"
|
||
return self.query_db(query, (prof_id,), one=True)[0]
|
||
def getProfData(self, profname:str):
|
||
"""Get mail, telephone number and title of a professor based on the name
|
||
|
||
Args:
|
||
profname (str): name of the professor
|
||
|
||
Returns:
|
||
tuple: the mail, telephone number and title of the professor
|
||
"""
|
||
data = self.query_db("SELECT mail, telnr, titel FROM prof WHERE fullname=?", (profname.replace(",",""),), one=True)
|
||
return data
|
||
def createProf(self, prof_details:dict):
|
||
"""Create a professor in the database
|
||
|
||
Args:
|
||
prof_details (dict): a dictionary containing the details of the professor
|
||
"""
|
||
prof_title = prof_details["prof_title"]
|
||
prof_fname = prof_details["profname"].split(",")[1]
|
||
prof_fname = prof_fname.strip()
|
||
prof_lname = prof_details["profname"].split(",")[0]
|
||
prof_lname = prof_lname.strip()
|
||
prof_fullname = prof_details["profname"].replace(",", "")
|
||
prof_mail = prof_details["prof_mail"]
|
||
prof_tel = prof_details["prof_tel"]
|
||
params = (prof_title, prof_fname, prof_lname, prof_mail, prof_tel, prof_fullname)
|
||
query = "INSERT OR IGNORE INTO prof (titel, fname, lname, mail, telnr, fullname) VALUES (?, ?, ?, ?, ?, ?)"
|
||
self.insertInto(query=query, params=params)
|
||
def getProfs(self)->list[tuple]:
|
||
"""Return all the professors in the database
|
||
|
||
Returns:
|
||
list[tuple]: a list containing all the professors in individual tuples
|
||
"""
|
||
return self.query_db("SELECT * FROM prof")
|
||
|
||
# Apparat
|
||
def getAllAparats(self,deleted=0)->list[tuple]:
|
||
"""Get all the apparats in the database
|
||
|
||
Args:
|
||
deleted (int, optional): Switch the result to use . Defaults to 0.
|
||
|
||
Returns:
|
||
list[tuple]: a list of tuples containing the apparats
|
||
"""
|
||
return self.query_db("SELECT * FROM semesterapparat WHERE deletion_status=?", (deleted,))
|
||
def getApparatData(self, appnr, appname)->ApparatData:
|
||
"""Get the Apparat data based on the apparat number and the name
|
||
|
||
Args:
|
||
appnr (str): the apparat number
|
||
appname (str): the name of the apparat
|
||
|
||
Raises:
|
||
NoResultError: an error is raised if no result is found
|
||
|
||
Returns:
|
||
ApparatData: the appended data of the apparat wrapped in an ApparatData object
|
||
"""
|
||
result = self.query_db("SELECT * FROM semesterapparat WHERE appnr=? AND name=?", (appnr,appname), one=True)
|
||
if result is None:
|
||
raise NoResultError("No result found")
|
||
apparat = ApparatData()
|
||
apparat.appname = result[1]
|
||
apparat.appnr = result[4]
|
||
apparat.dauerapp = True if result[7] == 1 else False
|
||
prof_data = self.getProfData(self.getProfNameById(result[2]))
|
||
apparat.profname = self.getProfNameById(result[2])
|
||
apparat.prof_mail = prof_data[0]
|
||
apparat.prof_tel = prof_data[1]
|
||
apparat.prof_title = prof_data[2]
|
||
apparat.app_fach = result[3]
|
||
apparat.erstellsemester = result[5]
|
||
apparat.semester = result[8]
|
||
apparat.deleted = result[9]
|
||
apparat.apparat_adis_id = result[11]
|
||
apparat.prof_adis_id = result[12]
|
||
return apparat
|
||
def getUnavailableApparatNumbers(self)->List[int]:
|
||
"""Get a list of all the apparat numbers in the database that are currently in use
|
||
|
||
Returns:
|
||
List[int]: the list of used apparat numbers
|
||
"""
|
||
numbers = self.query_db("SELECT appnr FROM semesterapparat WHERE deletion_status=0")
|
||
numbers = [i[0] for i in numbers]
|
||
logger.log_info(f"Currently used apparat numbers: {numbers}")
|
||
return numbers
|
||
def setNewSemesterDate(self, app_id:Union[str,int], newDate, dauerapp=False):
|
||
"""Set the new semester date for an apparat
|
||
|
||
Args:
|
||
app_id (Union[str,int]): the id of the apparat
|
||
newDate (str): the new date
|
||
dauerapp (bool, optional): if the apparat was changed to dauerapparat. Defaults to False.
|
||
"""
|
||
date = datetime.datetime.strptime(newDate, "%d.%m.%Y").strftime("%Y-%m-%d")
|
||
if dauerapp:
|
||
self.query_db("UPDATE semesterapparat SET verlängerung_bis=?, dauerapp=? WHERE appnr=?", (date,dauerapp,app_id))
|
||
else:
|
||
self.query_db("UPDATE semesterapparat SET endsemester=? WHERE appnr=?", (date,app_id))
|
||
def getApparatId(self, apparat_name)->Optional[int]:
|
||
"""get the id of an apparat based on the name
|
||
|
||
Args:
|
||
apparat_name (str): the name of the apparat e.g. "Semesterapparat 1"
|
||
|
||
Returns:
|
||
Optional[int]: the id of the apparat, if the apparat is not found, None is returned
|
||
"""
|
||
data = self.query_db("SELECT appnr FROM semesterapparat WHERE name=?", (apparat_name,), one=True)
|
||
if data is None:
|
||
return None
|
||
else:
|
||
return data[0]
|
||
def createApparat(self, apparat:ApparatData)->int:
|
||
"""create the apparat in the database
|
||
|
||
Args:
|
||
apparat (ApparatData): the wrapped metadata of the apparat
|
||
|
||
Raises:
|
||
AppPresentError: an error describing that the apparats chosen id is already present in the database
|
||
|
||
Returns:
|
||
Optional[int]: the id of the apparat
|
||
"""
|
||
|
||
prof_id = self.getProfId(apparat.profname)
|
||
app_id = self.getApparatId(apparat.appname)
|
||
if app_id:
|
||
raise AppPresentError(app_id)
|
||
|
||
self.createProf(apparat.get_prof_details())
|
||
prof_id = self.getProfId(apparat.profname)
|
||
ic(prof_id)
|
||
query = f"INSERT OR IGNORE INTO semesterapparat (appnr, name, erstellsemester, dauer, prof_id, fach,deletion_status,konto) VALUES ('{apparat.appnr}', '{apparat.appname}', '{apparat.semester}', '{apparat.dauerapp}', {prof_id}, '{apparat.app_fach}', '{0}', '{SEMAP_MEDIA_ACCOUNTS[apparat.appnr]}')"
|
||
logger.log_info(query)
|
||
self.query_db(query)
|
||
return self.getApparatId(apparat.appname)
|
||
def getApparatsByProf(self, prof_id:Union[str,int])->list[tuple]:
|
||
"""Get all apparats based on the professor id
|
||
|
||
Args:
|
||
prof_id (Union[str,int]): the id of the professor
|
||
|
||
Returns:
|
||
list[tuple]: a list of tuples containing the apparats
|
||
"""
|
||
return self.query_db("SELECT * FROM semesterapparat WHERE prof_id=?", (prof_id,))
|
||
def getApparatsBySemester(self, semester:str)->dict[list]:
|
||
"""get all apparats based on the semester
|
||
|
||
Args:
|
||
semester (str): the selected semester
|
||
|
||
Returns:
|
||
dict[list]: a list off all created and deleted apparats for the selected semester
|
||
"""
|
||
data = self.query_db("SELECT name, prof_id FROM semesterapparat WHERE erstellsemester=?", (semester,))
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
c_tmp = []
|
||
for i in data:
|
||
c_tmp.append((i[0], self.getProfNameById(i[1])))
|
||
query = (
|
||
f"SELECT name,prof_id FROM semesterapparat WHERE deleted_date='{semester}'"
|
||
)
|
||
result = cursor.execute(query).fetchall()
|
||
d_tmp = []
|
||
for i in result:
|
||
d_tmp.append((i[0], self.getProfNameById(i[1])))
|
||
# group the apparats by prof
|
||
c_ret = {}
|
||
for i in c_tmp:
|
||
if i[1] not in c_ret.keys():
|
||
c_ret[i[1]] = [i[0]]
|
||
else:
|
||
c_ret[i[1]].append(i[0])
|
||
d_ret = {}
|
||
for i in d_tmp:
|
||
if i[1] not in d_ret.keys():
|
||
d_ret[i[1]] = [i[0]]
|
||
else:
|
||
d_ret[i[1]].append(i[0])
|
||
self.close_connection(conn)
|
||
return {"created": c_ret, "deleted": d_ret}
|
||
def getApparatCountBySemester(self)->tuple[list[str],list[int]]:
|
||
"""get a list of all apparats created and deleted by semester
|
||
|
||
Returns:
|
||
tuple[list[str],list[int]]: a tuple containing two lists, the first list contains the semesters, the second list contains the amount of apparats created and deleted for the corresponding semester
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
semesters = self.getSemersters()
|
||
created = []
|
||
deleted = []
|
||
for semester in semesters:
|
||
query = f"SELECT COUNT(*) FROM semesterapparat WHERE erstellsemester='{semester}'"
|
||
result = cursor.execute(query).fetchone()
|
||
created.append(result[0])
|
||
query = f"SELECT COUNT(*) FROM semesterapparat WHERE deletion_status=1 AND deleted_date='{semester}'"
|
||
result = cursor.execute(query).fetchone()
|
||
deleted.append(result[0])
|
||
# store data in a tuple
|
||
ret = []
|
||
e_tuple = ()
|
||
for sem in semesters:
|
||
e_tuple = (
|
||
sem,
|
||
created[semesters.index(sem)],
|
||
deleted[semesters.index(sem)],
|
||
)
|
||
ret.append(e_tuple)
|
||
self.close_connection(conn)
|
||
return ret
|
||
def deleteApparat(self, app_id:Union[str,int], semester:str):
|
||
"""Delete an apparat from the database
|
||
|
||
Args:
|
||
app_id (Union[str, int]): the id of the apparat
|
||
semester (str): the semester the apparat should be deleted from
|
||
"""
|
||
self.query_db("UPDATE semesterapparat SET deletion_status=1, deleted_date=? WHERE appnr=?", (semester,app_id))
|
||
def isEternal(self, id):
|
||
"""check if the apparat is eternal (dauerapparat)
|
||
|
||
Args:
|
||
id (int): the id of the apparat to be checked
|
||
|
||
Returns:
|
||
int: the state of the apparat
|
||
"""
|
||
return self.query_db("SELECT dauer FROM semesterapparat WHERE appnr=?", (id,), one=True)
|
||
def getApparatName(self, app_id:Union[str,int], prof_id:Union[str,int]):
|
||
"""get the name of the apparat based on the id
|
||
|
||
Args:
|
||
app_id (Union[str,int]): the id of the apparat
|
||
prof_id (Union[str,int]): the id of the professor
|
||
|
||
Returns:
|
||
str: the name of the apparat
|
||
"""
|
||
return self.query_db("SELECT name FROM semesterapparat WHERE appnr=? AND prof_id=?", (app_id,prof_id), one=True)[0]
|
||
def updateApparat(self, apparat_data:ApparatData):
|
||
"""Update an apparat in the database
|
||
|
||
Args:
|
||
apparat_data (ApparatData): the new metadata of the apparat
|
||
"""
|
||
query = f"UPDATE semesterapparat SET name = ?, fach = ?, dauer = ?, prof_id = ? WHERE appnr = ?"
|
||
params = (
|
||
apparat_data.appname,
|
||
apparat_data.app_fach,
|
||
apparat_data.dauerapp,
|
||
self.getProfId(apparat_data.profname),
|
||
apparat_data.appnr,
|
||
)
|
||
self.query_db(query, params)
|
||
def checkApparatExists(self, apparat_name:str):
|
||
"""check if the apparat is already present in the database based on the name
|
||
|
||
Args:
|
||
apparat_name (str): the name of the apparat
|
||
|
||
Returns:
|
||
bool: True if the apparat is present, False if not
|
||
"""
|
||
return True if self.query_db("SELECT appnr FROM semesterapparat WHERE name=?", (apparat_name,), one=True) else False
|
||
def checkApparatExistsById(self, app_id:Union[str,int])->bool:
|
||
"""a check to see if the apparat is already present in the database, based on the id
|
||
|
||
Args:
|
||
app_id (Union[str, int]): the id of the apparat
|
||
|
||
Returns:
|
||
bool: True if the apparat is present, False if not
|
||
"""
|
||
return True if self.query_db("SELECT appnr FROM semesterapparat WHERE appnr=?", (app_id,), one=True) else False
|
||
# Statistics
|
||
def statistic_request(self, **kwargs: Any):
|
||
"""Take n amount of kwargs and return the result of the query
|
||
"""
|
||
def __query(query):
|
||
"""execute the query and return the result
|
||
|
||
Args:
|
||
query (str): the constructed query
|
||
|
||
Returns:
|
||
list: the result of the query
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
result = cursor.execute(query).fetchall()
|
||
for result_a in result:
|
||
orig_value = result_a
|
||
prof_name = self.getProfNameById(result_a[2])
|
||
# replace the prof_id with the prof_name
|
||
result_a = list(result_a)
|
||
result_a[2] = prof_name
|
||
result_a = tuple(result_a)
|
||
result[result.index(orig_value)] = result_a
|
||
self.close_connection(conn)
|
||
return result
|
||
if "deletable" in kwargs.keys():
|
||
query = f"SELECT * FROM semesterapparat WHERE deletion_status=0 AND dauer=0 AND (erstellsemester!='{kwargs['deletesemester']}' OR verlängerung_bis!='{kwargs['deletesemester']}')"
|
||
return __query(query)
|
||
if "dauer" in kwargs.keys():
|
||
kwargs["dauer"] = kwargs["dauer"].replace("Ja", "1").replace("Nein", "0")
|
||
query = "SELECT * FROM semesterapparat WHERE "
|
||
for key, value in kwargs.items() if kwargs.items() is not None else {}:
|
||
print(key, value)
|
||
query += f"{key}='{value}' AND "
|
||
print(query)
|
||
# remove deletesemester part from normal query, as this will be added to the database upon deleting the apparat
|
||
if "deletesemester" in kwargs.keys():
|
||
query = query.replace(
|
||
f"deletesemester='{kwargs['deletesemester']}' AND ", ""
|
||
)
|
||
if "endsemester" in kwargs.keys():
|
||
if "erstellsemester" in kwargs.keys():
|
||
query = query.replace(f"endsemester='{kwargs['endsemester']}' AND ", "")
|
||
query = query.replace(
|
||
f"erstellsemester='{kwargs['erstellsemester']} AND ", "xyz"
|
||
)
|
||
else:
|
||
query = query.replace(
|
||
f"endsemester='{kwargs['endsemester']}' AND ", "xyz"
|
||
)
|
||
print("replaced")
|
||
query = query.replace(
|
||
"xyz",
|
||
f"(erstellsemester='{kwargs['endsemester']}' OR verlängerung_bis='{kwargs['endsemester']}') AND ",
|
||
)
|
||
# remove all x="" parts from the query where x is a key in kwargs
|
||
query = query[:-5]
|
||
print(query)
|
||
return __query(query)
|
||
|
||
# Admin data
|
||
def getUser(self):
|
||
"""Get a single user from the database"""
|
||
return self.query_db("SELECT * FROM user", one=True)
|
||
def getUsers(self)->list[tuple]:
|
||
"""Return a list of tuples of all the users in the database"""
|
||
return self.query_db("SELECT * FROM user")
|
||
|
||
def login(self, user, hashed_password):
|
||
"""try to login the user.
|
||
The salt for the user will be requested from the database and then added to the hashed password. The password will then be compared to the password in the database
|
||
|
||
Args:
|
||
user (str): username that tries to login
|
||
hashed_password (str): the password the user tries to login with
|
||
|
||
Returns:
|
||
bool: True if the login was successful, False if not
|
||
"""
|
||
salt = self.query_db("SELECT salt FROM user WHERE username=?", (user,), one=True)[0]
|
||
if salt is None:
|
||
return False
|
||
hashed_password = salt + hashed_password
|
||
password = self.query_db("SELECT password FROM user WHERE username=?", (user,), one=True)[0]
|
||
if password == hashed_password:
|
||
return True
|
||
else:
|
||
return False
|
||
def changePassword(self, user, new_password):
|
||
"""change the password of a user.
|
||
The password will be added with the salt and then committed to the database
|
||
|
||
Args:
|
||
user (str): username
|
||
new_password (str): the hashed password
|
||
"""
|
||
salt = self.query_db("SELECT salt FROM user WHERE username=?", (user,), one=True)[0]
|
||
new_password = salt + new_password
|
||
self.query_db("UPDATE user SET password=? WHERE username=?", (new_password,user))
|
||
def getRole(self, user):
|
||
"""get the role of the user
|
||
|
||
Args:
|
||
user (str): username
|
||
|
||
Returns:
|
||
str: the name of the role
|
||
"""
|
||
return self.query_db("SELECT role FROM user WHERE username=?", (user,), one=True)[0]
|
||
def getRoles(self)->list[tuple]:
|
||
"""get all the roles in the database
|
||
|
||
Returns:
|
||
list[str]: a list of all the roles
|
||
"""
|
||
return self.query_db("SELECT role FROM user")
|
||
def checkUsername(self, user)->bool:
|
||
"""a check to see if the username is already present in the database
|
||
|
||
Args:
|
||
user (str): the username
|
||
|
||
Returns:
|
||
bool: True if the username is present, False if not
|
||
"""
|
||
data = self.query_db("SELECT username FROM user WHERE username=?", (user,), one=True)
|
||
return True if data is not None else False
|
||
def createUser(self, user, password, role, salt):
|
||
"""create an user from the AdminCommands class.
|
||
|
||
Args:
|
||
user (str): the username of the user
|
||
password (str): a hashed password
|
||
role (str): the role of the user
|
||
salt (str): a salt for the password
|
||
"""
|
||
self.query_db("INSERT OR IGNORE INTO user (username, password, role, salt) VALUES (?,?,?,?)", (user,password,role,salt))
|
||
def deleteUser(self, user):
|
||
"""delete an unser
|
||
|
||
Args:
|
||
user (str): username of the user
|
||
"""
|
||
self.query_db("DELETE FROM user WHERE username=?", (user,))
|
||
def updateUser(self, username, data:dict[str, str]):
|
||
"""changge the data of a user
|
||
|
||
Args:
|
||
username (str): the username of the user
|
||
data (dict[str, str]): the data to be changed
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
query = "UPDATE user SET "
|
||
for key,value in data.items():
|
||
if key == "username":
|
||
continue
|
||
query += f"{key}='{value}',"
|
||
query = query[:-1]
|
||
query += " WHERE username=?"
|
||
params = (username,)
|
||
cursor.execute(query, params)
|
||
conn.commit()
|
||
self.close_connection(conn)
|
||
def getFacultyMember(self, name:str)->tuple:
|
||
"""get a faculty member based on the name
|
||
|
||
Args:
|
||
name (str): the name to be searched for
|
||
|
||
Returns:
|
||
tuple: a tuple containing the data of the faculty member
|
||
"""
|
||
return self.query_db("SELECT titel, fname,lname,mail,telnr,fullname FROM prof WHERE fullname=?", (name,), one=True)
|
||
def updateFacultyMember(self, data:dict, oldlname:str, oldfname:str):
|
||
"""update the data of a faculty member
|
||
|
||
Args:
|
||
data (dict): a dictionary containing the data to be updated
|
||
oldlname (str): the old last name of the faculty member
|
||
oldfname (str): the old first name of the faculty member
|
||
"""
|
||
placeholders = ", ".join([f"{i}=:{i} " for i in data.keys()])
|
||
query = f"UPDATE prof SET {placeholders} WHERE lname = :oldlname AND fname = :oldfname"
|
||
data["oldlname"] = oldlname
|
||
data["oldfname"] = oldfname
|
||
self.query_db(query, data)
|
||
def getFacultyMembers(self):
|
||
"""get a list of all faculty members
|
||
|
||
Returns:
|
||
list[tuple]: a list of tuples containing the faculty members
|
||
"""
|
||
return self.query_db("SELECT titel, fname,lname,mail,telnr,fullname FROM prof")</code></pre>
|
||
</details>
|
||
<h3>Methods</h3>
|
||
<dl>
|
||
<dt id="database.Database.addBookToDatabase"><code class="name flex">
|
||
<span>def <span class="ident">addBookToDatabase</span></span>(<span>self, bookdata: src.logic.dataclass.BookData, app_id: Union[str, int], prof_id: Union[str, int])</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Add books to the database. Both app_id and prof_id are required to add the book to the database, as the app_id and prof_id are used to select the books later on.</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>bookdata</code></strong> : <code>BookData</code></dt>
|
||
<dd>The metadata of the book to be added</dd>
|
||
<dt><strong><code>app_id</code></strong> : <code>str</code></dt>
|
||
<dd>The apparat id where the book should be added to</dd>
|
||
<dt><strong><code>prof_id</code></strong> : <code>str</code></dt>
|
||
<dd>The id of the professor where the book should be added to.</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def addBookToDatabase(self, bookdata:BookData,app_id:Union[str,int], prof_id:Union[str,int]):
|
||
"""
|
||
Add books to the database. Both app_id and prof_id are required to add the book to the database, as the app_id and prof_id are used to select the books later on.
|
||
|
||
Args:
|
||
bookdata (BookData): The metadata of the book to be added
|
||
app_id (str): The apparat id where the book should be added to
|
||
prof_id (str): The id of the professor where the book should be added to.
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
t_query = (
|
||
f"SELECT bookdata FROM media WHERE app_id={app_id} AND prof_id={prof_id}"
|
||
)
|
||
# print(t_query)
|
||
result = cursor.execute(t_query).fetchall()
|
||
result = [load_pickle(i[0]) for i in result]
|
||
if bookdata in result:
|
||
print("Bookdata already in database")
|
||
# check if the book was deleted in the apparat
|
||
query = (
|
||
"SELECT deleted FROM media WHERE app_id=? AND prof_id=? AND bookdata=?"
|
||
)
|
||
params = (app_id, prof_id, dump_pickle(bookdata))
|
||
result = cursor.execute(query, params).fetchone()
|
||
if result[0] == 1:
|
||
print("Book was deleted, updating bookdata")
|
||
query = "UPDATE media SET deleted=0 WHERE app_id=? AND prof_id=? AND bookdata=?"
|
||
params = (app_id, prof_id, dump_pickle(bookdata))
|
||
cursor.execute(query, params)
|
||
conn.commit()
|
||
return
|
||
|
||
query = (
|
||
"INSERT INTO media (bookdata, app_id, prof_id,deleted) VALUES (?, ?, ?,?)"
|
||
)
|
||
converted = dump_pickle(bookdata)
|
||
params = (converted, app_id, prof_id, 0)
|
||
cursor.execute(query, params)
|
||
conn.commit()
|
||
self.close_connection(conn)</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.addMessage"><code class="name flex">
|
||
<span>def <span class="ident">addMessage</span></span>(<span>self, message: dict, user: str, app_id: Union[str, int])</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>add a Message to the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>message</code></strong> : <code>dict</code></dt>
|
||
<dd>the message to be added</dd>
|
||
<dt><strong><code>user</code></strong> : <code>str</code></dt>
|
||
<dd>the user who added the message</dd>
|
||
<dt><strong><code>app_id</code></strong> : <code>Union[str,int]</code></dt>
|
||
<dd>the id of the apparat</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def addMessage(self, message:dict,user:str, app_id:Union[str,int]):
|
||
"""add a Message to the database
|
||
|
||
Args:
|
||
message (dict): the message to be added
|
||
user (str): the user who added the message
|
||
app_id (Union[str,int]): the id of the apparat
|
||
"""
|
||
def __getUserId(user):
|
||
return self.query_db("SELECT id FROM user WHERE username=?", (user,), one=True)[0]
|
||
user_id = __getUserId(user)
|
||
self.query_db("INSERT INTO messages (message, user_id, remind_at,appnr) VALUES (?,?,?,?)", (message["message"],user_id,message["remind_at"],app_id))</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.changePassword"><code class="name flex">
|
||
<span>def <span class="ident">changePassword</span></span>(<span>self, user, new_password)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>change the password of a user.
|
||
The password will be added with the salt and then committed to the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>user</code></strong> : <code>str</code></dt>
|
||
<dd>username</dd>
|
||
<dt><strong><code>new_password</code></strong> : <code>str</code></dt>
|
||
<dd>the hashed password</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def changePassword(self, user, new_password):
|
||
"""change the password of a user.
|
||
The password will be added with the salt and then committed to the database
|
||
|
||
Args:
|
||
user (str): username
|
||
new_password (str): the hashed password
|
||
"""
|
||
salt = self.query_db("SELECT salt FROM user WHERE username=?", (user,), one=True)[0]
|
||
new_password = salt + new_password
|
||
self.query_db("UPDATE user SET password=? WHERE username=?", (new_password,user))</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.checkApparatExists"><code class="name flex">
|
||
<span>def <span class="ident">checkApparatExists</span></span>(<span>self, apparat_name: str)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>check if the apparat is already present in the database based on the name</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>apparat_name</code></strong> : <code>str</code></dt>
|
||
<dd>the name of the apparat</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>bool</code></dt>
|
||
<dd>True if the apparat is present, False if not</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def checkApparatExists(self, apparat_name:str):
|
||
"""check if the apparat is already present in the database based on the name
|
||
|
||
Args:
|
||
apparat_name (str): the name of the apparat
|
||
|
||
Returns:
|
||
bool: True if the apparat is present, False if not
|
||
"""
|
||
return True if self.query_db("SELECT appnr FROM semesterapparat WHERE name=?", (apparat_name,), one=True) else False</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.checkApparatExistsById"><code class="name flex">
|
||
<span>def <span class="ident">checkApparatExistsById</span></span>(<span>self, app_id: Union[str, int]) ‑> bool</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>a check to see if the apparat is already present in the database, based on the id</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>app_id</code></strong> : <code>Union[str, int]</code></dt>
|
||
<dd>the id of the apparat</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>bool</code></dt>
|
||
<dd>True if the apparat is present, False if not</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def checkApparatExistsById(self, app_id:Union[str,int])->bool:
|
||
"""a check to see if the apparat is already present in the database, based on the id
|
||
|
||
Args:
|
||
app_id (Union[str, int]): the id of the apparat
|
||
|
||
Returns:
|
||
bool: True if the apparat is present, False if not
|
||
"""
|
||
return True if self.query_db("SELECT appnr FROM semesterapparat WHERE appnr=?", (app_id,), one=True) else False</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.checkUsername"><code class="name flex">
|
||
<span>def <span class="ident">checkUsername</span></span>(<span>self, user) ‑> bool</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>a check to see if the username is already present in the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>user</code></strong> : <code>str</code></dt>
|
||
<dd>the username</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>bool</code></dt>
|
||
<dd>True if the username is present, False if not</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def checkUsername(self, user)->bool:
|
||
"""a check to see if the username is already present in the database
|
||
|
||
Args:
|
||
user (str): the username
|
||
|
||
Returns:
|
||
bool: True if the username is present, False if not
|
||
"""
|
||
data = self.query_db("SELECT username FROM user WHERE username=?", (user,), one=True)
|
||
return True if data is not None else False</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.close_connection"><code class="name flex">
|
||
<span>def <span class="ident">close_connection</span></span>(<span>self, conn: sqlite3.Connection)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>closes the connection to the database</p>
|
||
<h2 id="args">Args:</h2>
|
||
<pre><code>- conn (sql.Connection): the connection to be closed
|
||
</code></pre></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def close_connection(self, conn: sql.Connection):
|
||
"""
|
||
closes the connection to the database
|
||
|
||
Args:
|
||
----
|
||
- conn (sql.Connection): the connection to be closed
|
||
"""
|
||
conn.close()</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.connect"><code class="name flex">
|
||
<span>def <span class="ident">connect</span></span>(<span>self) ‑> sqlite3.Connection</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Connect to the database</p>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>sql.Connection</code></dt>
|
||
<dd>The active connection to the database</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def connect(self)->sql.Connection:
|
||
"""
|
||
Connect to the database
|
||
|
||
Returns:
|
||
sql.Connection: The active connection to the database
|
||
"""
|
||
return sql.connect(self.db_path)</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.createApparat"><code class="name flex">
|
||
<span>def <span class="ident">createApparat</span></span>(<span>self, apparat: src.logic.dataclass.ApparatData) ‑> int</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>create the apparat in the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>apparat</code></strong> : <code>ApparatData</code></dt>
|
||
<dd>the wrapped metadata of the apparat</dd>
|
||
</dl>
|
||
<h2 id="raises">Raises</h2>
|
||
<dl>
|
||
<dt><code>AppPresentError</code></dt>
|
||
<dd>an error describing that the apparats chosen id is already present in the database</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>Optional[int]</code></dt>
|
||
<dd>the id of the apparat</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def createApparat(self, apparat:ApparatData)->int:
|
||
"""create the apparat in the database
|
||
|
||
Args:
|
||
apparat (ApparatData): the wrapped metadata of the apparat
|
||
|
||
Raises:
|
||
AppPresentError: an error describing that the apparats chosen id is already present in the database
|
||
|
||
Returns:
|
||
Optional[int]: the id of the apparat
|
||
"""
|
||
|
||
prof_id = self.getProfId(apparat.profname)
|
||
app_id = self.getApparatId(apparat.appname)
|
||
if app_id:
|
||
raise AppPresentError(app_id)
|
||
|
||
self.createProf(apparat.get_prof_details())
|
||
prof_id = self.getProfId(apparat.profname)
|
||
ic(prof_id)
|
||
query = f"INSERT OR IGNORE INTO semesterapparat (appnr, name, erstellsemester, dauer, prof_id, fach,deletion_status,konto) VALUES ('{apparat.appnr}', '{apparat.appname}', '{apparat.semester}', '{apparat.dauerapp}', {prof_id}, '{apparat.app_fach}', '{0}', '{SEMAP_MEDIA_ACCOUNTS[apparat.appnr]}')"
|
||
logger.log_info(query)
|
||
self.query_db(query)
|
||
return self.getApparatId(apparat.appname)</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.createProf"><code class="name flex">
|
||
<span>def <span class="ident">createProf</span></span>(<span>self, prof_details: dict)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Create a professor in the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>prof_details</code></strong> : <code>dict</code></dt>
|
||
<dd>a dictionary containing the details of the professor</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def createProf(self, prof_details:dict):
|
||
"""Create a professor in the database
|
||
|
||
Args:
|
||
prof_details (dict): a dictionary containing the details of the professor
|
||
"""
|
||
prof_title = prof_details["prof_title"]
|
||
prof_fname = prof_details["profname"].split(",")[1]
|
||
prof_fname = prof_fname.strip()
|
||
prof_lname = prof_details["profname"].split(",")[0]
|
||
prof_lname = prof_lname.strip()
|
||
prof_fullname = prof_details["profname"].replace(",", "")
|
||
prof_mail = prof_details["prof_mail"]
|
||
prof_tel = prof_details["prof_tel"]
|
||
params = (prof_title, prof_fname, prof_lname, prof_mail, prof_tel, prof_fullname)
|
||
query = "INSERT OR IGNORE INTO prof (titel, fname, lname, mail, telnr, fullname) VALUES (?, ?, ?, ?, ?, ?)"
|
||
self.insertInto(query=query, params=params)</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.createUser"><code class="name flex">
|
||
<span>def <span class="ident">createUser</span></span>(<span>self, user, password, role, salt)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>create an user from the AdminCommands class.</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>user</code></strong> : <code>str</code></dt>
|
||
<dd>the username of the user</dd>
|
||
<dt><strong><code>password</code></strong> : <code>str</code></dt>
|
||
<dd>a hashed password</dd>
|
||
<dt><strong><code>role</code></strong> : <code>str</code></dt>
|
||
<dd>the role of the user</dd>
|
||
<dt><strong><code>salt</code></strong> : <code>str</code></dt>
|
||
<dd>a salt for the password</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def createUser(self, user, password, role, salt):
|
||
"""create an user from the AdminCommands class.
|
||
|
||
Args:
|
||
user (str): the username of the user
|
||
password (str): a hashed password
|
||
role (str): the role of the user
|
||
salt (str): a salt for the password
|
||
"""
|
||
self.query_db("INSERT OR IGNORE INTO user (username, password, role, salt) VALUES (?,?,?,?)", (user,password,role,salt))</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.create_tables"><code class="name flex">
|
||
<span>def <span class="ident">create_tables</span></span>(<span>self)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Create the tables in the database</p></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def create_tables(self):
|
||
"""
|
||
Create the tables in the database
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
cursor.execute(CREATE_TABLE_APPARAT)
|
||
cursor.execute(CREATE_TABLE_MESSAGES)
|
||
cursor.execute(CREATE_TABLE_MEDIA)
|
||
cursor.execute(CREATE_TABLE_APPKONTOS)
|
||
cursor.execute(CREATE_TABLE_FILES)
|
||
cursor.execute(CREATE_TABLE_PROF)
|
||
cursor.execute(CREATE_TABLE_USER)
|
||
cursor.execute(CREATE_TABLE_SUBJECTS)
|
||
conn.commit()
|
||
self.close_connection(conn)</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.deleteApparat"><code class="name flex">
|
||
<span>def <span class="ident">deleteApparat</span></span>(<span>self, app_id: Union[str, int], semester: str)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Delete an apparat from the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>app_id</code></strong> : <code>Union[str, int]</code></dt>
|
||
<dd>the id of the apparat</dd>
|
||
<dt><strong><code>semester</code></strong> : <code>str</code></dt>
|
||
<dd>the semester the apparat should be deleted from</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def deleteApparat(self, app_id:Union[str,int], semester:str):
|
||
"""Delete an apparat from the database
|
||
|
||
Args:
|
||
app_id (Union[str, int]): the id of the apparat
|
||
semester (str): the semester the apparat should be deleted from
|
||
"""
|
||
self.query_db("UPDATE semesterapparat SET deletion_status=1, deleted_date=? WHERE appnr=?", (semester,app_id)) </code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.deleteBook"><code class="name flex">
|
||
<span>def <span class="ident">deleteBook</span></span>(<span>self, book_id)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Delete a book from the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>book_id</code></strong> : <code>str</code></dt>
|
||
<dd>ID of the book</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def deleteBook(self, book_id):
|
||
"""
|
||
Delete a book from the database
|
||
|
||
Args:
|
||
book_id (str): ID of the book
|
||
"""
|
||
self.query_db("UPDATE media SET deleted=1 WHERE id=?", (book_id,))</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.deleteMessage"><code class="name flex">
|
||
<span>def <span class="ident">deleteMessage</span></span>(<span>self, message_id)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Delete a message from the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>message_id</code></strong> : <code>str</code></dt>
|
||
<dd>the id of the message</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def deleteMessage(self, message_id):
|
||
"""Delete a message from the database
|
||
|
||
Args:
|
||
message_id (str): the id of the message
|
||
"""
|
||
self.query_db("DELETE FROM messages WHERE id=?", (message_id,))</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.deleteUser"><code class="name flex">
|
||
<span>def <span class="ident">deleteUser</span></span>(<span>self, user)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>delete an unser</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>user</code></strong> : <code>str</code></dt>
|
||
<dd>username of the user</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def deleteUser(self, user):
|
||
"""delete an unser
|
||
|
||
Args:
|
||
user (str): username of the user
|
||
"""
|
||
self.query_db("DELETE FROM user WHERE username=?", (user,))</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getAllAparats"><code class="name flex">
|
||
<span>def <span class="ident">getAllAparats</span></span>(<span>self, deleted=0) ‑> list[tuple]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get all the apparats in the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>deleted</code></strong> : <code>int</code>, optional</dt>
|
||
<dd>Switch the result to use . Defaults to 0.</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>list[tuple]</code></dt>
|
||
<dd>a list of tuples containing the apparats</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getAllAparats(self,deleted=0)->list[tuple]:
|
||
"""Get all the apparats in the database
|
||
|
||
Args:
|
||
deleted (int, optional): Switch the result to use . Defaults to 0.
|
||
|
||
Returns:
|
||
list[tuple]: a list of tuples containing the apparats
|
||
"""
|
||
return self.query_db("SELECT * FROM semesterapparat WHERE deletion_status=?", (deleted,))</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getApparatCountBySemester"><code class="name flex">
|
||
<span>def <span class="ident">getApparatCountBySemester</span></span>(<span>self) ‑> tuple[list[str], list[int]]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>get a list of all apparats created and deleted by semester</p>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>tuple[list[str],list[int]]</code></dt>
|
||
<dd>a tuple containing two lists, the first list contains the semesters, the second list contains the amount of apparats created and deleted for the corresponding semester</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getApparatCountBySemester(self)->tuple[list[str],list[int]]:
|
||
"""get a list of all apparats created and deleted by semester
|
||
|
||
Returns:
|
||
tuple[list[str],list[int]]: a tuple containing two lists, the first list contains the semesters, the second list contains the amount of apparats created and deleted for the corresponding semester
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
semesters = self.getSemersters()
|
||
created = []
|
||
deleted = []
|
||
for semester in semesters:
|
||
query = f"SELECT COUNT(*) FROM semesterapparat WHERE erstellsemester='{semester}'"
|
||
result = cursor.execute(query).fetchone()
|
||
created.append(result[0])
|
||
query = f"SELECT COUNT(*) FROM semesterapparat WHERE deletion_status=1 AND deleted_date='{semester}'"
|
||
result = cursor.execute(query).fetchone()
|
||
deleted.append(result[0])
|
||
# store data in a tuple
|
||
ret = []
|
||
e_tuple = ()
|
||
for sem in semesters:
|
||
e_tuple = (
|
||
sem,
|
||
created[semesters.index(sem)],
|
||
deleted[semesters.index(sem)],
|
||
)
|
||
ret.append(e_tuple)
|
||
self.close_connection(conn)
|
||
return ret </code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getApparatData"><code class="name flex">
|
||
<span>def <span class="ident">getApparatData</span></span>(<span>self, appnr, appname) ‑> src.logic.dataclass.ApparatData</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get the Apparat data based on the apparat number and the name</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>appnr</code></strong> : <code>str</code></dt>
|
||
<dd>the apparat number</dd>
|
||
<dt><strong><code>appname</code></strong> : <code>str</code></dt>
|
||
<dd>the name of the apparat</dd>
|
||
</dl>
|
||
<h2 id="raises">Raises</h2>
|
||
<dl>
|
||
<dt><code>NoResultError</code></dt>
|
||
<dd>an error is raised if no result is found</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>ApparatData</code></dt>
|
||
<dd>the appended data of the apparat wrapped in an ApparatData object</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getApparatData(self, appnr, appname)->ApparatData:
|
||
"""Get the Apparat data based on the apparat number and the name
|
||
|
||
Args:
|
||
appnr (str): the apparat number
|
||
appname (str): the name of the apparat
|
||
|
||
Raises:
|
||
NoResultError: an error is raised if no result is found
|
||
|
||
Returns:
|
||
ApparatData: the appended data of the apparat wrapped in an ApparatData object
|
||
"""
|
||
result = self.query_db("SELECT * FROM semesterapparat WHERE appnr=? AND name=?", (appnr,appname), one=True)
|
||
if result is None:
|
||
raise NoResultError("No result found")
|
||
apparat = ApparatData()
|
||
apparat.appname = result[1]
|
||
apparat.appnr = result[4]
|
||
apparat.dauerapp = True if result[7] == 1 else False
|
||
prof_data = self.getProfData(self.getProfNameById(result[2]))
|
||
apparat.profname = self.getProfNameById(result[2])
|
||
apparat.prof_mail = prof_data[0]
|
||
apparat.prof_tel = prof_data[1]
|
||
apparat.prof_title = prof_data[2]
|
||
apparat.app_fach = result[3]
|
||
apparat.erstellsemester = result[5]
|
||
apparat.semester = result[8]
|
||
apparat.deleted = result[9]
|
||
apparat.apparat_adis_id = result[11]
|
||
apparat.prof_adis_id = result[12]
|
||
return apparat</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getApparatId"><code class="name flex">
|
||
<span>def <span class="ident">getApparatId</span></span>(<span>self, apparat_name) ‑> Optional[int]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>get the id of an apparat based on the name</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>apparat_name</code></strong> : <code>str</code></dt>
|
||
<dd>the name of the apparat e.g. "Semesterapparat 1"</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>Optional[int]</code></dt>
|
||
<dd>the id of the apparat, if the apparat is not found, None is returned</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getApparatId(self, apparat_name)->Optional[int]:
|
||
"""get the id of an apparat based on the name
|
||
|
||
Args:
|
||
apparat_name (str): the name of the apparat e.g. "Semesterapparat 1"
|
||
|
||
Returns:
|
||
Optional[int]: the id of the apparat, if the apparat is not found, None is returned
|
||
"""
|
||
data = self.query_db("SELECT appnr FROM semesterapparat WHERE name=?", (apparat_name,), one=True)
|
||
if data is None:
|
||
return None
|
||
else:
|
||
return data[0]</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getApparatName"><code class="name flex">
|
||
<span>def <span class="ident">getApparatName</span></span>(<span>self, app_id: Union[str, int], prof_id: Union[str, int])</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>get the name of the apparat based on the id</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>app_id</code></strong> : <code>Union[str,int]</code></dt>
|
||
<dd>the id of the apparat</dd>
|
||
<dt><strong><code>prof_id</code></strong> : <code>Union[str,int]</code></dt>
|
||
<dd>the id of the professor</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>str</code></dt>
|
||
<dd>the name of the apparat</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getApparatName(self, app_id:Union[str,int], prof_id:Union[str,int]):
|
||
"""get the name of the apparat based on the id
|
||
|
||
Args:
|
||
app_id (Union[str,int]): the id of the apparat
|
||
prof_id (Union[str,int]): the id of the professor
|
||
|
||
Returns:
|
||
str: the name of the apparat
|
||
"""
|
||
return self.query_db("SELECT name FROM semesterapparat WHERE appnr=? AND prof_id=?", (app_id,prof_id), one=True)[0]</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getApparatsByProf"><code class="name flex">
|
||
<span>def <span class="ident">getApparatsByProf</span></span>(<span>self, prof_id: Union[str, int]) ‑> list[tuple]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get all apparats based on the professor id</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>prof_id</code></strong> : <code>Union[str,int]</code></dt>
|
||
<dd>the id of the professor</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>list[tuple]</code></dt>
|
||
<dd>a list of tuples containing the apparats</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getApparatsByProf(self, prof_id:Union[str,int])->list[tuple]:
|
||
"""Get all apparats based on the professor id
|
||
|
||
Args:
|
||
prof_id (Union[str,int]): the id of the professor
|
||
|
||
Returns:
|
||
list[tuple]: a list of tuples containing the apparats
|
||
"""
|
||
return self.query_db("SELECT * FROM semesterapparat WHERE prof_id=?", (prof_id,))</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getApparatsBySemester"><code class="name flex">
|
||
<span>def <span class="ident">getApparatsBySemester</span></span>(<span>self, semester: str) ‑> dict[list]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>get all apparats based on the semester</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>semester</code></strong> : <code>str</code></dt>
|
||
<dd>the selected semester</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>dict[list]</code></dt>
|
||
<dd>a list off all created and deleted apparats for the selected semester</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getApparatsBySemester(self, semester:str)->dict[list]:
|
||
"""get all apparats based on the semester
|
||
|
||
Args:
|
||
semester (str): the selected semester
|
||
|
||
Returns:
|
||
dict[list]: a list off all created and deleted apparats for the selected semester
|
||
"""
|
||
data = self.query_db("SELECT name, prof_id FROM semesterapparat WHERE erstellsemester=?", (semester,))
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
c_tmp = []
|
||
for i in data:
|
||
c_tmp.append((i[0], self.getProfNameById(i[1])))
|
||
query = (
|
||
f"SELECT name,prof_id FROM semesterapparat WHERE deleted_date='{semester}'"
|
||
)
|
||
result = cursor.execute(query).fetchall()
|
||
d_tmp = []
|
||
for i in result:
|
||
d_tmp.append((i[0], self.getProfNameById(i[1])))
|
||
# group the apparats by prof
|
||
c_ret = {}
|
||
for i in c_tmp:
|
||
if i[1] not in c_ret.keys():
|
||
c_ret[i[1]] = [i[0]]
|
||
else:
|
||
c_ret[i[1]].append(i[0])
|
||
d_ret = {}
|
||
for i in d_tmp:
|
||
if i[1] not in d_ret.keys():
|
||
d_ret[i[1]] = [i[0]]
|
||
else:
|
||
d_ret[i[1]].append(i[0])
|
||
self.close_connection(conn)
|
||
return {"created": c_ret, "deleted": d_ret}</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getBlob"><code class="name flex">
|
||
<span>def <span class="ident">getBlob</span></span>(<span>self, filename, app_id: Union[str, int])</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get a blob from the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>filename</code></strong> : <code>str</code></dt>
|
||
<dd>The name of the file</dd>
|
||
<dt><strong><code>app_id</code></strong> : <code>str</code></dt>
|
||
<dd>ID of the apparat</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>bytes</code></dt>
|
||
<dd>The file stored in</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getBlob(self, filename, app_id:Union[str,int]):
|
||
"""
|
||
Get a blob from the database
|
||
|
||
Args:
|
||
filename (str): The name of the file
|
||
app_id (str): ID of the apparat
|
||
|
||
Returns:
|
||
bytes: The file stored in
|
||
"""
|
||
return self.query_db("SELECT fileblob FROM files WHERE filename=? AND app_id=?", (filename,app_id), one=True)[0]</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getBook"><code class="name flex">
|
||
<span>def <span class="ident">getBook</span></span>(<span>self, book_id: int) ‑> src.logic.dataclass.BookData</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get the book based on the id in the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>book_id</code></strong> : <code>int</code></dt>
|
||
<dd>The id of the book</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>BookData</code></dt>
|
||
<dd>The metadata of the book wrapped in a BookData object</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getBook(self,book_id:int)->BookData:
|
||
"""
|
||
Get the book based on the id in the database
|
||
|
||
Args:
|
||
book_id (int): The id of the book
|
||
|
||
Returns:
|
||
BookData: The metadata of the book wrapped in a BookData object
|
||
"""
|
||
return load_pickle(self.query_db("SELECT bookdata FROM media WHERE id=?", (book_id,), one=True)[0])</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getBookBasedOnSignature"><code class="name flex">
|
||
<span>def <span class="ident">getBookBasedOnSignature</span></span>(<span>self, app_id: Union[str, int], prof_id: Union[str, int], signature: str) ‑> src.logic.dataclass.BookData</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get the book based on the signature of the book.</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>app_id</code></strong> : <code>str</code></dt>
|
||
<dd>The apparat id the book should be associated with</dd>
|
||
<dt><strong><code>prof_id</code></strong> : <code>str</code></dt>
|
||
<dd>The professor id the book should be associated with</dd>
|
||
<dt><strong><code>signature</code></strong> : <code>str</code></dt>
|
||
<dd>The signature of the book</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>BookData</code></dt>
|
||
<dd>The total metadata of the book wrapped in a BookData object</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getBookBasedOnSignature(self, app_id:Union[str,int], prof_id:Union[str,int],signature:str)->BookData:
|
||
"""
|
||
Get the book based on the signature of the book.
|
||
|
||
Args:
|
||
app_id (str): The apparat id the book should be associated with
|
||
prof_id (str): The professor id the book should be associated with
|
||
signature (str): The signature of the book
|
||
|
||
Returns:
|
||
BookData: The total metadata of the book wrapped in a BookData object
|
||
"""
|
||
result = self.query_db("SELECT bookdata FROM media WHERE app_id=? AND prof_id=?", (app_id,prof_id))
|
||
books = [load_pickle(i[0]) for i in result]
|
||
book = [i for i in books if i.signature == signature][0]
|
||
return book</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getBookId"><code class="name flex">
|
||
<span>def <span class="ident">getBookId</span></span>(<span>self, bookdata: src.logic.dataclass.BookData, app_id: Union[str, int], prof_id: Union[str, int]) ‑> int</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get the id of a book based on the metadata of the book</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>bookdata</code></strong> : <code>BookData</code></dt>
|
||
<dd>The wrapped metadata of the book</dd>
|
||
<dt><strong><code>app_id</code></strong> : <code>str</code></dt>
|
||
<dd>The apparat id the book should be associated with</dd>
|
||
<dt><strong><code>prof_id</code></strong> : <code>str</code></dt>
|
||
<dd>The professor id the book should be associated with</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>int</code></dt>
|
||
<dd>ID of the book</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getBookId(self, bookdata:BookData, app_id:Union[str,int], prof_id:Union[str,int])->int:
|
||
"""
|
||
Get the id of a book based on the metadata of the book
|
||
|
||
Args:
|
||
bookdata (BookData): The wrapped metadata of the book
|
||
app_id (str): The apparat id the book should be associated with
|
||
prof_id (str): The professor id the book should be associated with
|
||
|
||
Returns:
|
||
int: ID of the book
|
||
"""
|
||
result = self.query_db("SELECT id FROM media WHERE bookdata=? AND app_id=? AND prof_id=?", (dump_pickle(bookdata),app_id,prof_id), one=True)
|
||
return result[0]</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getBookIdBasedOnSignature"><code class="name flex">
|
||
<span>def <span class="ident">getBookIdBasedOnSignature</span></span>(<span>self, app_id: Union[str, int], prof_id: Union[str, int], signature: str) ‑> int</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get a book id based on the signature of the book.</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>app_id</code></strong> : <code>str</code></dt>
|
||
<dd>The apparat id the book should be associated with</dd>
|
||
<dt><strong><code>prof_id</code></strong> : <code>str</code></dt>
|
||
<dd>The professor id the book should be associated with</dd>
|
||
<dt><strong><code>signature</code></strong> : <code>str</code></dt>
|
||
<dd>The signature of the book</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>int</code></dt>
|
||
<dd>The id of the book</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getBookIdBasedOnSignature(self, app_id:Union[str,int], prof_id:Union[str,int],signature:str)->int:
|
||
"""
|
||
Get a book id based on the signature of the book.
|
||
|
||
Args:
|
||
app_id (str): The apparat id the book should be associated with
|
||
prof_id (str): The professor id the book should be associated with
|
||
signature (str): The signature of the book
|
||
|
||
Returns:
|
||
int: The id of the book
|
||
"""
|
||
result = self.query_db("SELECT bookdata, id FROM media WHERE app_id=? AND prof_id=?", (app_id,prof_id))
|
||
books = [(load_pickle(i[0]),i[1]) for i in result]
|
||
book = [i for i in books if i[0].signature == signature][0][1]
|
||
return book</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getBooks"><code class="name flex">
|
||
<span>def <span class="ident">getBooks</span></span>(<span>self, app_id: Union[str, int], prof_id: Union[str, int], deleted=0) ‑> list[dict[int, src.logic.dataclass.BookData, int]]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get the Books based on the apparat id and the professor id</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>app_id</code></strong> : <code>str</code></dt>
|
||
<dd>The ID of the apparat</dd>
|
||
<dt><strong><code>prof_id</code></strong> : <code>str</code></dt>
|
||
<dd>The ID of the professor</dd>
|
||
<dt><strong><code>deleted</code></strong> : <code>int</code>, optional</dt>
|
||
<dd>The state of the book. Set to 1 to include deleted ones. Defaults to 0.</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>list[dict[int, BookData, int]]</code></dt>
|
||
<dd>A list of dictionaries containing the id, the metadata of the book and the availability of the book</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getBooks(self, app_id:Union[str,int], prof_id:Union[str,int], deleted=0)->list[dict[int, BookData, int]]:
|
||
"""
|
||
Get the Books based on the apparat id and the professor id
|
||
|
||
Args:
|
||
app_id (str): The ID of the apparat
|
||
prof_id (str): The ID of the professor
|
||
deleted (int, optional): The state of the book. Set to 1 to include deleted ones. Defaults to 0.
|
||
|
||
Returns:
|
||
list[dict[int, BookData, int]]: A list of dictionaries containing the id, the metadata of the book and the availability of the book
|
||
"""
|
||
qdata = self.query_db(f"SELECT id,bookdata,available FROM media WHERE (app_id={app_id} AND prof_id={prof_id}) AND (deleted={deleted if deleted == 0 else '1 OR deleted=0'})")
|
||
ret_result = []
|
||
for result_a in qdata:
|
||
data = {"id": int, "bookdata": BookData, "available": int}
|
||
data["id"] = result_a[0]
|
||
data["bookdata"] = load_pickle(result_a[1])
|
||
data["available"] = result_a[2]
|
||
ret_result.append(data)
|
||
return ret_result</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getFacultyMember"><code class="name flex">
|
||
<span>def <span class="ident">getFacultyMember</span></span>(<span>self, name: str) ‑> tuple</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>get a faculty member based on the name</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>name</code></strong> : <code>str</code></dt>
|
||
<dd>the name to be searched for</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>tuple</code></dt>
|
||
<dd>a tuple containing the data of the faculty member</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getFacultyMember(self, name:str)->tuple:
|
||
"""get a faculty member based on the name
|
||
|
||
Args:
|
||
name (str): the name to be searched for
|
||
|
||
Returns:
|
||
tuple: a tuple containing the data of the faculty member
|
||
"""
|
||
return self.query_db("SELECT titel, fname,lname,mail,telnr,fullname FROM prof WHERE fullname=?", (name,), one=True)</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getFacultyMembers"><code class="name flex">
|
||
<span>def <span class="ident">getFacultyMembers</span></span>(<span>self)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>get a list of all faculty members</p>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>list[tuple]</code></dt>
|
||
<dd>a list of tuples containing the faculty members</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getFacultyMembers(self):
|
||
"""get a list of all faculty members
|
||
|
||
Returns:
|
||
list[tuple]: a list of tuples containing the faculty members
|
||
"""
|
||
return self.query_db("SELECT titel, fname,lname,mail,telnr,fullname FROM prof")</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getFiles"><code class="name flex">
|
||
<span>def <span class="ident">getFiles</span></span>(<span>self, app_id: Union[str, int], prof_id: int) ‑> list[tuple]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get all the files associated with the apparat and the professor</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>app_id</code></strong> : <code>Union[str,int]</code></dt>
|
||
<dd>The id of the apparat</dd>
|
||
<dt><strong><code>prof_id</code></strong> : <code>Union[str,int]</code></dt>
|
||
<dd>the id of the professor</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>list[tuple]</code></dt>
|
||
<dd>a list of tuples containing the filename and the filetype for the corresponding apparat and professor</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getFiles(self, app_id:Union[str,int], prof_id:int)->list[tuple]:
|
||
"""Get all the files associated with the apparat and the professor
|
||
|
||
Args:
|
||
app_id (Union[str,int]): The id of the apparat
|
||
prof_id (Union[str,int]): the id of the professor
|
||
|
||
Returns:
|
||
list[tuple]: a list of tuples containing the filename and the filetype for the corresponding apparat and professor
|
||
"""
|
||
return self.query_db("SELECT filename, filetyp FROM files WHERE app_id=? AND prof_id=?", (app_id,prof_id))</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getLastBookId"><code class="name flex">
|
||
<span>def <span class="ident">getLastBookId</span></span>(<span>self) ‑> int</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get the last book id in the database</p>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>int</code></dt>
|
||
<dd>ID of the last book in the database</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getLastBookId(self)->int:
|
||
"""
|
||
Get the last book id in the database
|
||
|
||
Returns:
|
||
int: ID of the last book in the database
|
||
"""
|
||
return self.query_db("SELECT id FROM media ORDER BY id DESC", one=True)[0]</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getMessages"><code class="name flex">
|
||
<span>def <span class="ident">getMessages</span></span>(<span>self, date: str) ‑> list[dict[str, str, str, str]]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get all the messages for a specific date</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>date</code></strong> : <code>str</code></dt>
|
||
<dd>a date.datetime object formatted as a string in the format "YYYY-MM-DD"</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>list[dict[str, str, str, str]]</code></dt>
|
||
<dd>a list of dictionaries containing the message, the user who added the message, the apparat id and the id of the message</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getMessages(self, date:str)->list[dict[str, str, str, str]]:
|
||
"""Get all the messages for a specific date
|
||
|
||
Args:
|
||
date (str): a date.datetime object formatted as a string in the format "YYYY-MM-DD"
|
||
|
||
Returns:
|
||
list[dict[str, str, str, str]]: a list of dictionaries containing the message, the user who added the message, the apparat id and the id of the message
|
||
"""
|
||
def __get_user_name(user_id):
|
||
return self.query_db("SELECT username FROM user WHERE id=?", (user_id,), one=True)[0]
|
||
messages = self.query_db("SELECT * FROM messages WHERE remind_at=?", (date,))
|
||
ret = [
|
||
{
|
||
"message": i[2],
|
||
"user": __get_user_name(i[4]),
|
||
"appnr": i[5],
|
||
"id": i[0]
|
||
}
|
||
for i in messages
|
||
]
|
||
return ret</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getProfByName"><code class="name flex">
|
||
<span>def <span class="ident">getProfByName</span></span>(<span>self, prof_name: str) ‑> tuple</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>get all the data of a professor based on the name</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>prof_name</code></strong> : <code>str</code></dt>
|
||
<dd>the name of the professor</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>tuple</code></dt>
|
||
<dd>the data of the professor</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getProfByName(self, prof_name:str)->tuple:
|
||
"""get all the data of a professor based on the name
|
||
|
||
Args:
|
||
prof_name (str): the name of the professor
|
||
|
||
Returns:
|
||
tuple: the data of the professor
|
||
"""
|
||
return self.query_db("SELECT * FROM prof WHERE fullname=?", (prof_name,), one=True)</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getProfData"><code class="name flex">
|
||
<span>def <span class="ident">getProfData</span></span>(<span>self, profname: str)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get mail, telephone number and title of a professor based on the name</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>profname</code></strong> : <code>str</code></dt>
|
||
<dd>name of the professor</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>tuple</code></dt>
|
||
<dd>the mail, telephone number and title of the professor</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getProfData(self, profname:str):
|
||
"""Get mail, telephone number and title of a professor based on the name
|
||
|
||
Args:
|
||
profname (str): name of the professor
|
||
|
||
Returns:
|
||
tuple: the mail, telephone number and title of the professor
|
||
"""
|
||
data = self.query_db("SELECT mail, telnr, titel FROM prof WHERE fullname=?", (profname.replace(",",""),), one=True)
|
||
return data</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getProfId"><code class="name flex">
|
||
<span>def <span class="ident">getProfId</span></span>(<span>self, prof_name: str) ‑> Optional[int]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get the id of a professor based on the name</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>prof_name</code></strong> : <code>str</code></dt>
|
||
<dd>the name of the professor</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>Optional[int]</code></dt>
|
||
<dd>the id of the professor, if the professor is not found, None is returned</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getProfId(self, prof_name:str)->Optional[int]:
|
||
"""Get the id of a professor based on the name
|
||
|
||
Args:
|
||
prof_name (str): the name of the professor
|
||
|
||
Returns:
|
||
Optional[int]: the id of the professor, if the professor is not found, None is returned
|
||
"""
|
||
|
||
data = self.getProfByName(prof_name.replace(",", ""))
|
||
if data is None:
|
||
return None
|
||
else:
|
||
return data[0]</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getProfNameById"><code class="name flex">
|
||
<span>def <span class="ident">getProfNameById</span></span>(<span>self, prof_id: Union[str, int], add_title: bool = False) ‑> str</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get a professor name based on the id</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>prof_id</code></strong> : <code>Union[str,int]</code></dt>
|
||
<dd>The id of the professor</dd>
|
||
<dt><strong><code>add_title</code></strong> : <code>bool</code>, optional</dt>
|
||
<dd>wether to add the title or no. Defaults to False.</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>str</code></dt>
|
||
<dd>The name of the professor</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getProfNameById(self, prof_id:Union[str,int],add_title:bool=False)->str:
|
||
"""Get a professor name based on the id
|
||
|
||
Args:
|
||
prof_id (Union[str,int]): The id of the professor
|
||
add_title (bool, optional): wether to add the title or no. Defaults to False.
|
||
|
||
Returns:
|
||
str: The name of the professor
|
||
"""
|
||
prof = self.query_db("SELECT fullname FROM prof WHERE id=?", (prof_id,), one=True)
|
||
if add_title:
|
||
return f"{self.getTitleById(prof_id)}{prof[0]}"
|
||
else:
|
||
return prof[0]</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getProfs"><code class="name flex">
|
||
<span>def <span class="ident">getProfs</span></span>(<span>self) ‑> list[tuple]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Return all the professors in the database</p>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>list[tuple]</code></dt>
|
||
<dd>a list containing all the professors in individual tuples</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getProfs(self)->list[tuple]:
|
||
"""Return all the professors in the database
|
||
|
||
Returns:
|
||
list[tuple]: a list containing all the professors in individual tuples
|
||
"""
|
||
return self.query_db("SELECT * FROM prof")</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getRole"><code class="name flex">
|
||
<span>def <span class="ident">getRole</span></span>(<span>self, user)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>get the role of the user</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>user</code></strong> : <code>str</code></dt>
|
||
<dd>username</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>str</code></dt>
|
||
<dd>the name of the role</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getRole(self, user):
|
||
"""get the role of the user
|
||
|
||
Args:
|
||
user (str): username
|
||
|
||
Returns:
|
||
str: the name of the role
|
||
"""
|
||
return self.query_db("SELECT role FROM user WHERE username=?", (user,), one=True)[0]</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getRoles"><code class="name flex">
|
||
<span>def <span class="ident">getRoles</span></span>(<span>self) ‑> list[tuple]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>get all the roles in the database</p>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>list[str]</code></dt>
|
||
<dd>a list of all the roles</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getRoles(self)->list[tuple]:
|
||
"""get all the roles in the database
|
||
|
||
Returns:
|
||
list[str]: a list of all the roles
|
||
"""
|
||
return self.query_db("SELECT role FROM user")</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getSemersters"><code class="name flex">
|
||
<span>def <span class="ident">getSemersters</span></span>(<span>self) ‑> list[str]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Return all the unique semesters in the database</p>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>list</code></dt>
|
||
<dd>a list of strings containing the semesters</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getSemersters(self)->list[str]:
|
||
"""Return all the unique semesters in the database
|
||
|
||
Returns:
|
||
list: a list of strings containing the semesters
|
||
"""
|
||
data = self.query_db("SELECT DISTINCT erstellsemester FROM semesterapparat")
|
||
return [i[0] for i in data]</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getSpecificProfData"><code class="name flex">
|
||
<span>def <span class="ident">getSpecificProfData</span></span>(<span>self, prof_id: Union[str, int], fields: List[str]) ‑> tuple</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>A customisable function to get specific data of a professor based on the id</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>prof_id</code></strong> : <code>Union[str,int]</code></dt>
|
||
<dd>the id of the professor</dd>
|
||
<dt><strong><code>fields</code></strong> : <code>List[str]</code></dt>
|
||
<dd>a list of fields to be returned</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>tuple</code></dt>
|
||
<dd>a tuple containing the requested data</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getSpecificProfData(self, prof_id:Union[str,int], fields:List[str])->tuple:
|
||
"""A customisable function to get specific data of a professor based on the id
|
||
|
||
Args:
|
||
prof_id (Union[str,int]): the id of the professor
|
||
fields (List[str]): a list of fields to be returned
|
||
|
||
Returns:
|
||
tuple: a tuple containing the requested data
|
||
"""
|
||
query = "SELECT "
|
||
for field in fields:
|
||
query += f"{field},"
|
||
query = query[:-1]
|
||
query += " FROM prof WHERE id=?"
|
||
return self.query_db(query, (prof_id,), one=True)[0]</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getSubjects"><code class="name flex">
|
||
<span>def <span class="ident">getSubjects</span></span>(<span>self)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get all the subjects in the database</p>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>list[tuple]</code></dt>
|
||
<dd>a list of tuples containing the subjects</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getSubjects(self):
|
||
"""Get all the subjects in the database
|
||
|
||
Returns:
|
||
list[tuple]: a list of tuples containing the subjects
|
||
"""
|
||
return self.query_db("SELECT * FROM subjects")</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getTitleById"><code class="name flex">
|
||
<span>def <span class="ident">getTitleById</span></span>(<span>self, prof_id: Union[str, int]) ‑> str</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>get the title of a professor based on the id</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>prof_id</code></strong> : <code>Union[str,int]</code></dt>
|
||
<dd>the id of the professor</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>str</code></dt>
|
||
<dd>the title of the professor, with an added whitespace at the end, if no title is present, an empty string is returned</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getTitleById(self, prof_id:Union[str,int])->str:
|
||
"""get the title of a professor based on the id
|
||
|
||
Args:
|
||
prof_id (Union[str,int]): the id of the professor
|
||
|
||
Returns:
|
||
str: the title of the professor, with an added whitespace at the end, if no title is present, an empty string is returned
|
||
"""
|
||
title = self.query_db("SELECT titel FROM prof WHERE id=?", (prof_id,), one=True)[0]
|
||
return f"{title} " if title is not None else ""</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getUnavailableApparatNumbers"><code class="name flex">
|
||
<span>def <span class="ident">getUnavailableApparatNumbers</span></span>(<span>self) ‑> List[int]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get a list of all the apparat numbers in the database that are currently in use</p>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>List[int]</code></dt>
|
||
<dd>the list of used apparat numbers</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getUnavailableApparatNumbers(self)->List[int]:
|
||
"""Get a list of all the apparat numbers in the database that are currently in use
|
||
|
||
Returns:
|
||
List[int]: the list of used apparat numbers
|
||
"""
|
||
numbers = self.query_db("SELECT appnr FROM semesterapparat WHERE deletion_status=0")
|
||
numbers = [i[0] for i in numbers]
|
||
logger.log_info(f"Currently used apparat numbers: {numbers}")
|
||
return numbers</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getUser"><code class="name flex">
|
||
<span>def <span class="ident">getUser</span></span>(<span>self)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get a single user from the database</p></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getUser(self):
|
||
"""Get a single user from the database"""
|
||
return self.query_db("SELECT * FROM user", one=True)</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.getUsers"><code class="name flex">
|
||
<span>def <span class="ident">getUsers</span></span>(<span>self) ‑> list[tuple]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Return a list of tuples of all the users in the database</p></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def getUsers(self)->list[tuple]:
|
||
"""Return a list of tuples of all the users in the database"""
|
||
return self.query_db("SELECT * FROM user")</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.get_db_contents"><code class="name flex">
|
||
<span>def <span class="ident">get_db_contents</span></span>(<span>self) ‑> Optional[List[Tuple]]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Get the contents of the </p>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>Union[List[Tuple], None]</code></dt>
|
||
<dd><em>description</em></dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def get_db_contents(self)->Union[List[Tuple], None]:
|
||
"""
|
||
Get the contents of the
|
||
|
||
Returns:
|
||
Union[List[Tuple], None]: _description_
|
||
"""
|
||
try:
|
||
with sql.connect(self.db_path) as conn:
|
||
cursor = conn.cursor()
|
||
cursor.execute("SELECT * FROM sqlite_master WHERE type='table'")
|
||
return cursor.fetchall()
|
||
except sql.OperationalError:
|
||
return None</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.insertFile"><code class="name flex">
|
||
<span>def <span class="ident">insertFile</span></span>(<span>self, file: list[dict], app_id: Union[str, int], prof_id: Union[str, int])</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Instert a list of files into the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>file</code></strong> : <code>list[dict]</code></dt>
|
||
<dd>a list containing all the files to be inserted</dd>
|
||
<dt><strong><code>Structured</code></strong></dt>
|
||
<dd>[{"name": "filename", "path": "path", "type": "filetype"}]</dd>
|
||
<dt><strong><code>app_id</code></strong> : <code>int</code></dt>
|
||
<dd>the id of the apparat</dd>
|
||
<dt><strong><code>prof_id</code></strong> : <code>str</code></dt>
|
||
<dd>the id of the professor</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def insertFile(self, file: list[dict], app_id:Union[str,int], prof_id:Union[str,int]):
|
||
"""Instert a list of files into the database
|
||
|
||
Args:
|
||
file (list[dict]): a list containing all the files to be inserted
|
||
Structured: [{"name": "filename", "path": "path", "type": "filetype"}]
|
||
app_id (int): the id of the apparat
|
||
prof_id (str): the id of the professor
|
||
"""
|
||
for f in file:
|
||
filename = f["name"]
|
||
path = f["path"]
|
||
filetyp = f["type"]
|
||
if path == "Database":
|
||
continue
|
||
blob = create_blob(path)
|
||
query = "INSERT OR IGNORE INTO files (filename, fileblob, app_id, filetyp,prof_id) VALUES (?, ?, ?, ?,?)"
|
||
self.query_db(query, (filename, blob, app_id, filetyp,prof_id))</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.insertInto"><code class="name flex">
|
||
<span>def <span class="ident">insertInto</span></span>(<span>self, query: str, params: Tuple) ‑> None</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Insert sent data into the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>query</code></strong> : <code>str</code></dt>
|
||
<dd>The query to be executed</dd>
|
||
<dt><strong><code>params</code></strong> : <code>Tuple</code></dt>
|
||
<dd>the parameters to be inserted into the database</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def insertInto(self, query:str, params:Tuple) -> None:
|
||
"""
|
||
Insert sent data into the database
|
||
|
||
Args:
|
||
query (str): The query to be executed
|
||
params (Tuple): the parameters to be inserted into the database
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
logger.log_info(f"Inserting {params} into database with query {query}")
|
||
cursor.execute(query, params)
|
||
conn.commit()
|
||
self.close_connection(conn)</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.isEternal"><code class="name flex">
|
||
<span>def <span class="ident">isEternal</span></span>(<span>self, id)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>check if the apparat is eternal (dauerapparat)</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>id</code></strong> : <code>int</code></dt>
|
||
<dd>the id of the apparat to be checked</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>int</code></dt>
|
||
<dd>the state of the apparat</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def isEternal(self, id):
|
||
"""check if the apparat is eternal (dauerapparat)
|
||
|
||
Args:
|
||
id (int): the id of the apparat to be checked
|
||
|
||
Returns:
|
||
int: the state of the apparat
|
||
"""
|
||
return self.query_db("SELECT dauer FROM semesterapparat WHERE appnr=?", (id,), one=True)</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.login"><code class="name flex">
|
||
<span>def <span class="ident">login</span></span>(<span>self, user, hashed_password)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>try to login the user.
|
||
The salt for the user will be requested from the database and then added to the hashed password. The password will then be compared to the password in the database </p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>user</code></strong> : <code>str</code></dt>
|
||
<dd>username that tries to login</dd>
|
||
<dt><strong><code>hashed_password</code></strong> : <code>str</code></dt>
|
||
<dd>the password the user tries to login with</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>bool</code></dt>
|
||
<dd>True if the login was successful, False if not</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def login(self, user, hashed_password):
|
||
"""try to login the user.
|
||
The salt for the user will be requested from the database and then added to the hashed password. The password will then be compared to the password in the database
|
||
|
||
Args:
|
||
user (str): username that tries to login
|
||
hashed_password (str): the password the user tries to login with
|
||
|
||
Returns:
|
||
bool: True if the login was successful, False if not
|
||
"""
|
||
salt = self.query_db("SELECT salt FROM user WHERE username=?", (user,), one=True)[0]
|
||
if salt is None:
|
||
return False
|
||
hashed_password = salt + hashed_password
|
||
password = self.query_db("SELECT password FROM user WHERE username=?", (user,), one=True)[0]
|
||
if password == hashed_password:
|
||
return True
|
||
else:
|
||
return False</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.query_db"><code class="name flex">
|
||
<span>def <span class="ident">query_db</span></span>(<span>self, query: str, args: Tuple = (), one: bool = False) ‑> Union[Tuple, List[Tuple]]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Query the Database for the sent query.</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>query</code></strong> : <code>str</code></dt>
|
||
<dd>The query to be executed</dd>
|
||
<dt><strong><code>args</code></strong> : <code>Tuple</code>, optional</dt>
|
||
<dd>The arguments for the query. Defaults to ().</dd>
|
||
<dt><strong><code>one</code></strong> : <code>bool</code>, optional</dt>
|
||
<dd>Return the first result only. Defaults to False.</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<p>Union[Typle|List[Tuple]]: Returns the result of the query</p></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def query_db(self, query: str, args: Tuple = (), one: bool = False)->Union[Tuple, List[Tuple]]:
|
||
"""
|
||
Query the Database for the sent query.
|
||
|
||
Args:
|
||
query (str): The query to be executed
|
||
args (Tuple, optional): The arguments for the query. Defaults to ().
|
||
one (bool, optional): Return the first result only. Defaults to False.
|
||
|
||
Returns:
|
||
Union[Typle|List[Tuple]]: Returns the result of the query
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
logger.log_info(f"Querying database with query {query}, args: {args}")
|
||
cursor.execute(query, args)
|
||
rv = cursor.fetchall()
|
||
conn.commit()
|
||
self.close_connection(conn)
|
||
return (rv[0] if rv else None) if one else rv</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.recreateFile"><code class="name flex">
|
||
<span>def <span class="ident">recreateFile</span></span>(<span>self, filename: str, app_id: Union[str, int], filetype: str) ‑> str</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Recreate a file from the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>filename</code></strong> : <code>str</code></dt>
|
||
<dd>the name of the file</dd>
|
||
<dt><strong><code>app_id</code></strong> : <code>Union[str,int]</code></dt>
|
||
<dd>the id of the apparat</dd>
|
||
<dt><strong><code>filetype</code></strong> : <code>str</code></dt>
|
||
<dd>the extension of the file to be created</dd>
|
||
</dl>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>str</code></dt>
|
||
<dd>The filename of the recreated file</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def recreateFile(self, filename:str, app_id:Union[str,int],filetype:str)->str:
|
||
"""Recreate a file from the database
|
||
|
||
Args:
|
||
filename (str): the name of the file
|
||
app_id (Union[str,int]): the id of the apparat
|
||
filetype (str): the extension of the file to be created
|
||
|
||
Returns:
|
||
str: The filename of the recreated file
|
||
"""
|
||
blob = self.getBlob(filename, app_id)
|
||
tempdir = config.database.tempdir
|
||
tempdir = tempdir.replace("~", str(Path.home()))
|
||
tempdir_path = Path(tempdir)
|
||
if not os.path.exists(tempdir_path):
|
||
os.mkdir(tempdir_path)
|
||
file = tempfile.NamedTemporaryFile(
|
||
delete=False, dir=tempdir_path, mode="wb", suffix=f".{filetype}"
|
||
)
|
||
file.write(blob)
|
||
print("file created")
|
||
return file.name</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.searchBook"><code class="name flex">
|
||
<span>def <span class="ident">searchBook</span></span>(<span>self, data: dict[str, str]) ‑> list[tuple[src.logic.dataclass.BookData, int]]</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Search a book in the database based on the sent data.</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>data</code></strong> : <code>dict[str, str]</code></dt>
|
||
<dd>A dictionary containing the data to be searched for. The dictionary can contain the following: </dd>
|
||
</dl>
|
||
<ul>
|
||
<li>signature: The signature of the book</li>
|
||
<li>title: The title of the book</li>
|
||
</ul>
|
||
<h2 id="returns">Returns</h2>
|
||
<dl>
|
||
<dt><code>list[tuple[BookData, int]]</code></dt>
|
||
<dd>A list of tuples containing the wrapped Metadata and the id of the book</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def searchBook(self, data:dict[str, str])->list[tuple[BookData, int]]:
|
||
"""
|
||
Search a book in the database based on the sent data.
|
||
|
||
Args:
|
||
data (dict[str, str]): A dictionary containing the data to be searched for. The dictionary can contain the following:
|
||
- signature: The signature of the book
|
||
- title: The title of the book
|
||
|
||
Returns:
|
||
list[tuple[BookData, int]]: A list of tuples containing the wrapped Metadata and the id of the book
|
||
"""
|
||
rdata = self.query_db("SELECT * FROM media WHERE deleted=0")
|
||
ic(rdata, len(rdata))
|
||
mode = 0
|
||
if len(data)== 1:
|
||
if "signature" in data.keys():
|
||
mode = 1
|
||
elif "title" in data.keys():
|
||
mode = 2
|
||
elif len(data) == 2:
|
||
mode = 3
|
||
else:
|
||
return None
|
||
ret = []
|
||
for book in rdata:
|
||
bookdata = load_pickle(book[1])
|
||
app_id = book[2]
|
||
prof_id = book[3]
|
||
if mode == 1:
|
||
if data["signature"] in bookdata.signature:
|
||
ret.append((bookdata,app_id,prof_id))
|
||
elif mode == 2:
|
||
if data["title"] in bookdata.title:
|
||
ret.append((bookdata,app_id,prof_id))
|
||
elif mode == 3:
|
||
if data["signature"] in bookdata.signature and data["title"] in bookdata.title:
|
||
ret.append((bookdata,app_id,prof_id))
|
||
ic(ret)
|
||
return ret</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.setAvailability"><code class="name flex">
|
||
<span>def <span class="ident">setAvailability</span></span>(<span>self, book_id: str, available: str)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Set the availability of a book in the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>book_id</code></strong> : <code>str</code></dt>
|
||
<dd>The id of the book</dd>
|
||
<dt><strong><code>available</code></strong> : <code>str</code></dt>
|
||
<dd>The availability of the book</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def setAvailability(self, book_id:str, available:str):
|
||
"""
|
||
Set the availability of a book in the database
|
||
|
||
Args:
|
||
book_id (str): The id of the book
|
||
available (str): The availability of the book
|
||
"""
|
||
self.query_db("UPDATE media SET available=? WHERE id=?", (available,book_id))</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.setNewSemesterDate"><code class="name flex">
|
||
<span>def <span class="ident">setNewSemesterDate</span></span>(<span>self, app_id: Union[str, int], newDate, dauerapp=False)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Set the new semester date for an apparat</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>app_id</code></strong> : <code>Union[str,int]</code></dt>
|
||
<dd>the id of the apparat</dd>
|
||
<dt><strong><code>newDate</code></strong> : <code>str</code></dt>
|
||
<dd>the new date</dd>
|
||
<dt><strong><code>dauerapp</code></strong> : <code>bool</code>, optional</dt>
|
||
<dd>if the apparat was changed to dauerapparat. Defaults to False.</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def setNewSemesterDate(self, app_id:Union[str,int], newDate, dauerapp=False):
|
||
"""Set the new semester date for an apparat
|
||
|
||
Args:
|
||
app_id (Union[str,int]): the id of the apparat
|
||
newDate (str): the new date
|
||
dauerapp (bool, optional): if the apparat was changed to dauerapparat. Defaults to False.
|
||
"""
|
||
date = datetime.datetime.strptime(newDate, "%d.%m.%Y").strftime("%Y-%m-%d")
|
||
if dauerapp:
|
||
self.query_db("UPDATE semesterapparat SET verlängerung_bis=?, dauerapp=? WHERE appnr=?", (date,dauerapp,app_id))
|
||
else:
|
||
self.query_db("UPDATE semesterapparat SET endsemester=? WHERE appnr=?", (date,app_id))</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.statistic_request"><code class="name flex">
|
||
<span>def <span class="ident">statistic_request</span></span>(<span>self, **kwargs: Any)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Take n amount of kwargs and return the result of the query</p></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def statistic_request(self, **kwargs: Any):
|
||
"""Take n amount of kwargs and return the result of the query
|
||
"""
|
||
def __query(query):
|
||
"""execute the query and return the result
|
||
|
||
Args:
|
||
query (str): the constructed query
|
||
|
||
Returns:
|
||
list: the result of the query
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
result = cursor.execute(query).fetchall()
|
||
for result_a in result:
|
||
orig_value = result_a
|
||
prof_name = self.getProfNameById(result_a[2])
|
||
# replace the prof_id with the prof_name
|
||
result_a = list(result_a)
|
||
result_a[2] = prof_name
|
||
result_a = tuple(result_a)
|
||
result[result.index(orig_value)] = result_a
|
||
self.close_connection(conn)
|
||
return result
|
||
if "deletable" in kwargs.keys():
|
||
query = f"SELECT * FROM semesterapparat WHERE deletion_status=0 AND dauer=0 AND (erstellsemester!='{kwargs['deletesemester']}' OR verlängerung_bis!='{kwargs['deletesemester']}')"
|
||
return __query(query)
|
||
if "dauer" in kwargs.keys():
|
||
kwargs["dauer"] = kwargs["dauer"].replace("Ja", "1").replace("Nein", "0")
|
||
query = "SELECT * FROM semesterapparat WHERE "
|
||
for key, value in kwargs.items() if kwargs.items() is not None else {}:
|
||
print(key, value)
|
||
query += f"{key}='{value}' AND "
|
||
print(query)
|
||
# remove deletesemester part from normal query, as this will be added to the database upon deleting the apparat
|
||
if "deletesemester" in kwargs.keys():
|
||
query = query.replace(
|
||
f"deletesemester='{kwargs['deletesemester']}' AND ", ""
|
||
)
|
||
if "endsemester" in kwargs.keys():
|
||
if "erstellsemester" in kwargs.keys():
|
||
query = query.replace(f"endsemester='{kwargs['endsemester']}' AND ", "")
|
||
query = query.replace(
|
||
f"erstellsemester='{kwargs['erstellsemester']} AND ", "xyz"
|
||
)
|
||
else:
|
||
query = query.replace(
|
||
f"endsemester='{kwargs['endsemester']}' AND ", "xyz"
|
||
)
|
||
print("replaced")
|
||
query = query.replace(
|
||
"xyz",
|
||
f"(erstellsemester='{kwargs['endsemester']}' OR verlängerung_bis='{kwargs['endsemester']}') AND ",
|
||
)
|
||
# remove all x="" parts from the query where x is a key in kwargs
|
||
query = query[:-5]
|
||
print(query)
|
||
return __query(query)</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.updateApparat"><code class="name flex">
|
||
<span>def <span class="ident">updateApparat</span></span>(<span>self, apparat_data: src.logic.dataclass.ApparatData)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Update an apparat in the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>apparat_data</code></strong> : <code>ApparatData</code></dt>
|
||
<dd>the new metadata of the apparat</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def updateApparat(self, apparat_data:ApparatData):
|
||
"""Update an apparat in the database
|
||
|
||
Args:
|
||
apparat_data (ApparatData): the new metadata of the apparat
|
||
"""
|
||
query = f"UPDATE semesterapparat SET name = ?, fach = ?, dauer = ?, prof_id = ? WHERE appnr = ?"
|
||
params = (
|
||
apparat_data.appname,
|
||
apparat_data.app_fach,
|
||
apparat_data.dauerapp,
|
||
self.getProfId(apparat_data.profname),
|
||
apparat_data.appnr,
|
||
)
|
||
self.query_db(query, params)</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.updateBookdata"><code class="name flex">
|
||
<span>def <span class="ident">updateBookdata</span></span>(<span>self, book_id, bookdata: src.logic.dataclass.BookData)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>Update the bookdata in the database</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>book_id</code></strong> : <code>str</code></dt>
|
||
<dd>The id of the book</dd>
|
||
<dt><strong><code>bookdata</code></strong> : <code>BookData</code></dt>
|
||
<dd>The new metadata of the book</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def updateBookdata(self, book_id, bookdata:BookData):
|
||
"""
|
||
Update the bookdata in the database
|
||
|
||
Args:
|
||
book_id (str): The id of the book
|
||
bookdata (BookData): The new metadata of the book
|
||
"""
|
||
self.query_db("UPDATE media SET bookdata=? WHERE id=?", (dump_pickle(bookdata),book_id))</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.updateFacultyMember"><code class="name flex">
|
||
<span>def <span class="ident">updateFacultyMember</span></span>(<span>self, data: dict, oldlname: str, oldfname: str)</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>update the data of a faculty member</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>data</code></strong> : <code>dict</code></dt>
|
||
<dd>a dictionary containing the data to be updated</dd>
|
||
<dt><strong><code>oldlname</code></strong> : <code>str</code></dt>
|
||
<dd>the old last name of the faculty member</dd>
|
||
<dt><strong><code>oldfname</code></strong> : <code>str</code></dt>
|
||
<dd>the old first name of the faculty member</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def updateFacultyMember(self, data:dict, oldlname:str, oldfname:str):
|
||
"""update the data of a faculty member
|
||
|
||
Args:
|
||
data (dict): a dictionary containing the data to be updated
|
||
oldlname (str): the old last name of the faculty member
|
||
oldfname (str): the old first name of the faculty member
|
||
"""
|
||
placeholders = ", ".join([f"{i}=:{i} " for i in data.keys()])
|
||
query = f"UPDATE prof SET {placeholders} WHERE lname = :oldlname AND fname = :oldfname"
|
||
data["oldlname"] = oldlname
|
||
data["oldfname"] = oldfname
|
||
self.query_db(query, data)</code></pre>
|
||
</details>
|
||
</dd>
|
||
<dt id="database.Database.updateUser"><code class="name flex">
|
||
<span>def <span class="ident">updateUser</span></span>(<span>self, username, data: dict[str, str])</span>
|
||
</code></dt>
|
||
<dd>
|
||
<div class="desc"><p>changge the data of a user</p>
|
||
<h2 id="args">Args</h2>
|
||
<dl>
|
||
<dt><strong><code>username</code></strong> : <code>str</code></dt>
|
||
<dd>the username of the user</dd>
|
||
<dt><strong><code>data</code></strong> : <code>dict[str, str]</code></dt>
|
||
<dd>the data to be changed</dd>
|
||
</dl></div>
|
||
<details class="source">
|
||
<summary>
|
||
<span>Expand source code</span>
|
||
</summary>
|
||
<pre><code class="python">def updateUser(self, username, data:dict[str, str]):
|
||
"""changge the data of a user
|
||
|
||
Args:
|
||
username (str): the username of the user
|
||
data (dict[str, str]): the data to be changed
|
||
"""
|
||
conn = self.connect()
|
||
cursor = conn.cursor()
|
||
query = "UPDATE user SET "
|
||
for key,value in data.items():
|
||
if key == "username":
|
||
continue
|
||
query += f"{key}='{value}',"
|
||
query = query[:-1]
|
||
query += " WHERE username=?"
|
||
params = (username,)
|
||
cursor.execute(query, params)
|
||
conn.commit()
|
||
self.close_connection(conn)</code></pre>
|
||
</details>
|
||
</dd>
|
||
</dl>
|
||
</dd>
|
||
</dl>
|
||
</section>
|
||
</article>
|
||
<nav id="sidebar">
|
||
<h1>Index</h1>
|
||
<div class="toc">
|
||
<ul></ul>
|
||
</div>
|
||
<ul id="index">
|
||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||
<ul>
|
||
<li>
|
||
<h4><code><a title="database.Database" href="#database.Database">Database</a></code></h4>
|
||
<ul class="">
|
||
<li><code><a title="database.Database.addBookToDatabase" href="#database.Database.addBookToDatabase">addBookToDatabase</a></code></li>
|
||
<li><code><a title="database.Database.addMessage" href="#database.Database.addMessage">addMessage</a></code></li>
|
||
<li><code><a title="database.Database.changePassword" href="#database.Database.changePassword">changePassword</a></code></li>
|
||
<li><code><a title="database.Database.checkApparatExists" href="#database.Database.checkApparatExists">checkApparatExists</a></code></li>
|
||
<li><code><a title="database.Database.checkApparatExistsById" href="#database.Database.checkApparatExistsById">checkApparatExistsById</a></code></li>
|
||
<li><code><a title="database.Database.checkUsername" href="#database.Database.checkUsername">checkUsername</a></code></li>
|
||
<li><code><a title="database.Database.close_connection" href="#database.Database.close_connection">close_connection</a></code></li>
|
||
<li><code><a title="database.Database.connect" href="#database.Database.connect">connect</a></code></li>
|
||
<li><code><a title="database.Database.createApparat" href="#database.Database.createApparat">createApparat</a></code></li>
|
||
<li><code><a title="database.Database.createProf" href="#database.Database.createProf">createProf</a></code></li>
|
||
<li><code><a title="database.Database.createUser" href="#database.Database.createUser">createUser</a></code></li>
|
||
<li><code><a title="database.Database.create_tables" href="#database.Database.create_tables">create_tables</a></code></li>
|
||
<li><code><a title="database.Database.deleteApparat" href="#database.Database.deleteApparat">deleteApparat</a></code></li>
|
||
<li><code><a title="database.Database.deleteBook" href="#database.Database.deleteBook">deleteBook</a></code></li>
|
||
<li><code><a title="database.Database.deleteMessage" href="#database.Database.deleteMessage">deleteMessage</a></code></li>
|
||
<li><code><a title="database.Database.deleteUser" href="#database.Database.deleteUser">deleteUser</a></code></li>
|
||
<li><code><a title="database.Database.getAllAparats" href="#database.Database.getAllAparats">getAllAparats</a></code></li>
|
||
<li><code><a title="database.Database.getApparatCountBySemester" href="#database.Database.getApparatCountBySemester">getApparatCountBySemester</a></code></li>
|
||
<li><code><a title="database.Database.getApparatData" href="#database.Database.getApparatData">getApparatData</a></code></li>
|
||
<li><code><a title="database.Database.getApparatId" href="#database.Database.getApparatId">getApparatId</a></code></li>
|
||
<li><code><a title="database.Database.getApparatName" href="#database.Database.getApparatName">getApparatName</a></code></li>
|
||
<li><code><a title="database.Database.getApparatsByProf" href="#database.Database.getApparatsByProf">getApparatsByProf</a></code></li>
|
||
<li><code><a title="database.Database.getApparatsBySemester" href="#database.Database.getApparatsBySemester">getApparatsBySemester</a></code></li>
|
||
<li><code><a title="database.Database.getBlob" href="#database.Database.getBlob">getBlob</a></code></li>
|
||
<li><code><a title="database.Database.getBook" href="#database.Database.getBook">getBook</a></code></li>
|
||
<li><code><a title="database.Database.getBookBasedOnSignature" href="#database.Database.getBookBasedOnSignature">getBookBasedOnSignature</a></code></li>
|
||
<li><code><a title="database.Database.getBookId" href="#database.Database.getBookId">getBookId</a></code></li>
|
||
<li><code><a title="database.Database.getBookIdBasedOnSignature" href="#database.Database.getBookIdBasedOnSignature">getBookIdBasedOnSignature</a></code></li>
|
||
<li><code><a title="database.Database.getBooks" href="#database.Database.getBooks">getBooks</a></code></li>
|
||
<li><code><a title="database.Database.getFacultyMember" href="#database.Database.getFacultyMember">getFacultyMember</a></code></li>
|
||
<li><code><a title="database.Database.getFacultyMembers" href="#database.Database.getFacultyMembers">getFacultyMembers</a></code></li>
|
||
<li><code><a title="database.Database.getFiles" href="#database.Database.getFiles">getFiles</a></code></li>
|
||
<li><code><a title="database.Database.getLastBookId" href="#database.Database.getLastBookId">getLastBookId</a></code></li>
|
||
<li><code><a title="database.Database.getMessages" href="#database.Database.getMessages">getMessages</a></code></li>
|
||
<li><code><a title="database.Database.getProfByName" href="#database.Database.getProfByName">getProfByName</a></code></li>
|
||
<li><code><a title="database.Database.getProfData" href="#database.Database.getProfData">getProfData</a></code></li>
|
||
<li><code><a title="database.Database.getProfId" href="#database.Database.getProfId">getProfId</a></code></li>
|
||
<li><code><a title="database.Database.getProfNameById" href="#database.Database.getProfNameById">getProfNameById</a></code></li>
|
||
<li><code><a title="database.Database.getProfs" href="#database.Database.getProfs">getProfs</a></code></li>
|
||
<li><code><a title="database.Database.getRole" href="#database.Database.getRole">getRole</a></code></li>
|
||
<li><code><a title="database.Database.getRoles" href="#database.Database.getRoles">getRoles</a></code></li>
|
||
<li><code><a title="database.Database.getSemersters" href="#database.Database.getSemersters">getSemersters</a></code></li>
|
||
<li><code><a title="database.Database.getSpecificProfData" href="#database.Database.getSpecificProfData">getSpecificProfData</a></code></li>
|
||
<li><code><a title="database.Database.getSubjects" href="#database.Database.getSubjects">getSubjects</a></code></li>
|
||
<li><code><a title="database.Database.getTitleById" href="#database.Database.getTitleById">getTitleById</a></code></li>
|
||
<li><code><a title="database.Database.getUnavailableApparatNumbers" href="#database.Database.getUnavailableApparatNumbers">getUnavailableApparatNumbers</a></code></li>
|
||
<li><code><a title="database.Database.getUser" href="#database.Database.getUser">getUser</a></code></li>
|
||
<li><code><a title="database.Database.getUsers" href="#database.Database.getUsers">getUsers</a></code></li>
|
||
<li><code><a title="database.Database.get_db_contents" href="#database.Database.get_db_contents">get_db_contents</a></code></li>
|
||
<li><code><a title="database.Database.insertFile" href="#database.Database.insertFile">insertFile</a></code></li>
|
||
<li><code><a title="database.Database.insertInto" href="#database.Database.insertInto">insertInto</a></code></li>
|
||
<li><code><a title="database.Database.isEternal" href="#database.Database.isEternal">isEternal</a></code></li>
|
||
<li><code><a title="database.Database.login" href="#database.Database.login">login</a></code></li>
|
||
<li><code><a title="database.Database.query_db" href="#database.Database.query_db">query_db</a></code></li>
|
||
<li><code><a title="database.Database.recreateFile" href="#database.Database.recreateFile">recreateFile</a></code></li>
|
||
<li><code><a title="database.Database.searchBook" href="#database.Database.searchBook">searchBook</a></code></li>
|
||
<li><code><a title="database.Database.setAvailability" href="#database.Database.setAvailability">setAvailability</a></code></li>
|
||
<li><code><a title="database.Database.setNewSemesterDate" href="#database.Database.setNewSemesterDate">setNewSemesterDate</a></code></li>
|
||
<li><code><a title="database.Database.statistic_request" href="#database.Database.statistic_request">statistic_request</a></code></li>
|
||
<li><code><a title="database.Database.updateApparat" href="#database.Database.updateApparat">updateApparat</a></code></li>
|
||
<li><code><a title="database.Database.updateBookdata" href="#database.Database.updateBookdata">updateBookdata</a></code></li>
|
||
<li><code><a title="database.Database.updateFacultyMember" href="#database.Database.updateFacultyMember">updateFacultyMember</a></code></li>
|
||
<li><code><a title="database.Database.updateUser" href="#database.Database.updateUser">updateUser</a></code></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</nav>
|
||
</main>
|
||
<footer id="footer">
|
||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||
</footer>
|
||
</body>
|
||
</html> |