Files
SemesterapparatsManager/documentation/database.html
2024-05-17 08:35:37 +02:00

3071 lines
131 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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(&#34;config.yaml&#34;)
logger = MyLogger(__name__)
class Database:
&#34;&#34;&#34;
Initialize the database and create the tables if they do not exist.
&#34;&#34;&#34;
def __init__(self, db_path: str = None):
&#34;&#34;&#34;
Default constructor for the database class
Args:
db_path (str, optional): Optional Path for testing / specific purposes. Defaults to None.
&#34;&#34;&#34;
if db_path is None:
self.db_path = config.database.path + config.database.name
self.db_path = self.db_path.replace(&#34;~&#34;, str(Path.home()))
else:
self.db_path = db_path
if self.get_db_contents() is None:
logger.log_critical(&#34;Database does not exist, creating tables&#34;)
self.create_tables()
def get_db_contents(self)-&gt;Union[List[Tuple], None]:
&#34;&#34;&#34;
Get the contents of the
Returns:
Union[List[Tuple], None]: _description_
&#34;&#34;&#34;
try:
with sql.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute(&#34;SELECT * FROM sqlite_master WHERE type=&#39;table&#39;&#34;)
return cursor.fetchall()
except sql.OperationalError:
return None
def connect(self)-&gt;sql.Connection:
&#34;&#34;&#34;
Connect to the database
Returns:
sql.Connection: The active connection to the database
&#34;&#34;&#34;
return sql.connect(self.db_path)
def close_connection(self, conn: sql.Connection):
&#34;&#34;&#34;
closes the connection to the database
Args:
----
- conn (sql.Connection): the connection to be closed
&#34;&#34;&#34;
conn.close()
def create_tables(self):
&#34;&#34;&#34;
Create the tables in the database
&#34;&#34;&#34;
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) -&gt; None:
&#34;&#34;&#34;
Insert sent data into the database
Args:
query (str): The query to be executed
params (Tuple): the parameters to be inserted into the database
&#34;&#34;&#34;
conn = self.connect()
cursor = conn.cursor()
logger.log_info(f&#34;Inserting {params} into database with query {query}&#34;)
cursor.execute(query, params)
conn.commit()
self.close_connection(conn)
def query_db(self, query: str, args: Tuple = (), one: bool = False)-&gt;Union[Tuple, List[Tuple]]:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
conn = self.connect()
cursor = conn.cursor()
logger.log_info(f&#34;Querying database with query {query}, args: {args}&#34;)
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:str, prof_id:str):
&#34;&#34;&#34;
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.
&#34;&#34;&#34;
conn = self.connect()
cursor = conn.cursor()
t_query = (
f&#34;SELECT bookdata FROM media WHERE app_id={app_id} AND prof_id={prof_id}&#34;
)
# print(t_query)
result = cursor.execute(t_query).fetchall()
result = [load_pickle(i[0]) for i in result]
if bookdata in result:
print(&#34;Bookdata already in database&#34;)
# check if the book was deleted in the apparat
query = (
&#34;SELECT deleted FROM media WHERE app_id=? AND prof_id=? AND bookdata=?&#34;
)
params = (app_id, prof_id, dump_pickle(bookdata))
result = cursor.execute(query, params).fetchone()
if result[0] == 1:
print(&#34;Book was deleted, updating bookdata&#34;)
query = &#34;UPDATE media SET deleted=0 WHERE app_id=? AND prof_id=? AND bookdata=?&#34;
params = (app_id, prof_id, dump_pickle(bookdata))
cursor.execute(query, params)
conn.commit()
return
query = (
&#34;INSERT INTO media (bookdata, app_id, prof_id,deleted) VALUES (?, ?, ?,?)&#34;
)
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:str, prof_id:str,signature:str)-&gt;int:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
result = self.query_db(&#34;SELECT bookdata, id FROM media WHERE app_id=? AND prof_id=?&#34;, (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:str, prof_id:str,signature:str)-&gt;BookData:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
result = self.query_db(&#34;SELECT bookdata FROM media WHERE app_id=? AND prof_id=?&#34;, (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)-&gt;int:
&#34;&#34;&#34;
Get the last book id in the database
Returns:
int: ID of the last book in the database
&#34;&#34;&#34;
return self.query_db(&#34;SELECT id FROM media ORDER BY id DESC&#34;, one=True)[0]
def searchBook(self, data:dict[str, str])-&gt;list[tuple[BookData, int]]:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
rdata = self.query_db(&#34;SELECT * FROM media WHERE deleted=0&#34;)
#ic(rdata, len(rdata))
mode = 0
if len(data)== 1:
if &#34;signature&#34; in data.keys():
mode = 1
elif &#34;title&#34; 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[&#34;signature&#34;] in bookdata.signature:
ret.append((bookdata,app_id,prof_id))
elif mode == 2:
if data[&#34;title&#34;] in bookdata.title:
ret.append((bookdata,app_id,prof_id))
elif mode == 3:
if data[&#34;signature&#34;] in bookdata.signature and data[&#34;title&#34;] in bookdata.title:
ret.append((bookdata,app_id,prof_id))
#ic(ret)
return ret
def setAvailability(self, book_id:str, available:str):
&#34;&#34;&#34;
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
&#34;&#34;&#34;
self.query_db(&#34;UPDATE media SET available=? WHERE id=?&#34;, (available,book_id))
def getBookId(self, bookdata:BookData, app_id, prof_id)-&gt;int:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
result = self.query_db(&#34;SELECT id FROM media WHERE bookdata=? AND app_id=? AND prof_id=?&#34;, (dump_pickle(bookdata),app_id,prof_id), one=True)
return result[0]
def getBook(self,book_id:int)-&gt;BookData:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
return load_pickle(self.query_db(&#34;SELECT bookdata FROM media WHERE id=?&#34;, (book_id,), one=True)[0])
def getBooks(self, app_id, prof_id, deleted=0)-&gt;list[dict[int, BookData, int]]:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
qdata = self.query_db(f&#34;SELECT id,bookdata,available FROM media WHERE (app_id={app_id} AND prof_id={prof_id}) AND (deleted={deleted if deleted == 0 else &#39;1 OR deleted=0&#39;})&#34;)
ret_result = []
for result_a in qdata:
data = {&#34;id&#34;: int, &#34;bookdata&#34;: BookData, &#34;available&#34;: int}
data[&#34;id&#34;] = result_a[0]
data[&#34;bookdata&#34;] = load_pickle(result_a[1])
data[&#34;available&#34;] = result_a[2]
ret_result.append(data)
return ret_result
def updateBookdata(self, book_id, bookdata:BookData):
&#34;&#34;&#34;
Update the bookdata in the database
Args:
book_id (str): The id of the book
bookdata (BookData): The new metadata of the book
&#34;&#34;&#34;
self.query_db(&#34;UPDATE media SET bookdata=? WHERE id=?&#34;, (dump_pickle(bookdata),book_id))
def deleteBook(self, book_id):
&#34;&#34;&#34;
Delete a book from the database
Args:
book_id (str): ID of the book
&#34;&#34;&#34;
self.query_db(&#34;UPDATE media SET deleted=1 WHERE id=?&#34;, (book_id,))
# File Interactions
def getBlob(self, filename, app_id):
&#34;&#34;&#34;
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
&#34;&#34;&#34;
return self.query_db(&#34;SELECT fileblob FROM files WHERE filename=? AND app_id=?&#34;, (filename,app_id), one=True)[0]
def insertFile(self, file: list[dict], app_id: int, prof_id):
for f in file:
filename = f[&#34;name&#34;]
path = f[&#34;path&#34;]
filetyp = f[&#34;type&#34;]
if path == &#34;Database&#34;:
continue
blob = create_blob(path)
query = &#34;INSERT OR IGNORE INTO files (filename, fileblob, app_id, filetyp,prof_id) VALUES (?, ?, ?, ?,?)&#34;
self.query_db(query, (filename, blob, app_id, filetyp,prof_id))
def recreateFile(self, filename, app_id,filetype):
blob = self.getBlob(filename, app_id)
tempdir = config.database.tempdir
tempdir = tempdir.replace(&#34;~&#34;, 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=&#34;wb&#34;, suffix=f&#34;.{filetype}&#34;
)
file.write(blob)
print(&#34;file created&#34;)
return file.name
def getFiles(self, app_id:int, prof_id:int)-&gt;list[tuple]:
return self.query_db(&#34;SELECT filename, filetyp FROM files WHERE app_id=? AND prof_id=?&#34;, (app_id,prof_id))
def getSemersters(self):
data = self.query_db(&#34;SELECT DISTINCT erstellsemester FROM semesterapparat&#34;)
return [i[0] for i in data]
def getSubjects(self):
return self.query_db(&#34;SELECT * FROM subjects&#34;)
# Messages
def addMessage(self, message:dict,user, appnr):
def __getUserId(user):
return self.query_db(&#34;SELECT id FROM user WHERE username=?&#34;, (user,), one=True)[0]
user_id = __getUserId(user)
self.query_db(&#34;INSERT INTO messages (message, user_id, remind_at,appnr) VALUES (?,?,?,?)&#34;, (message[&#34;message&#34;],user_id,message[&#34;remind_at&#34;],appnr))
def getMessages(self, date:str):
def __get_user_name(user_id):
return self.query_db(&#34;SELECT username FROM user WHERE id=?&#34;, (user_id,), one=True)[0]
messages = self.query_db(&#34;SELECT * FROM messages WHERE remind_at=?&#34;, (date,))
ret = [
{
&#34;message&#34;: i[2],
&#34;user&#34;: __get_user_name(i[4]),
&#34;appnr&#34;: i[5],
&#34;id&#34;: i[0]
}
for i in messages
]
return ret
def deleteMessage(self, message_id):
self.query_db(&#34;DELETE FROM messages WHERE id=?&#34;, (message_id,))
# Prof data
def getProfNameById(self, prof_id:int,add_title:bool=False):
prof = self.query_db(&#34;SELECT fullname FROM prof WHERE id=?&#34;, (prof_id,), one=True)
if add_title:
return f&#34;{self.getTitleById(prof_id)}{prof[0]}&#34;
else:
return prof[0]
def getTitleById(self, prof_id:int):
title = self.query_db(&#34;SELECT titel FROM prof WHERE id=?&#34;, (prof_id,), one=True)[0]
return f&#34;{title} &#34; if title is not None else &#34;&#34;
def getProfByName(self, prof_name:str):
return self.query_db(&#34;SELECT * FROM prof WHERE fullname=?&#34;, (prof_name,), one=True)
def getProfId(self, prof_name:str):
&#34;&#34;&#34;
getProfId _summary_
:param prof_name: _description_
:type prof_name: str
:return: _description_
:rtype: _type_
&#34;&#34;&#34;
data = self.getProfByName(prof_name.replace(&#34;,&#34;, &#34;&#34;))
if data is None:
return None
else:
return data[0]
def getSpecificProfData(self, prof_id:int, fields:List[str]):
&#34;&#34;&#34;
getSpecificProfData _summary_
Args:
----
- prof_id (int): _description_
- fields (List[str]): _description_
Returns:
-------
- _type_: _description_
&#34;&#34;&#34;
query = &#34;SELECT &#34;
for field in fields:
query += f&#34;{field},&#34;
query = query[:-1]
query += &#34; FROM prof WHERE id=?&#34;
return self.query_db(query, (prof_id,), one=True)[0]
def getProfData(self, profname:str):
data = self.query_db(&#34;SELECT mail, telnr, titel FROM prof WHERE fullname=?&#34;, (profname.replace(&#34;,&#34;,&#34;&#34;),), one=True)
return data
def createProf(self, prof_details:dict):
prof_title = prof_details[&#34;prof_title&#34;]
prof_fname = prof_details[&#34;profname&#34;].split(&#34;,&#34;)[1]
prof_fname = prof_fname.strip()
prof_lname = prof_details[&#34;profname&#34;].split(&#34;,&#34;)[0]
prof_lname = prof_lname.strip()
prof_fullname = prof_details[&#34;profname&#34;].replace(&#34;,&#34;, &#34;&#34;)
prof_mail = prof_details[&#34;prof_mail&#34;]
prof_tel = prof_details[&#34;prof_tel&#34;]
params = (prof_title, prof_fname, prof_lname, prof_mail, prof_tel, prof_fullname)
query = &#34;INSERT OR IGNORE INTO prof (titel, fname, lname, mail, telnr, fullname) VALUES (?, ?, ?, ?, ?, ?)&#34;
self.insertInto(query=query, params=params)
def getProfs(self):
return self.query_db(&#34;SELECT * FROM prof&#34;)
# Apparat
def getAllAparats(self,deleted=0):
return self.query_db(&#34;SELECT * FROM semesterapparat WHERE deletion_status=?&#34;, (deleted,))
def getApparatData(self, appnr, appname)-&gt;ApparatData:
result = self.query_db(&#34;SELECT * FROM semesterapparat WHERE appnr=? AND name=?&#34;, (appnr,appname), one=True)
if result is None:
raise NoResultError(&#34;No result found&#34;)
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)-&gt;List[int]:
&#34;&#34;&#34;
getUnavailableApparatNumbers returns a list of all currently used ApparatNumbers
Returns:
-------
- number(List[int]): a list of all currently used apparat numbers
&#34;&#34;&#34;
numbers = self.query_db(&#34;SELECT appnr FROM semesterapparat WHERE deletion_status=0&#34;)
numbers = [i[0] for i in numbers]
logger.log_info(f&#34;Currently used apparat numbers: {numbers}&#34;)
return numbers
def setNewSemesterDate(self, appnr, newDate, dauerapp=False):
date = datetime.datetime.strptime(newDate, &#34;%d.%m.%Y&#34;).strftime(&#34;%Y-%m-%d&#34;)
if dauerapp:
self.query_db(&#34;UPDATE semesterapparat SET verlängerung_bis=?, dauerapp=? WHERE appnr=?&#34;, (date,dauerapp,appnr))
else:
self.query_db(&#34;UPDATE semesterapparat SET endsemester=? WHERE appnr=?&#34;, (date,appnr))
def getApparatId(self, apparat_name):
data = self.query_db(&#34;SELECT appnr FROM semesterapparat WHERE name=?&#34;, (apparat_name,), one=True)
if data is None:
return None
else:
return data[0]
def createApparat(self, apparat:ApparatData)-&gt;Optional[AppPresentError]|int:
prof_id = self.getProfId(apparat.profname)
app_id = self.getApparatId(apparat.appname)
if app_id:
return AppPresentError(app_id)
self.createProf(apparat.get_prof_details())
prof_id = self.getProfId(apparat.profname)
#ic(prof_id)
query = f&#34;INSERT OR IGNORE INTO semesterapparat (appnr, name, erstellsemester, dauer, prof_id, fach,deletion_status,konto) VALUES (&#39;{apparat.appnr}&#39;, &#39;{apparat.appname}&#39;, &#39;{apparat.semester}&#39;, &#39;{apparat.dauerapp}&#39;, {prof_id}, &#39;{apparat.app_fach}&#39;, &#39;{0}&#39;, &#39;{SEMAP_MEDIA_ACCOUNTS[apparat.appnr]}&#39;)&#34;
logger.log_info(query)
self.query_db(query)
return self.getApparatId(apparat.appname)
def getApparatsByProf(self, prof_id:int)-&gt;list[tuple]:
return self.query_db(&#34;SELECT * FROM semesterapparat WHERE prof_id=?&#34;, (prof_id,))
def getApparatsBySemester(self, semester:str)-&gt;dict:
data = self.query_db(&#34;SELECT name, prof_id FROM semesterapparat WHERE erstellsemester=?&#34;, (semester,))
conn = self.connect()
cursor = conn.cursor()
c_tmp = []
for i in data:
c_tmp.append((i[0], self.getProfNameById(i[1])))
query = (
f&#34;SELECT name,prof_id FROM semesterapparat WHERE deleted_date=&#39;{semester}&#39;&#34;
)
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 {&#34;created&#34;: c_ret, &#34;deleted&#34;: d_ret}
def getApparatCountBySemester(self)-&gt;tuple[list[str],list[int]]:
conn = self.connect()
cursor = conn.cursor()
semesters = self.getSemersters()
created = []
deleted = []
for semester in semesters:
query = f&#34;SELECT COUNT(*) FROM semesterapparat WHERE erstellsemester=&#39;{semester}&#39;&#34;
result = cursor.execute(query).fetchone()
created.append(result[0])
query = f&#34;SELECT COUNT(*) FROM semesterapparat WHERE deletion_status=1 AND deleted_date=&#39;{semester}&#39;&#34;
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, appnr, semester):
self.query_db(&#34;UPDATE semesterapparat SET deletion_status=1, deleted_date=? WHERE appnr=?&#34;, (semester,appnr))
def isEternal(self, id):
return self.query_db(&#34;SELECT dauer FROM semesterapparat WHERE appnr=?&#34;, (id,), one=True)
def getApparatName(self, app_id, prof_id):
return self.query_db(&#34;SELECT name FROM semesterapparat WHERE appnr=? AND prof_id=?&#34;, (app_id,prof_id), one=True)[0]
def updateApparat(self, apparat_data:ApparatData):
query = f&#34;UPDATE semesterapparat SET name = ?, fach = ?, dauer = ?, prof_id = ? WHERE appnr = ?&#34;
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):
return True if self.query_db(&#34;SELECT appnr FROM semesterapparat WHERE name=?&#34;, (apparat_name,), one=True) else False
def checkApparatExistsById(self, apparat_id):
return True if self.query_db(&#34;SELECT appnr FROM semesterapparat WHERE appnr=?&#34;, (apparat_id,), one=True) else False
# Statistics
def statistic_request(self, **kwargs: Any):
def __query(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 &#34;deletable&#34; in kwargs.keys():
query = f&#34;SELECT * FROM semesterapparat WHERE deletion_status=0 AND dauer=0 AND (erstellsemester!=&#39;{kwargs[&#39;deletesemester&#39;]}&#39; OR verlängerung_bis!=&#39;{kwargs[&#39;deletesemester&#39;]}&#39;)&#34;
return __query(query)
if &#34;dauer&#34; in kwargs.keys():
kwargs[&#34;dauer&#34;] = kwargs[&#34;dauer&#34;].replace(&#34;Ja&#34;, &#34;1&#34;).replace(&#34;Nein&#34;, &#34;0&#34;)
query = &#34;SELECT * FROM semesterapparat WHERE &#34;
for key, value in kwargs.items() if kwargs.items() is not None else {}:
print(key, value)
query += f&#34;{key}=&#39;{value}&#39; AND &#34;
print(query)
# remove deletesemester part from normal query, as this will be added to the database upon deleting the apparat
if &#34;deletesemester&#34; in kwargs.keys():
query = query.replace(
f&#34;deletesemester=&#39;{kwargs[&#39;deletesemester&#39;]}&#39; AND &#34;, &#34;&#34;
)
if &#34;endsemester&#34; in kwargs.keys():
if &#34;erstellsemester&#34; in kwargs.keys():
query = query.replace(f&#34;endsemester=&#39;{kwargs[&#39;endsemester&#39;]}&#39; AND &#34;, &#34;&#34;)
query = query.replace(
f&#34;erstellsemester=&#39;{kwargs[&#39;erstellsemester&#39;]} AND &#34;, &#34;xyz&#34;
)
else:
query = query.replace(
f&#34;endsemester=&#39;{kwargs[&#39;endsemester&#39;]}&#39; AND &#34;, &#34;xyz&#34;
)
print(&#34;replaced&#34;)
query = query.replace(
&#34;xyz&#34;,
f&#34;(erstellsemester=&#39;{kwargs[&#39;endsemester&#39;]}&#39; OR verlängerung_bis=&#39;{kwargs[&#39;endsemester&#39;]}&#39;) AND &#34;,
)
# remove all x=&#34;&#34; parts from the query where x is a key in kwargs
query = query[:-5]
print(query)
return __query(query)
# Admin data
def getUser(self):
return self.query_db(&#34;SELECT * FROM user&#34;, one=True)
def getUsers(self):
return self.query_db(&#34;SELECT * FROM user&#34;)
def login(self, user, hashed_password):
salt = self.query_db(&#34;SELECT salt FROM user WHERE username=?&#34;, (user,), one=True)[0]
if salt is None:
return False
hashed_password = salt + hashed_password
password = self.query_db(&#34;SELECT password FROM user WHERE username=?&#34;, (user,), one=True)[0]
if password == hashed_password:
return True
else:
return False
def changePassword(self, user, new_password):
salt = self.query_db(&#34;SELECT salt FROM user WHERE username=?&#34;, (user,), one=True)[0]
new_password = salt + new_password
self.query_db(&#34;UPDATE user SET password=? WHERE username=?&#34;, (new_password,user))
def getRole(self, user):
return self.query_db(&#34;SELECT role FROM user WHERE username=?&#34;, (user,), one=True)[0]
def getRoles(self):
return self.query_db(&#34;SELECT role FROM user&#34;)
def checkUsername(self, user):
data = self.query_db(&#34;SELECT username FROM user WHERE username=?&#34;, (user,), one=True)
return True if data is not None else False
def createUser(self, user, password, role, salt):
&#34;&#34;&#34;Create a user based on passed data.
Args:
----
- username (str): Username to be used
- password (str): the salted password
- role (str): Role of the user
- salt (str): a random salt for the user
&#34;&#34;&#34;
self.query_db(&#34;INSERT OR IGNORE INTO user (username, password, role, salt) VALUES (?,?,?,?)&#34;, (user,password,role,salt))
def deleteUser(self, user):
self.query_db(&#34;DELETE FROM user WHERE username=?&#34;, (user,))
def updateUser(self, username, data:dict[str, str]):
conn = self.connect()
cursor = conn.cursor()
query = &#34;UPDATE user SET &#34;
for key,value in data.items():
if key == &#34;username&#34;:
continue
query += f&#34;{key}=&#39;{value}&#39;,&#34;
query = query[:-1]
query += &#34; WHERE username=?&#34;
params = (username,)
cursor.execute(query, params)
conn.commit()
self.close_connection(conn)
def getFacultyMember(self, name:str):
return self.query_db(&#34;SELECT titel, fname,lname,mail,telnr,fullname FROM prof WHERE fullname=?&#34;, (name,), one=True)
def updateFacultyMember(self, data, oldlname, oldfname):
placeholders = &#34;, &#34;.join([f&#34;{i}=:{i} &#34; for i in data.keys()])
query = f&#34;UPDATE prof SET {placeholders} WHERE lname = :oldlname AND fname = :oldfname&#34;
data[&#34;oldlname&#34;] = oldlname
data[&#34;oldfname&#34;] = oldfname
self.query_db(query, data)
def getFacultyMembers(self):
return self.query_db(&#34;SELECT titel, fname,lname,mail,telnr,fullname FROM prof&#34;)</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> :&ensp;<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:
&#34;&#34;&#34;
Initialize the database and create the tables if they do not exist.
&#34;&#34;&#34;
def __init__(self, db_path: str = None):
&#34;&#34;&#34;
Default constructor for the database class
Args:
db_path (str, optional): Optional Path for testing / specific purposes. Defaults to None.
&#34;&#34;&#34;
if db_path is None:
self.db_path = config.database.path + config.database.name
self.db_path = self.db_path.replace(&#34;~&#34;, str(Path.home()))
else:
self.db_path = db_path
if self.get_db_contents() is None:
logger.log_critical(&#34;Database does not exist, creating tables&#34;)
self.create_tables()
def get_db_contents(self)-&gt;Union[List[Tuple], None]:
&#34;&#34;&#34;
Get the contents of the
Returns:
Union[List[Tuple], None]: _description_
&#34;&#34;&#34;
try:
with sql.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute(&#34;SELECT * FROM sqlite_master WHERE type=&#39;table&#39;&#34;)
return cursor.fetchall()
except sql.OperationalError:
return None
def connect(self)-&gt;sql.Connection:
&#34;&#34;&#34;
Connect to the database
Returns:
sql.Connection: The active connection to the database
&#34;&#34;&#34;
return sql.connect(self.db_path)
def close_connection(self, conn: sql.Connection):
&#34;&#34;&#34;
closes the connection to the database
Args:
----
- conn (sql.Connection): the connection to be closed
&#34;&#34;&#34;
conn.close()
def create_tables(self):
&#34;&#34;&#34;
Create the tables in the database
&#34;&#34;&#34;
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) -&gt; None:
&#34;&#34;&#34;
Insert sent data into the database
Args:
query (str): The query to be executed
params (Tuple): the parameters to be inserted into the database
&#34;&#34;&#34;
conn = self.connect()
cursor = conn.cursor()
logger.log_info(f&#34;Inserting {params} into database with query {query}&#34;)
cursor.execute(query, params)
conn.commit()
self.close_connection(conn)
def query_db(self, query: str, args: Tuple = (), one: bool = False)-&gt;Union[Tuple, List[Tuple]]:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
conn = self.connect()
cursor = conn.cursor()
logger.log_info(f&#34;Querying database with query {query}, args: {args}&#34;)
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:str, prof_id:str):
&#34;&#34;&#34;
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.
&#34;&#34;&#34;
conn = self.connect()
cursor = conn.cursor()
t_query = (
f&#34;SELECT bookdata FROM media WHERE app_id={app_id} AND prof_id={prof_id}&#34;
)
# print(t_query)
result = cursor.execute(t_query).fetchall()
result = [load_pickle(i[0]) for i in result]
if bookdata in result:
print(&#34;Bookdata already in database&#34;)
# check if the book was deleted in the apparat
query = (
&#34;SELECT deleted FROM media WHERE app_id=? AND prof_id=? AND bookdata=?&#34;
)
params = (app_id, prof_id, dump_pickle(bookdata))
result = cursor.execute(query, params).fetchone()
if result[0] == 1:
print(&#34;Book was deleted, updating bookdata&#34;)
query = &#34;UPDATE media SET deleted=0 WHERE app_id=? AND prof_id=? AND bookdata=?&#34;
params = (app_id, prof_id, dump_pickle(bookdata))
cursor.execute(query, params)
conn.commit()
return
query = (
&#34;INSERT INTO media (bookdata, app_id, prof_id,deleted) VALUES (?, ?, ?,?)&#34;
)
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:str, prof_id:str,signature:str)-&gt;int:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
result = self.query_db(&#34;SELECT bookdata, id FROM media WHERE app_id=? AND prof_id=?&#34;, (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:str, prof_id:str,signature:str)-&gt;BookData:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
result = self.query_db(&#34;SELECT bookdata FROM media WHERE app_id=? AND prof_id=?&#34;, (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)-&gt;int:
&#34;&#34;&#34;
Get the last book id in the database
Returns:
int: ID of the last book in the database
&#34;&#34;&#34;
return self.query_db(&#34;SELECT id FROM media ORDER BY id DESC&#34;, one=True)[0]
def searchBook(self, data:dict[str, str])-&gt;list[tuple[BookData, int]]:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
rdata = self.query_db(&#34;SELECT * FROM media WHERE deleted=0&#34;)
#ic(rdata, len(rdata))
mode = 0
if len(data)== 1:
if &#34;signature&#34; in data.keys():
mode = 1
elif &#34;title&#34; 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[&#34;signature&#34;] in bookdata.signature:
ret.append((bookdata,app_id,prof_id))
elif mode == 2:
if data[&#34;title&#34;] in bookdata.title:
ret.append((bookdata,app_id,prof_id))
elif mode == 3:
if data[&#34;signature&#34;] in bookdata.signature and data[&#34;title&#34;] in bookdata.title:
ret.append((bookdata,app_id,prof_id))
#ic(ret)
return ret
def setAvailability(self, book_id:str, available:str):
&#34;&#34;&#34;
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
&#34;&#34;&#34;
self.query_db(&#34;UPDATE media SET available=? WHERE id=?&#34;, (available,book_id))
def getBookId(self, bookdata:BookData, app_id, prof_id)-&gt;int:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
result = self.query_db(&#34;SELECT id FROM media WHERE bookdata=? AND app_id=? AND prof_id=?&#34;, (dump_pickle(bookdata),app_id,prof_id), one=True)
return result[0]
def getBook(self,book_id:int)-&gt;BookData:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
return load_pickle(self.query_db(&#34;SELECT bookdata FROM media WHERE id=?&#34;, (book_id,), one=True)[0])
def getBooks(self, app_id, prof_id, deleted=0)-&gt;list[dict[int, BookData, int]]:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
qdata = self.query_db(f&#34;SELECT id,bookdata,available FROM media WHERE (app_id={app_id} AND prof_id={prof_id}) AND (deleted={deleted if deleted == 0 else &#39;1 OR deleted=0&#39;})&#34;)
ret_result = []
for result_a in qdata:
data = {&#34;id&#34;: int, &#34;bookdata&#34;: BookData, &#34;available&#34;: int}
data[&#34;id&#34;] = result_a[0]
data[&#34;bookdata&#34;] = load_pickle(result_a[1])
data[&#34;available&#34;] = result_a[2]
ret_result.append(data)
return ret_result
def updateBookdata(self, book_id, bookdata:BookData):
&#34;&#34;&#34;
Update the bookdata in the database
Args:
book_id (str): The id of the book
bookdata (BookData): The new metadata of the book
&#34;&#34;&#34;
self.query_db(&#34;UPDATE media SET bookdata=? WHERE id=?&#34;, (dump_pickle(bookdata),book_id))
def deleteBook(self, book_id):
&#34;&#34;&#34;
Delete a book from the database
Args:
book_id (str): ID of the book
&#34;&#34;&#34;
self.query_db(&#34;UPDATE media SET deleted=1 WHERE id=?&#34;, (book_id,))
# File Interactions
def getBlob(self, filename, app_id):
&#34;&#34;&#34;
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
&#34;&#34;&#34;
return self.query_db(&#34;SELECT fileblob FROM files WHERE filename=? AND app_id=?&#34;, (filename,app_id), one=True)[0]
def insertFile(self, file: list[dict], app_id: int, prof_id):
for f in file:
filename = f[&#34;name&#34;]
path = f[&#34;path&#34;]
filetyp = f[&#34;type&#34;]
if path == &#34;Database&#34;:
continue
blob = create_blob(path)
query = &#34;INSERT OR IGNORE INTO files (filename, fileblob, app_id, filetyp,prof_id) VALUES (?, ?, ?, ?,?)&#34;
self.query_db(query, (filename, blob, app_id, filetyp,prof_id))
def recreateFile(self, filename, app_id,filetype):
blob = self.getBlob(filename, app_id)
tempdir = config.database.tempdir
tempdir = tempdir.replace(&#34;~&#34;, 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=&#34;wb&#34;, suffix=f&#34;.{filetype}&#34;
)
file.write(blob)
print(&#34;file created&#34;)
return file.name
def getFiles(self, app_id:int, prof_id:int)-&gt;list[tuple]:
return self.query_db(&#34;SELECT filename, filetyp FROM files WHERE app_id=? AND prof_id=?&#34;, (app_id,prof_id))
def getSemersters(self):
data = self.query_db(&#34;SELECT DISTINCT erstellsemester FROM semesterapparat&#34;)
return [i[0] for i in data]
def getSubjects(self):
return self.query_db(&#34;SELECT * FROM subjects&#34;)
# Messages
def addMessage(self, message:dict,user, appnr):
def __getUserId(user):
return self.query_db(&#34;SELECT id FROM user WHERE username=?&#34;, (user,), one=True)[0]
user_id = __getUserId(user)
self.query_db(&#34;INSERT INTO messages (message, user_id, remind_at,appnr) VALUES (?,?,?,?)&#34;, (message[&#34;message&#34;],user_id,message[&#34;remind_at&#34;],appnr))
def getMessages(self, date:str):
def __get_user_name(user_id):
return self.query_db(&#34;SELECT username FROM user WHERE id=?&#34;, (user_id,), one=True)[0]
messages = self.query_db(&#34;SELECT * FROM messages WHERE remind_at=?&#34;, (date,))
ret = [
{
&#34;message&#34;: i[2],
&#34;user&#34;: __get_user_name(i[4]),
&#34;appnr&#34;: i[5],
&#34;id&#34;: i[0]
}
for i in messages
]
return ret
def deleteMessage(self, message_id):
self.query_db(&#34;DELETE FROM messages WHERE id=?&#34;, (message_id,))
# Prof data
def getProfNameById(self, prof_id:int,add_title:bool=False):
prof = self.query_db(&#34;SELECT fullname FROM prof WHERE id=?&#34;, (prof_id,), one=True)
if add_title:
return f&#34;{self.getTitleById(prof_id)}{prof[0]}&#34;
else:
return prof[0]
def getTitleById(self, prof_id:int):
title = self.query_db(&#34;SELECT titel FROM prof WHERE id=?&#34;, (prof_id,), one=True)[0]
return f&#34;{title} &#34; if title is not None else &#34;&#34;
def getProfByName(self, prof_name:str):
return self.query_db(&#34;SELECT * FROM prof WHERE fullname=?&#34;, (prof_name,), one=True)
def getProfId(self, prof_name:str):
&#34;&#34;&#34;
getProfId _summary_
:param prof_name: _description_
:type prof_name: str
:return: _description_
:rtype: _type_
&#34;&#34;&#34;
data = self.getProfByName(prof_name.replace(&#34;,&#34;, &#34;&#34;))
if data is None:
return None
else:
return data[0]
def getSpecificProfData(self, prof_id:int, fields:List[str]):
&#34;&#34;&#34;
getSpecificProfData _summary_
Args:
----
- prof_id (int): _description_
- fields (List[str]): _description_
Returns:
-------
- _type_: _description_
&#34;&#34;&#34;
query = &#34;SELECT &#34;
for field in fields:
query += f&#34;{field},&#34;
query = query[:-1]
query += &#34; FROM prof WHERE id=?&#34;
return self.query_db(query, (prof_id,), one=True)[0]
def getProfData(self, profname:str):
data = self.query_db(&#34;SELECT mail, telnr, titel FROM prof WHERE fullname=?&#34;, (profname.replace(&#34;,&#34;,&#34;&#34;),), one=True)
return data
def createProf(self, prof_details:dict):
prof_title = prof_details[&#34;prof_title&#34;]
prof_fname = prof_details[&#34;profname&#34;].split(&#34;,&#34;)[1]
prof_fname = prof_fname.strip()
prof_lname = prof_details[&#34;profname&#34;].split(&#34;,&#34;)[0]
prof_lname = prof_lname.strip()
prof_fullname = prof_details[&#34;profname&#34;].replace(&#34;,&#34;, &#34;&#34;)
prof_mail = prof_details[&#34;prof_mail&#34;]
prof_tel = prof_details[&#34;prof_tel&#34;]
params = (prof_title, prof_fname, prof_lname, prof_mail, prof_tel, prof_fullname)
query = &#34;INSERT OR IGNORE INTO prof (titel, fname, lname, mail, telnr, fullname) VALUES (?, ?, ?, ?, ?, ?)&#34;
self.insertInto(query=query, params=params)
def getProfs(self):
return self.query_db(&#34;SELECT * FROM prof&#34;)
# Apparat
def getAllAparats(self,deleted=0):
return self.query_db(&#34;SELECT * FROM semesterapparat WHERE deletion_status=?&#34;, (deleted,))
def getApparatData(self, appnr, appname)-&gt;ApparatData:
result = self.query_db(&#34;SELECT * FROM semesterapparat WHERE appnr=? AND name=?&#34;, (appnr,appname), one=True)
if result is None:
raise NoResultError(&#34;No result found&#34;)
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)-&gt;List[int]:
&#34;&#34;&#34;
getUnavailableApparatNumbers returns a list of all currently used ApparatNumbers
Returns:
-------
- number(List[int]): a list of all currently used apparat numbers
&#34;&#34;&#34;
numbers = self.query_db(&#34;SELECT appnr FROM semesterapparat WHERE deletion_status=0&#34;)
numbers = [i[0] for i in numbers]
logger.log_info(f&#34;Currently used apparat numbers: {numbers}&#34;)
return numbers
def setNewSemesterDate(self, appnr, newDate, dauerapp=False):
date = datetime.datetime.strptime(newDate, &#34;%d.%m.%Y&#34;).strftime(&#34;%Y-%m-%d&#34;)
if dauerapp:
self.query_db(&#34;UPDATE semesterapparat SET verlängerung_bis=?, dauerapp=? WHERE appnr=?&#34;, (date,dauerapp,appnr))
else:
self.query_db(&#34;UPDATE semesterapparat SET endsemester=? WHERE appnr=?&#34;, (date,appnr))
def getApparatId(self, apparat_name):
data = self.query_db(&#34;SELECT appnr FROM semesterapparat WHERE name=?&#34;, (apparat_name,), one=True)
if data is None:
return None
else:
return data[0]
def createApparat(self, apparat:ApparatData)-&gt;Optional[AppPresentError]|int:
prof_id = self.getProfId(apparat.profname)
app_id = self.getApparatId(apparat.appname)
if app_id:
return AppPresentError(app_id)
self.createProf(apparat.get_prof_details())
prof_id = self.getProfId(apparat.profname)
#ic(prof_id)
query = f&#34;INSERT OR IGNORE INTO semesterapparat (appnr, name, erstellsemester, dauer, prof_id, fach,deletion_status,konto) VALUES (&#39;{apparat.appnr}&#39;, &#39;{apparat.appname}&#39;, &#39;{apparat.semester}&#39;, &#39;{apparat.dauerapp}&#39;, {prof_id}, &#39;{apparat.app_fach}&#39;, &#39;{0}&#39;, &#39;{SEMAP_MEDIA_ACCOUNTS[apparat.appnr]}&#39;)&#34;
logger.log_info(query)
self.query_db(query)
return self.getApparatId(apparat.appname)
def getApparatsByProf(self, prof_id:int)-&gt;list[tuple]:
return self.query_db(&#34;SELECT * FROM semesterapparat WHERE prof_id=?&#34;, (prof_id,))
def getApparatsBySemester(self, semester:str)-&gt;dict:
data = self.query_db(&#34;SELECT name, prof_id FROM semesterapparat WHERE erstellsemester=?&#34;, (semester,))
conn = self.connect()
cursor = conn.cursor()
c_tmp = []
for i in data:
c_tmp.append((i[0], self.getProfNameById(i[1])))
query = (
f&#34;SELECT name,prof_id FROM semesterapparat WHERE deleted_date=&#39;{semester}&#39;&#34;
)
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 {&#34;created&#34;: c_ret, &#34;deleted&#34;: d_ret}
def getApparatCountBySemester(self)-&gt;tuple[list[str],list[int]]:
conn = self.connect()
cursor = conn.cursor()
semesters = self.getSemersters()
created = []
deleted = []
for semester in semesters:
query = f&#34;SELECT COUNT(*) FROM semesterapparat WHERE erstellsemester=&#39;{semester}&#39;&#34;
result = cursor.execute(query).fetchone()
created.append(result[0])
query = f&#34;SELECT COUNT(*) FROM semesterapparat WHERE deletion_status=1 AND deleted_date=&#39;{semester}&#39;&#34;
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, appnr, semester):
self.query_db(&#34;UPDATE semesterapparat SET deletion_status=1, deleted_date=? WHERE appnr=?&#34;, (semester,appnr))
def isEternal(self, id):
return self.query_db(&#34;SELECT dauer FROM semesterapparat WHERE appnr=?&#34;, (id,), one=True)
def getApparatName(self, app_id, prof_id):
return self.query_db(&#34;SELECT name FROM semesterapparat WHERE appnr=? AND prof_id=?&#34;, (app_id,prof_id), one=True)[0]
def updateApparat(self, apparat_data:ApparatData):
query = f&#34;UPDATE semesterapparat SET name = ?, fach = ?, dauer = ?, prof_id = ? WHERE appnr = ?&#34;
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):
return True if self.query_db(&#34;SELECT appnr FROM semesterapparat WHERE name=?&#34;, (apparat_name,), one=True) else False
def checkApparatExistsById(self, apparat_id):
return True if self.query_db(&#34;SELECT appnr FROM semesterapparat WHERE appnr=?&#34;, (apparat_id,), one=True) else False
# Statistics
def statistic_request(self, **kwargs: Any):
def __query(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 &#34;deletable&#34; in kwargs.keys():
query = f&#34;SELECT * FROM semesterapparat WHERE deletion_status=0 AND dauer=0 AND (erstellsemester!=&#39;{kwargs[&#39;deletesemester&#39;]}&#39; OR verlängerung_bis!=&#39;{kwargs[&#39;deletesemester&#39;]}&#39;)&#34;
return __query(query)
if &#34;dauer&#34; in kwargs.keys():
kwargs[&#34;dauer&#34;] = kwargs[&#34;dauer&#34;].replace(&#34;Ja&#34;, &#34;1&#34;).replace(&#34;Nein&#34;, &#34;0&#34;)
query = &#34;SELECT * FROM semesterapparat WHERE &#34;
for key, value in kwargs.items() if kwargs.items() is not None else {}:
print(key, value)
query += f&#34;{key}=&#39;{value}&#39; AND &#34;
print(query)
# remove deletesemester part from normal query, as this will be added to the database upon deleting the apparat
if &#34;deletesemester&#34; in kwargs.keys():
query = query.replace(
f&#34;deletesemester=&#39;{kwargs[&#39;deletesemester&#39;]}&#39; AND &#34;, &#34;&#34;
)
if &#34;endsemester&#34; in kwargs.keys():
if &#34;erstellsemester&#34; in kwargs.keys():
query = query.replace(f&#34;endsemester=&#39;{kwargs[&#39;endsemester&#39;]}&#39; AND &#34;, &#34;&#34;)
query = query.replace(
f&#34;erstellsemester=&#39;{kwargs[&#39;erstellsemester&#39;]} AND &#34;, &#34;xyz&#34;
)
else:
query = query.replace(
f&#34;endsemester=&#39;{kwargs[&#39;endsemester&#39;]}&#39; AND &#34;, &#34;xyz&#34;
)
print(&#34;replaced&#34;)
query = query.replace(
&#34;xyz&#34;,
f&#34;(erstellsemester=&#39;{kwargs[&#39;endsemester&#39;]}&#39; OR verlängerung_bis=&#39;{kwargs[&#39;endsemester&#39;]}&#39;) AND &#34;,
)
# remove all x=&#34;&#34; parts from the query where x is a key in kwargs
query = query[:-5]
print(query)
return __query(query)
# Admin data
def getUser(self):
return self.query_db(&#34;SELECT * FROM user&#34;, one=True)
def getUsers(self):
return self.query_db(&#34;SELECT * FROM user&#34;)
def login(self, user, hashed_password):
salt = self.query_db(&#34;SELECT salt FROM user WHERE username=?&#34;, (user,), one=True)[0]
if salt is None:
return False
hashed_password = salt + hashed_password
password = self.query_db(&#34;SELECT password FROM user WHERE username=?&#34;, (user,), one=True)[0]
if password == hashed_password:
return True
else:
return False
def changePassword(self, user, new_password):
salt = self.query_db(&#34;SELECT salt FROM user WHERE username=?&#34;, (user,), one=True)[0]
new_password = salt + new_password
self.query_db(&#34;UPDATE user SET password=? WHERE username=?&#34;, (new_password,user))
def getRole(self, user):
return self.query_db(&#34;SELECT role FROM user WHERE username=?&#34;, (user,), one=True)[0]
def getRoles(self):
return self.query_db(&#34;SELECT role FROM user&#34;)
def checkUsername(self, user):
data = self.query_db(&#34;SELECT username FROM user WHERE username=?&#34;, (user,), one=True)
return True if data is not None else False
def createUser(self, user, password, role, salt):
&#34;&#34;&#34;Create a user based on passed data.
Args:
----
- username (str): Username to be used
- password (str): the salted password
- role (str): Role of the user
- salt (str): a random salt for the user
&#34;&#34;&#34;
self.query_db(&#34;INSERT OR IGNORE INTO user (username, password, role, salt) VALUES (?,?,?,?)&#34;, (user,password,role,salt))
def deleteUser(self, user):
self.query_db(&#34;DELETE FROM user WHERE username=?&#34;, (user,))
def updateUser(self, username, data:dict[str, str]):
conn = self.connect()
cursor = conn.cursor()
query = &#34;UPDATE user SET &#34;
for key,value in data.items():
if key == &#34;username&#34;:
continue
query += f&#34;{key}=&#39;{value}&#39;,&#34;
query = query[:-1]
query += &#34; WHERE username=?&#34;
params = (username,)
cursor.execute(query, params)
conn.commit()
self.close_connection(conn)
def getFacultyMember(self, name:str):
return self.query_db(&#34;SELECT titel, fname,lname,mail,telnr,fullname FROM prof WHERE fullname=?&#34;, (name,), one=True)
def updateFacultyMember(self, data, oldlname, oldfname):
placeholders = &#34;, &#34;.join([f&#34;{i}=:{i} &#34; for i in data.keys()])
query = f&#34;UPDATE prof SET {placeholders} WHERE lname = :oldlname AND fname = :oldfname&#34;
data[&#34;oldlname&#34;] = oldlname
data[&#34;oldfname&#34;] = oldfname
self.query_db(query, data)
def getFacultyMembers(self):
return self.query_db(&#34;SELECT titel, fname,lname,mail,telnr,fullname FROM prof&#34;)</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: str, prof_id: str)</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> :&ensp;<code>BookData</code></dt>
<dd>The metadata of the book to be added</dd>
<dt><strong><code>app_id</code></strong> :&ensp;<code>str</code></dt>
<dd>The apparat id where the book should be added to</dd>
<dt><strong><code>prof_id</code></strong> :&ensp;<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:str, prof_id:str):
&#34;&#34;&#34;
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.
&#34;&#34;&#34;
conn = self.connect()
cursor = conn.cursor()
t_query = (
f&#34;SELECT bookdata FROM media WHERE app_id={app_id} AND prof_id={prof_id}&#34;
)
# print(t_query)
result = cursor.execute(t_query).fetchall()
result = [load_pickle(i[0]) for i in result]
if bookdata in result:
print(&#34;Bookdata already in database&#34;)
# check if the book was deleted in the apparat
query = (
&#34;SELECT deleted FROM media WHERE app_id=? AND prof_id=? AND bookdata=?&#34;
)
params = (app_id, prof_id, dump_pickle(bookdata))
result = cursor.execute(query, params).fetchone()
if result[0] == 1:
print(&#34;Book was deleted, updating bookdata&#34;)
query = &#34;UPDATE media SET deleted=0 WHERE app_id=? AND prof_id=? AND bookdata=?&#34;
params = (app_id, prof_id, dump_pickle(bookdata))
cursor.execute(query, params)
conn.commit()
return
query = (
&#34;INSERT INTO media (bookdata, app_id, prof_id,deleted) VALUES (?, ?, ?,?)&#34;
)
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, appnr)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def addMessage(self, message:dict,user, appnr):
def __getUserId(user):
return self.query_db(&#34;SELECT id FROM user WHERE username=?&#34;, (user,), one=True)[0]
user_id = __getUserId(user)
self.query_db(&#34;INSERT INTO messages (message, user_id, remind_at,appnr) VALUES (?,?,?,?)&#34;, (message[&#34;message&#34;],user_id,message[&#34;remind_at&#34;],appnr))</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"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def changePassword(self, user, new_password):
salt = self.query_db(&#34;SELECT salt FROM user WHERE username=?&#34;, (user,), one=True)[0]
new_password = salt + new_password
self.query_db(&#34;UPDATE user SET password=? WHERE username=?&#34;, (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)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def checkApparatExists(self, apparat_name):
return True if self.query_db(&#34;SELECT appnr FROM semesterapparat WHERE name=?&#34;, (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, apparat_id)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def checkApparatExistsById(self, apparat_id):
return True if self.query_db(&#34;SELECT appnr FROM semesterapparat WHERE appnr=?&#34;, (apparat_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)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def checkUsername(self, user):
data = self.query_db(&#34;SELECT username FROM user WHERE username=?&#34;, (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):
&#34;&#34;&#34;
closes the connection to the database
Args:
----
- conn (sql.Connection): the connection to be closed
&#34;&#34;&#34;
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)-&gt;sql.Connection:
&#34;&#34;&#34;
Connect to the database
Returns:
sql.Connection: The active connection to the database
&#34;&#34;&#34;
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) > Union[src.errors.DatabaseErrors.AppPresentError, ForwardRef(None), int]</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def createApparat(self, apparat:ApparatData)-&gt;Optional[AppPresentError]|int:
prof_id = self.getProfId(apparat.profname)
app_id = self.getApparatId(apparat.appname)
if app_id:
return AppPresentError(app_id)
self.createProf(apparat.get_prof_details())
prof_id = self.getProfId(apparat.profname)
#ic(prof_id)
query = f&#34;INSERT OR IGNORE INTO semesterapparat (appnr, name, erstellsemester, dauer, prof_id, fach,deletion_status,konto) VALUES (&#39;{apparat.appnr}&#39;, &#39;{apparat.appname}&#39;, &#39;{apparat.semester}&#39;, &#39;{apparat.dauerapp}&#39;, {prof_id}, &#39;{apparat.app_fach}&#39;, &#39;{0}&#39;, &#39;{SEMAP_MEDIA_ACCOUNTS[apparat.appnr]}&#39;)&#34;
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"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def createProf(self, prof_details:dict):
prof_title = prof_details[&#34;prof_title&#34;]
prof_fname = prof_details[&#34;profname&#34;].split(&#34;,&#34;)[1]
prof_fname = prof_fname.strip()
prof_lname = prof_details[&#34;profname&#34;].split(&#34;,&#34;)[0]
prof_lname = prof_lname.strip()
prof_fullname = prof_details[&#34;profname&#34;].replace(&#34;,&#34;, &#34;&#34;)
prof_mail = prof_details[&#34;prof_mail&#34;]
prof_tel = prof_details[&#34;prof_tel&#34;]
params = (prof_title, prof_fname, prof_lname, prof_mail, prof_tel, prof_fullname)
query = &#34;INSERT OR IGNORE INTO prof (titel, fname, lname, mail, telnr, fullname) VALUES (?, ?, ?, ?, ?, ?)&#34;
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 a user based on passed data.</p>
<h2 id="args">Args:</h2>
<pre><code>- username (str): Username to be used
- password (str): the salted password
- role (str): Role of the user
- salt (str): a random salt for the user
</code></pre></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def createUser(self, user, password, role, salt):
&#34;&#34;&#34;Create a user based on passed data.
Args:
----
- username (str): Username to be used
- password (str): the salted password
- role (str): Role of the user
- salt (str): a random salt for the user
&#34;&#34;&#34;
self.query_db(&#34;INSERT OR IGNORE INTO user (username, password, role, salt) VALUES (?,?,?,?)&#34;, (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):
&#34;&#34;&#34;
Create the tables in the database
&#34;&#34;&#34;
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, appnr, semester)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def deleteApparat(self, appnr, semester):
self.query_db(&#34;UPDATE semesterapparat SET deletion_status=1, deleted_date=? WHERE appnr=?&#34;, (semester,appnr)) </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> :&ensp;<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):
&#34;&#34;&#34;
Delete a book from the database
Args:
book_id (str): ID of the book
&#34;&#34;&#34;
self.query_db(&#34;UPDATE media SET deleted=1 WHERE id=?&#34;, (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"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def deleteMessage(self, message_id):
self.query_db(&#34;DELETE FROM messages WHERE id=?&#34;, (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"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def deleteUser(self, user):
self.query_db(&#34;DELETE FROM user WHERE username=?&#34;, (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)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getAllAparats(self,deleted=0):
return self.query_db(&#34;SELECT * FROM semesterapparat WHERE deletion_status=?&#34;, (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"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getApparatCountBySemester(self)-&gt;tuple[list[str],list[int]]:
conn = self.connect()
cursor = conn.cursor()
semesters = self.getSemersters()
created = []
deleted = []
for semester in semesters:
query = f&#34;SELECT COUNT(*) FROM semesterapparat WHERE erstellsemester=&#39;{semester}&#39;&#34;
result = cursor.execute(query).fetchone()
created.append(result[0])
query = f&#34;SELECT COUNT(*) FROM semesterapparat WHERE deletion_status=1 AND deleted_date=&#39;{semester}&#39;&#34;
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"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getApparatData(self, appnr, appname)-&gt;ApparatData:
result = self.query_db(&#34;SELECT * FROM semesterapparat WHERE appnr=? AND name=?&#34;, (appnr,appname), one=True)
if result is None:
raise NoResultError(&#34;No result found&#34;)
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)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getApparatId(self, apparat_name):
data = self.query_db(&#34;SELECT appnr FROM semesterapparat WHERE name=?&#34;, (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, prof_id)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getApparatName(self, app_id, prof_id):
return self.query_db(&#34;SELECT name FROM semesterapparat WHERE appnr=? AND prof_id=?&#34;, (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: int) > list[tuple]</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getApparatsByProf(self, prof_id:int)-&gt;list[tuple]:
return self.query_db(&#34;SELECT * FROM semesterapparat WHERE prof_id=?&#34;, (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</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getApparatsBySemester(self, semester:str)-&gt;dict:
data = self.query_db(&#34;SELECT name, prof_id FROM semesterapparat WHERE erstellsemester=?&#34;, (semester,))
conn = self.connect()
cursor = conn.cursor()
c_tmp = []
for i in data:
c_tmp.append((i[0], self.getProfNameById(i[1])))
query = (
f&#34;SELECT name,prof_id FROM semesterapparat WHERE deleted_date=&#39;{semester}&#39;&#34;
)
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 {&#34;created&#34;: c_ret, &#34;deleted&#34;: 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)</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> :&ensp;<code>str</code></dt>
<dd>The name of the file</dd>
<dt><strong><code>app_id</code></strong> :&ensp;<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):
&#34;&#34;&#34;
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
&#34;&#34;&#34;
return self.query_db(&#34;SELECT fileblob FROM files WHERE filename=? AND app_id=?&#34;, (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> :&ensp;<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)-&gt;BookData:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
return load_pickle(self.query_db(&#34;SELECT bookdata FROM media WHERE id=?&#34;, (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: str, prof_id: str, 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> :&ensp;<code>str</code></dt>
<dd>The apparat id the book should be associated with</dd>
<dt><strong><code>prof_id</code></strong> :&ensp;<code>str</code></dt>
<dd>The professor id the book should be associated with</dd>
<dt><strong><code>signature</code></strong> :&ensp;<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:str, prof_id:str,signature:str)-&gt;BookData:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
result = self.query_db(&#34;SELECT bookdata FROM media WHERE app_id=? AND prof_id=?&#34;, (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, prof_id) > 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> :&ensp;<code>BookData</code></dt>
<dd>The wrapped metadata of the book</dd>
<dt><strong><code>app_id</code></strong> :&ensp;<code>str</code></dt>
<dd>The apparat id the book should be associated with</dd>
<dt><strong><code>prof_id</code></strong> :&ensp;<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, prof_id)-&gt;int:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
result = self.query_db(&#34;SELECT id FROM media WHERE bookdata=? AND app_id=? AND prof_id=?&#34;, (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: str, prof_id: str, 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> :&ensp;<code>str</code></dt>
<dd>The apparat id the book should be associated with</dd>
<dt><strong><code>prof_id</code></strong> :&ensp;<code>str</code></dt>
<dd>The professor id the book should be associated with</dd>
<dt><strong><code>signature</code></strong> :&ensp;<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:str, prof_id:str,signature:str)-&gt;int:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
result = self.query_db(&#34;SELECT bookdata, id FROM media WHERE app_id=? AND prof_id=?&#34;, (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, prof_id, 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> :&ensp;<code>str</code></dt>
<dd>The ID of the apparat</dd>
<dt><strong><code>prof_id</code></strong> :&ensp;<code>str</code></dt>
<dd>The ID of the professor</dd>
<dt><strong><code>deleted</code></strong> :&ensp;<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, prof_id, deleted=0)-&gt;list[dict[int, BookData, int]]:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
qdata = self.query_db(f&#34;SELECT id,bookdata,available FROM media WHERE (app_id={app_id} AND prof_id={prof_id}) AND (deleted={deleted if deleted == 0 else &#39;1 OR deleted=0&#39;})&#34;)
ret_result = []
for result_a in qdata:
data = {&#34;id&#34;: int, &#34;bookdata&#34;: BookData, &#34;available&#34;: int}
data[&#34;id&#34;] = result_a[0]
data[&#34;bookdata&#34;] = load_pickle(result_a[1])
data[&#34;available&#34;] = 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)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getFacultyMember(self, name:str):
return self.query_db(&#34;SELECT titel, fname,lname,mail,telnr,fullname FROM prof WHERE fullname=?&#34;, (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"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getFacultyMembers(self):
return self.query_db(&#34;SELECT titel, fname,lname,mail,telnr,fullname FROM prof&#34;)</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: int, prof_id: int) > list[tuple]</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getFiles(self, app_id:int, prof_id:int)-&gt;list[tuple]:
return self.query_db(&#34;SELECT filename, filetyp FROM files WHERE app_id=? AND prof_id=?&#34;, (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)-&gt;int:
&#34;&#34;&#34;
Get the last book id in the database
Returns:
int: ID of the last book in the database
&#34;&#34;&#34;
return self.query_db(&#34;SELECT id FROM media ORDER BY id DESC&#34;, 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)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getMessages(self, date:str):
def __get_user_name(user_id):
return self.query_db(&#34;SELECT username FROM user WHERE id=?&#34;, (user_id,), one=True)[0]
messages = self.query_db(&#34;SELECT * FROM messages WHERE remind_at=?&#34;, (date,))
ret = [
{
&#34;message&#34;: i[2],
&#34;user&#34;: __get_user_name(i[4]),
&#34;appnr&#34;: i[5],
&#34;id&#34;: 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)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getProfByName(self, prof_name:str):
return self.query_db(&#34;SELECT * FROM prof WHERE fullname=?&#34;, (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"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getProfData(self, profname:str):
data = self.query_db(&#34;SELECT mail, telnr, titel FROM prof WHERE fullname=?&#34;, (profname.replace(&#34;,&#34;,&#34;&#34;),), 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)</span>
</code></dt>
<dd>
<div class="desc"><p>getProfId <em>summary</em></p>
<p>:param prof_name: <em>description</em>
:type prof_name: str
:return: <em>description</em>
:rtype: <em>type</em></p></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getProfId(self, prof_name:str):
&#34;&#34;&#34;
getProfId _summary_
:param prof_name: _description_
:type prof_name: str
:return: _description_
:rtype: _type_
&#34;&#34;&#34;
data = self.getProfByName(prof_name.replace(&#34;,&#34;, &#34;&#34;))
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: int, add_title: bool = False)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getProfNameById(self, prof_id:int,add_title:bool=False):
prof = self.query_db(&#34;SELECT fullname FROM prof WHERE id=?&#34;, (prof_id,), one=True)
if add_title:
return f&#34;{self.getTitleById(prof_id)}{prof[0]}&#34;
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)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getProfs(self):
return self.query_db(&#34;SELECT * FROM prof&#34;)</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"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getRole(self, user):
return self.query_db(&#34;SELECT role FROM user WHERE username=?&#34;, (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)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getRoles(self):
return self.query_db(&#34;SELECT role FROM user&#34;)</code></pre>
</details>
</dd>
<dt id="database.Database.getSemersters"><code class="name flex">
<span>def <span class="ident">getSemersters</span></span>(<span>self)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getSemersters(self):
data = self.query_db(&#34;SELECT DISTINCT erstellsemester FROM semesterapparat&#34;)
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: int, fields: List[str])</span>
</code></dt>
<dd>
<div class="desc"><p>getSpecificProfData <em>summary</em></p>
<h2 id="args">Args:</h2>
<pre><code>- prof_id (int): _description_
- fields (List[str]): _description_
</code></pre>
<h2 id="returns">Returns:</h2>
<pre><code>- _type_: _description_
</code></pre></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getSpecificProfData(self, prof_id:int, fields:List[str]):
&#34;&#34;&#34;
getSpecificProfData _summary_
Args:
----
- prof_id (int): _description_
- fields (List[str]): _description_
Returns:
-------
- _type_: _description_
&#34;&#34;&#34;
query = &#34;SELECT &#34;
for field in fields:
query += f&#34;{field},&#34;
query = query[:-1]
query += &#34; FROM prof WHERE id=?&#34;
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"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getSubjects(self):
return self.query_db(&#34;SELECT * FROM subjects&#34;)</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: int)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getTitleById(self, prof_id:int):
title = self.query_db(&#34;SELECT titel FROM prof WHERE id=?&#34;, (prof_id,), one=True)[0]
return f&#34;{title} &#34; if title is not None else &#34;&#34;</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>getUnavailableApparatNumbers returns a list of all currently used ApparatNumbers</p>
<h2 id="returns">Returns:</h2>
<pre><code>- number(List[int]): a list of all currently used apparat numbers
</code></pre></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getUnavailableApparatNumbers(self)-&gt;List[int]:
&#34;&#34;&#34;
getUnavailableApparatNumbers returns a list of all currently used ApparatNumbers
Returns:
-------
- number(List[int]): a list of all currently used apparat numbers
&#34;&#34;&#34;
numbers = self.query_db(&#34;SELECT appnr FROM semesterapparat WHERE deletion_status=0&#34;)
numbers = [i[0] for i in numbers]
logger.log_info(f&#34;Currently used apparat numbers: {numbers}&#34;)
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"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getUser(self):
return self.query_db(&#34;SELECT * FROM user&#34;, 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)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def getUsers(self):
return self.query_db(&#34;SELECT * FROM user&#34;)</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)-&gt;Union[List[Tuple], None]:
&#34;&#34;&#34;
Get the contents of the
Returns:
Union[List[Tuple], None]: _description_
&#34;&#34;&#34;
try:
with sql.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute(&#34;SELECT * FROM sqlite_master WHERE type=&#39;table&#39;&#34;)
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: int, prof_id)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def insertFile(self, file: list[dict], app_id: int, prof_id):
for f in file:
filename = f[&#34;name&#34;]
path = f[&#34;path&#34;]
filetyp = f[&#34;type&#34;]
if path == &#34;Database&#34;:
continue
blob = create_blob(path)
query = &#34;INSERT OR IGNORE INTO files (filename, fileblob, app_id, filetyp,prof_id) VALUES (?, ?, ?, ?,?)&#34;
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> :&ensp;<code>str</code></dt>
<dd>The query to be executed</dd>
<dt><strong><code>params</code></strong> :&ensp;<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) -&gt; None:
&#34;&#34;&#34;
Insert sent data into the database
Args:
query (str): The query to be executed
params (Tuple): the parameters to be inserted into the database
&#34;&#34;&#34;
conn = self.connect()
cursor = conn.cursor()
logger.log_info(f&#34;Inserting {params} into database with query {query}&#34;)
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"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def isEternal(self, id):
return self.query_db(&#34;SELECT dauer FROM semesterapparat WHERE appnr=?&#34;, (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"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def login(self, user, hashed_password):
salt = self.query_db(&#34;SELECT salt FROM user WHERE username=?&#34;, (user,), one=True)[0]
if salt is None:
return False
hashed_password = salt + hashed_password
password = self.query_db(&#34;SELECT password FROM user WHERE username=?&#34;, (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> :&ensp;<code>str</code></dt>
<dd>The query to be executed</dd>
<dt><strong><code>args</code></strong> :&ensp;<code>Tuple</code>, optional</dt>
<dd>The arguments for the query. Defaults to ().</dd>
<dt><strong><code>one</code></strong> :&ensp;<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)-&gt;Union[Tuple, List[Tuple]]:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
conn = self.connect()
cursor = conn.cursor()
logger.log_info(f&#34;Querying database with query {query}, args: {args}&#34;)
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, app_id, filetype)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def recreateFile(self, filename, app_id,filetype):
blob = self.getBlob(filename, app_id)
tempdir = config.database.tempdir
tempdir = tempdir.replace(&#34;~&#34;, 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=&#34;wb&#34;, suffix=f&#34;.{filetype}&#34;
)
file.write(blob)
print(&#34;file created&#34;)
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> :&ensp;<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])-&gt;list[tuple[BookData, int]]:
&#34;&#34;&#34;
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
&#34;&#34;&#34;
rdata = self.query_db(&#34;SELECT * FROM media WHERE deleted=0&#34;)
#ic(rdata, len(rdata))
mode = 0
if len(data)== 1:
if &#34;signature&#34; in data.keys():
mode = 1
elif &#34;title&#34; 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[&#34;signature&#34;] in bookdata.signature:
ret.append((bookdata,app_id,prof_id))
elif mode == 2:
if data[&#34;title&#34;] in bookdata.title:
ret.append((bookdata,app_id,prof_id))
elif mode == 3:
if data[&#34;signature&#34;] in bookdata.signature and data[&#34;title&#34;] 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> :&ensp;<code>str</code></dt>
<dd>The id of the book</dd>
<dt><strong><code>available</code></strong> :&ensp;<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):
&#34;&#34;&#34;
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
&#34;&#34;&#34;
self.query_db(&#34;UPDATE media SET available=? WHERE id=?&#34;, (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, appnr, newDate, dauerapp=False)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def setNewSemesterDate(self, appnr, newDate, dauerapp=False):
date = datetime.datetime.strptime(newDate, &#34;%d.%m.%Y&#34;).strftime(&#34;%Y-%m-%d&#34;)
if dauerapp:
self.query_db(&#34;UPDATE semesterapparat SET verlängerung_bis=?, dauerapp=? WHERE appnr=?&#34;, (date,dauerapp,appnr))
else:
self.query_db(&#34;UPDATE semesterapparat SET endsemester=? WHERE appnr=?&#34;, (date,appnr))</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"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def statistic_request(self, **kwargs: Any):
def __query(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 &#34;deletable&#34; in kwargs.keys():
query = f&#34;SELECT * FROM semesterapparat WHERE deletion_status=0 AND dauer=0 AND (erstellsemester!=&#39;{kwargs[&#39;deletesemester&#39;]}&#39; OR verlängerung_bis!=&#39;{kwargs[&#39;deletesemester&#39;]}&#39;)&#34;
return __query(query)
if &#34;dauer&#34; in kwargs.keys():
kwargs[&#34;dauer&#34;] = kwargs[&#34;dauer&#34;].replace(&#34;Ja&#34;, &#34;1&#34;).replace(&#34;Nein&#34;, &#34;0&#34;)
query = &#34;SELECT * FROM semesterapparat WHERE &#34;
for key, value in kwargs.items() if kwargs.items() is not None else {}:
print(key, value)
query += f&#34;{key}=&#39;{value}&#39; AND &#34;
print(query)
# remove deletesemester part from normal query, as this will be added to the database upon deleting the apparat
if &#34;deletesemester&#34; in kwargs.keys():
query = query.replace(
f&#34;deletesemester=&#39;{kwargs[&#39;deletesemester&#39;]}&#39; AND &#34;, &#34;&#34;
)
if &#34;endsemester&#34; in kwargs.keys():
if &#34;erstellsemester&#34; in kwargs.keys():
query = query.replace(f&#34;endsemester=&#39;{kwargs[&#39;endsemester&#39;]}&#39; AND &#34;, &#34;&#34;)
query = query.replace(
f&#34;erstellsemester=&#39;{kwargs[&#39;erstellsemester&#39;]} AND &#34;, &#34;xyz&#34;
)
else:
query = query.replace(
f&#34;endsemester=&#39;{kwargs[&#39;endsemester&#39;]}&#39; AND &#34;, &#34;xyz&#34;
)
print(&#34;replaced&#34;)
query = query.replace(
&#34;xyz&#34;,
f&#34;(erstellsemester=&#39;{kwargs[&#39;endsemester&#39;]}&#39; OR verlängerung_bis=&#39;{kwargs[&#39;endsemester&#39;]}&#39;) AND &#34;,
)
# remove all x=&#34;&#34; 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"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def updateApparat(self, apparat_data:ApparatData):
query = f&#34;UPDATE semesterapparat SET name = ?, fach = ?, dauer = ?, prof_id = ? WHERE appnr = ?&#34;
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> :&ensp;<code>str</code></dt>
<dd>The id of the book</dd>
<dt><strong><code>bookdata</code></strong> :&ensp;<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):
&#34;&#34;&#34;
Update the bookdata in the database
Args:
book_id (str): The id of the book
bookdata (BookData): The new metadata of the book
&#34;&#34;&#34;
self.query_db(&#34;UPDATE media SET bookdata=? WHERE id=?&#34;, (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, oldlname, oldfname)</span>
</code></dt>
<dd>
<div class="desc"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def updateFacultyMember(self, data, oldlname, oldfname):
placeholders = &#34;, &#34;.join([f&#34;{i}=:{i} &#34; for i in data.keys()])
query = f&#34;UPDATE prof SET {placeholders} WHERE lname = :oldlname AND fname = :oldfname&#34;
data[&#34;oldlname&#34;] = oldlname
data[&#34;oldfname&#34;] = 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"></div>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def updateUser(self, username, data:dict[str, str]):
conn = self.connect()
cursor = conn.cursor()
query = &#34;UPDATE user SET &#34;
for key,value in data.items():
if key == &#34;username&#34;:
continue
query += f&#34;{key}=&#39;{value}&#39;,&#34;
query = query[:-1]
query += &#34; WHERE username=?&#34;
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>