fix broken files after faulty update
This commit is contained in:
@@ -1,11 +1,25 @@
|
||||
__version__ = "1.0.0"
|
||||
__author__ = "Alexander Kirchner"
|
||||
|
||||
import sys
|
||||
from config import Config
|
||||
import os
|
||||
from loguru import logger as log
|
||||
import sys
|
||||
|
||||
settings = Config("config/config.yaml")
|
||||
|
||||
from .utils.icon import Icon
|
||||
|
||||
from .logic.log import MyLogger
|
||||
from .ui.userInterface import launch_gui as UI
|
||||
__version__ = "0.1.0"
|
||||
__author__ = "Alexander Kirchner"
|
||||
|
||||
|
||||
if not os.path.exists("logs"):
|
||||
os.mkdir("logs")
|
||||
# open and close the file to create it
|
||||
logger = log
|
||||
logger.remove()
|
||||
logger.add("logs/application_info.log", rotation="1 week", level="INFO", enqueue=True)
|
||||
logger.add("logs/application_error.log", rotation="1 week", level="ERROR", enqueue=True)
|
||||
logger.add("logs/application_debug.log", rotation="1 week", level="DEBUG", enqueue=True)
|
||||
logger.add("logs/application.log", rotation="1 week", enqueue=True)
|
||||
# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
|
||||
logger.add(sys.stdout)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
from .admin_console import AdminCommands
|
||||
from .create_file import recreateElsaFile, recreateFile
|
||||
from .database import Database
|
||||
from .delete_temp_contents import delete_temp_contents as tempdelete
|
||||
from .semester import generateSemesterByDate, generateSemesterByOffset
|
||||
from .semester import Semester
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import hashlib
|
||||
import random
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from icecream import ic
|
||||
|
||||
from src.backend.database import Database
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ import tempfile
|
||||
from pathlib import Path
|
||||
from src import settings
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
# from icecream import ic
|
||||
from omegaconf import OmegaConf
|
||||
import datetime
|
||||
from src import logger
|
||||
from src.backend.db import (
|
||||
CREATE_ELSA_FILES_TABLE,
|
||||
CREATE_ELSA_MEDIA_TABLE,
|
||||
@@ -22,15 +22,14 @@ from src.backend.db import (
|
||||
CREATE_TABLE_USER,
|
||||
)
|
||||
from src.errors import AppPresentError, NoResultError
|
||||
from src.logic import ApparatData, BookData, Prof, Apparat, ELSA, logger as log
|
||||
from src.logic import ApparatData, BookData, Prof, Apparat, ELSA
|
||||
from src.logic.constants import SEMAP_MEDIA_ACCOUNTS
|
||||
from src.utils import create_blob, dump_pickle, load_pickle
|
||||
from .semester import generateSemesterByDate
|
||||
from icecream import ic
|
||||
from string import ascii_lowercase as lower, digits
|
||||
from .semester import Semester
|
||||
from string import ascii_lowercase as lower, digits, punctuation
|
||||
|
||||
|
||||
ascii_lowercase = lower + digits
|
||||
ascii_lowercase = lower + digits + punctuation
|
||||
# get the line that called the function
|
||||
class Database:
|
||||
database = settings.database
|
||||
@@ -62,7 +61,7 @@ class Database:
|
||||
# print(path)
|
||||
os.makedirs(path)
|
||||
if self.get_db_contents() == []:
|
||||
log.critical("Database does not exist, creating tables")
|
||||
logger.critical("Database does not exist, creating tables")
|
||||
self.create_tables()
|
||||
self.insertSubjects()
|
||||
|
||||
@@ -146,12 +145,12 @@ class Database:
|
||||
"""
|
||||
conn = self.connect()
|
||||
cursor = conn.cursor()
|
||||
log.info(f"Inserting {params} into database with query {query}")
|
||||
logger.debug(f"Inserting {params} into database with query {query}")
|
||||
cursor.execute(query, params)
|
||||
conn.commit()
|
||||
self.close_connection(conn)
|
||||
|
||||
@log.catch
|
||||
@logger.catch
|
||||
def query_db(
|
||||
self, query: str, args: Tuple = (), one: bool = False
|
||||
) -> Union[Tuple, List[Tuple]]:
|
||||
@@ -181,14 +180,14 @@ class Database:
|
||||
# if "INSERT" in query:
|
||||
# log_message = f"Querying database with query {query}"
|
||||
|
||||
log.info(log_message)
|
||||
logger.debug(log_message)
|
||||
try:
|
||||
cursor.execute(query, args)
|
||||
rv = cursor.fetchall()
|
||||
conn.commit()
|
||||
self.close_connection(conn)
|
||||
except sql.OperationalError as e:
|
||||
log.error(f"Error in query: {e}")
|
||||
logger.error(f"Error in query: {e}")
|
||||
return None
|
||||
return (rv[0] if rv else None) if one else rv
|
||||
|
||||
@@ -211,7 +210,7 @@ class Database:
|
||||
t_query = (
|
||||
f"SELECT bookdata FROM media WHERE app_id={app_id} AND prof_id={prof_id}"
|
||||
)
|
||||
log.info(t_query)
|
||||
logger.debug(t_query)
|
||||
# # print(t_query)
|
||||
result = cursor.execute(t_query).fetchall()
|
||||
result = [load_pickle(i[0]) for i in result]
|
||||
@@ -238,7 +237,7 @@ class Database:
|
||||
params = (converted, app_id, prof_id, 0)
|
||||
cursor.execute(query, params)
|
||||
logMessage = f"Added book with signature {bookdata.signature} to database, data: {converted}"
|
||||
log.info(logMessage)
|
||||
logger.info(logMessage)
|
||||
conn.commit()
|
||||
self.close_connection(conn)
|
||||
|
||||
@@ -307,7 +306,7 @@ class Database:
|
||||
list[tuple[BookData, int]]: A list of tuples containing the wrapped Metadata and the id of the book
|
||||
"""
|
||||
rdata = self.query_db("SELECT * FROM media WHERE deleted=0")
|
||||
# ic(rdata, len(rdata))
|
||||
# logger.debug(rdata, len(rdata))
|
||||
mode = 0
|
||||
if len(data) == 1:
|
||||
if "signature" in data.keys():
|
||||
@@ -335,7 +334,7 @@ class Database:
|
||||
and data["title"] in bookdata.title
|
||||
):
|
||||
ret.append((bookdata, app_id, prof_id))
|
||||
# ic(ret)
|
||||
# logger.debug(ret)
|
||||
return ret
|
||||
|
||||
def setAvailability(self, book_id: str, available: str):
|
||||
@@ -514,7 +513,7 @@ class Database:
|
||||
(app_id, prof_id),
|
||||
)
|
||||
|
||||
def getSemersters(self) -> list[str]:
|
||||
def getSemesters(self) -> list[str]:
|
||||
"""Return all the unique semesters in the database
|
||||
|
||||
Returns:
|
||||
@@ -640,7 +639,7 @@ class Database:
|
||||
Args:
|
||||
message_id (str): the id of the message
|
||||
"""
|
||||
log.info(f"Deleting message with id {message_id}")
|
||||
logger.debug(f"Deleting message with id {message_id}")
|
||||
self.query_db("DELETE FROM messages WHERE id=?", (message_id,))
|
||||
|
||||
# Prof data
|
||||
@@ -710,7 +709,6 @@ class Database:
|
||||
(profname.replace(",", ""),),
|
||||
one=True,
|
||||
)
|
||||
print(data)
|
||||
person = Prof()
|
||||
return person.from_tuple(data)
|
||||
|
||||
@@ -770,20 +768,21 @@ class Database:
|
||||
if result is None:
|
||||
raise NoResultError("No result found")
|
||||
apparat = ApparatData()
|
||||
apparat.appname = result[1]
|
||||
apparat.appnr = result[4]
|
||||
apparat.dauerapp = True if result[7] == 1 else False
|
||||
prof_data = self.getProfData(self.getProfNameById(result[2]))
|
||||
apparat.profname = self.getProfNameById(result[2])
|
||||
apparat.prof_mail = prof_data.mail
|
||||
apparat.prof_tel = prof_data.telnr
|
||||
apparat.prof_title = prof_data.title
|
||||
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]
|
||||
apparat.apparat.id = result[0]
|
||||
apparat.apparat.name = result[1]
|
||||
apparat.apparat.appnr = result[4]
|
||||
apparat.apparat.eternal = True if result[7] == 1 else False
|
||||
apparat.prof = self.getProfData(self.getProfNameById(result[2]))
|
||||
apparat.prof.fullname = self.getProfNameById(result[2])
|
||||
apparat.apparat.prof_id = result[2]
|
||||
|
||||
apparat.apparat.subject = result[3]
|
||||
apparat.apparat.created_semester = result[5]
|
||||
apparat.apparat.extend_until = result[8]
|
||||
apparat.apparat.deleted = result[9]
|
||||
apparat.apparat.apparat_id_adis = result[11]
|
||||
apparat.apparat.prof_id_adis = result[12]
|
||||
apparat.apparat.konto = result[13]
|
||||
return apparat
|
||||
|
||||
def getUnavailableApparatNumbers(self) -> List[int]:
|
||||
@@ -796,7 +795,7 @@ class Database:
|
||||
"SELECT appnr FROM semesterapparat WHERE deletion_status=0"
|
||||
)
|
||||
numbers = [i[0] for i in numbers]
|
||||
log.info(f"Currently used apparat numbers: {numbers}")
|
||||
logger.info(f"Currently used apparat numbers: {numbers}")
|
||||
return numbers
|
||||
|
||||
def setNewSemesterDate(self, app_id: Union[str, int], newDate, dauerapp=False):
|
||||
@@ -850,21 +849,22 @@ class Database:
|
||||
Returns:
|
||||
Optional[int]: the id of the apparat
|
||||
"""
|
||||
ic(apparat)
|
||||
prof = self.getProfByName(apparat.prof_details.fullname)
|
||||
prof_id = prof.id
|
||||
ic(prof_id, apparat.profname)
|
||||
|
||||
app_id = self.getApparatId(apparat.appname)
|
||||
logger.debug(apparat)
|
||||
app = apparat.apparat
|
||||
prof = apparat.prof
|
||||
present_prof = self.getProfByName(prof.name())
|
||||
prof_id = present_prof.id
|
||||
logger.debug(present_prof)
|
||||
|
||||
app_id = self.getApparatId(app.name)
|
||||
if app_id:
|
||||
return AppPresentError(app_id)
|
||||
if not prof_id:
|
||||
print("prof id not present, creating prof with data", apparat.prof_details)
|
||||
prof_id = self.createProf(apparat.prof_details)
|
||||
# self.getProfId(apparat.profname)
|
||||
ic(prof_id)
|
||||
query = f"INSERT OR IGNORE INTO semesterapparat (appnr, name, erstellsemester, dauer, prof_id, fach,deletion_status,konto) VALUES ('{apparat.appnr}', '{apparat.appname}', '{apparat.semester}', '{apparat.dauerapp}', {prof_id}, '{apparat.app_fach}', '{0}', '{SEMAP_MEDIA_ACCOUNTS[apparat.appnr]}')"
|
||||
log.info(query)
|
||||
logger.debug("prof id not present, creating prof with data", prof)
|
||||
prof_id = self.createProf(prof)
|
||||
logger.debug(prof_id)
|
||||
query = f"INSERT OR IGNORE INTO semesterapparat (appnr, name, erstellsemester, dauer, prof_id, fach,deletion_status,konto) VALUES ('{app.appnr}', '{app.name}', '{app.created_semester}', '{app.eternal}', {prof_id}, '{app.subject}', '{0}', '{SEMAP_MEDIA_ACCOUNTS[app.appnr]}')"
|
||||
logger.debug(query)
|
||||
self.query_db(query)
|
||||
return None
|
||||
def getApparatsByProf(self, prof_id: Union[str, int]) -> list[tuple]:
|
||||
@@ -934,7 +934,7 @@ class Database:
|
||||
"""
|
||||
conn = self.connect()
|
||||
cursor = conn.cursor()
|
||||
semesters = self.getSemersters()
|
||||
semesters = self.getSemesters()
|
||||
created = []
|
||||
deleted = []
|
||||
for semester in semesters:
|
||||
@@ -946,7 +946,6 @@ class Database:
|
||||
deleted.append(result[0])
|
||||
# store data in a tuple
|
||||
ret = []
|
||||
e_tuple = ()
|
||||
for sem in semesters:
|
||||
e_tuple = (
|
||||
sem,
|
||||
@@ -957,17 +956,16 @@ class Database:
|
||||
self.close_connection(conn)
|
||||
return ret
|
||||
|
||||
def deleteApparat(self, app_id: Union[str, int]):
|
||||
def deleteApparat(self, app_id: Union[str, int], semester):
|
||||
"""Delete an apparat from the database
|
||||
|
||||
Args:
|
||||
app_id (Union[str, int]): the id of the apparat
|
||||
semester (str): the semester the apparat should be deleted from
|
||||
"""
|
||||
today = datetime.datetime.now().strftime("%Y-%m-%d")
|
||||
self.query_db(
|
||||
"UPDATE semesterapparat SET deletion_status=1, deleted_date=? WHERE appnr=?",
|
||||
(today, app_id),
|
||||
(semester, app_id),
|
||||
)
|
||||
|
||||
def isEternal(self, id):
|
||||
@@ -1007,15 +1005,15 @@ class Database:
|
||||
"""
|
||||
query = "UPDATE semesterapparat SET name = ?, fach = ?, dauer = ?, prof_id = ?, prof_id_adis = ?, apparat_id_adis = ? WHERE appnr = ?"
|
||||
params = (
|
||||
apparat_data.appname,
|
||||
apparat_data.app_fach,
|
||||
apparat_data.dauerapp,
|
||||
self.getProfData(apparat_data.prof_details.fullname).id,
|
||||
apparat_data.prof_adis_id,
|
||||
apparat_data.apparat_adis_id,
|
||||
apparat_data.appnr,
|
||||
apparat_data.apparat.name,
|
||||
apparat_data.apparat.subject,
|
||||
apparat_data.apparat.eternal,
|
||||
self.getProfData(apparat_data.prof.fullname).id,
|
||||
apparat_data.apparat.prof_id_adis,
|
||||
apparat_data.apparat.apparat_id_adis,
|
||||
apparat_data.apparat.appnr,
|
||||
)
|
||||
log.info(f"Updating apparat with query {query} and params {params}")
|
||||
logger.debug(f"Updating apparat with query {query} and params {params}")
|
||||
self.query_db(query, params)
|
||||
|
||||
def checkApparatExists(self, app_name: str):
|
||||
@@ -1067,7 +1065,8 @@ class Database:
|
||||
Returns:
|
||||
list: the result of the query
|
||||
"""
|
||||
ic(query)
|
||||
logger.debug(query)
|
||||
logger.debug(f"Query: {query}")
|
||||
conn = self.connect()
|
||||
cursor = conn.cursor()
|
||||
result = cursor.execute(query).fetchall()
|
||||
@@ -1080,15 +1079,15 @@ class Database:
|
||||
result_a = tuple(result_a)
|
||||
result[result.index(orig_value)] = result_a
|
||||
self.close_connection(conn)
|
||||
log.info(f"Query result: {result}")
|
||||
logger.debug(f"Query result: {result}")
|
||||
return result
|
||||
|
||||
if "deletable" in kwargs.keys():
|
||||
query = f"""SELECT * FROM semesterapparat
|
||||
WHERE deletion_status=0 AND dauer=0 AND
|
||||
(
|
||||
(erstellsemester!='{kwargs['deletesemester']}' AND verlängerung_bis IS NULL) OR
|
||||
(erstellsemester!='{kwargs['deletesemester']}' AND verlängerung_bis!='{kwargs['deletesemester']}' AND verlängerung_bis!='{generateSemesterByDate(True)}')
|
||||
(erstellsemester!='{kwargs["deletesemester"]}' AND verlängerung_bis IS NULL) OR
|
||||
(erstellsemester!='{kwargs["deletesemester"]}' AND verlängerung_bis!='{kwargs["deletesemester"]}' AND verlängerung_bis!='{Semester()}')
|
||||
)"""
|
||||
return __query(query)
|
||||
if "dauer" in kwargs.keys():
|
||||
@@ -1119,8 +1118,10 @@ class Database:
|
||||
f"(erstellsemester='{kwargs['endsemester']}' OR verlängerung_bis='{kwargs['endsemester']}') AND ",
|
||||
)
|
||||
# remove all x="" parts from the query where x is a key in kwargs
|
||||
query = query[:-5]
|
||||
logger.info(f"Query before: {query}")
|
||||
query = query.strip()
|
||||
query = query[:-4]
|
||||
logger.info(f"Query after: {query}")
|
||||
# check if query ends with lowercase letter or a '. if not, remove last symbol and try again
|
||||
while query[-1] not in ascii_lowercase and query[-1] != "'":
|
||||
query = query[:-1]
|
||||
@@ -1471,22 +1472,19 @@ class Database:
|
||||
)
|
||||
###
|
||||
|
||||
|
||||
|
||||
def createProf(self, profdata:Prof):
|
||||
print("createProf")
|
||||
ic(profdata)
|
||||
def createProf(self, profdata: Prof):
|
||||
logger.debug(profdata)
|
||||
conn = self.connect()
|
||||
cursor = conn.cursor()
|
||||
fname = profdata.firstname#profdata["profname"].split(", ")[1].strip()
|
||||
lname = profdata.lastname#profdata["profname"].split(", ")[0].strip()
|
||||
fname = profdata.firstname
|
||||
lname = profdata.lastname
|
||||
fullname = f"{lname} {fname}"
|
||||
mail = profdata.mail#profdata["prof_mail"]
|
||||
telnr = profdata.telnr#profdata["prof_tel"]
|
||||
title = profdata.title #profdata["title"]
|
||||
mail = profdata.mail
|
||||
telnr = profdata.telnr
|
||||
title = profdata.title
|
||||
|
||||
query = f"INSERT INTO prof (fname, lname, fullname, mail, telnr,titel) VALUES ('{fname}','{lname}','{fullname}','{mail}','{telnr}','{title}')"
|
||||
log.info(query)
|
||||
logger.debug(query)
|
||||
cursor.execute(query)
|
||||
|
||||
conn.commit()
|
||||
@@ -1519,7 +1517,7 @@ class Database:
|
||||
conn = self.connect()
|
||||
cursor = conn.cursor()
|
||||
if isinstance(profdata, Prof):
|
||||
fullname = profdata.fullname
|
||||
fullname = profdata.name()
|
||||
else:
|
||||
name = profdata["profname"]
|
||||
if ","in name:
|
||||
@@ -1529,7 +1527,7 @@ class Database:
|
||||
else:
|
||||
fullname = profdata["profname"]
|
||||
query = f"SELECT id FROM prof WHERE fullname = '{fullname}'"
|
||||
log.info(query)
|
||||
logger.debug(query)
|
||||
|
||||
cursor.execute(query)
|
||||
result = cursor.fetchone()
|
||||
@@ -1546,7 +1544,7 @@ class Database:
|
||||
conn = self.connect()
|
||||
cursor = conn.cursor()
|
||||
query = f"SELECT * FROM prof WHERE fullname = '{fullname}'"
|
||||
log.info(query)
|
||||
logger.debug(query)
|
||||
|
||||
result = cursor.execute(query).fetchone()
|
||||
if result:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
CREATE_TABLE_APPARAT = """CREATE TABLE semesterapparat (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
name TEXT,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from src import database
|
||||
|
||||
from src import settings
|
||||
|
||||
database = settings.database
|
||||
|
||||
def delete_temp_contents():
|
||||
"""
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import pickle
|
||||
from typing import Any, ByteString
|
||||
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
import datetime
|
||||
from src.logic.log import logger
|
||||
from src import logger
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class Semester:
|
||||
logger.debug("Semester class loaded")
|
||||
|
||||
_year: int | None = datetime.datetime.now().year
|
||||
_year: int | None = str(datetime.datetime.now().year)[2:]
|
||||
_semester: str | None = None
|
||||
_month: int | None = datetime.datetime.now().month
|
||||
value: str = None
|
||||
logger.debug(f"Got values year:{_year}, semester:{_semester}, month:{_month}")
|
||||
|
||||
def __post_init__(self):
|
||||
logger.debug(
|
||||
f"Got values post_init year:{self._year}, semester:{self._semester}, month:{self._month}"
|
||||
)
|
||||
|
||||
if isinstance(self._year, str):
|
||||
self._year = int(self._year)
|
||||
if self._year is None:
|
||||
self._year = datetime.datetime.now().year
|
||||
self._year = datetime.datetime.now().year[2:]
|
||||
if self._month is None:
|
||||
self._month = datetime.datetime.now().month
|
||||
if self._semester is None:
|
||||
@@ -37,11 +34,7 @@ class Semester:
|
||||
@logger.catch
|
||||
def computeValue(self):
|
||||
# year is only last two digits
|
||||
year = str(self._year)[2:]
|
||||
year = int(year)
|
||||
logger.debug(
|
||||
f"Year is {year}, month is {self._month}, semester is {self._semester}"
|
||||
)
|
||||
year = self._year
|
||||
if self._semester == "WiSe":
|
||||
if self._month < 4:
|
||||
valueyear = str(year - 1) + "/" + str(year)
|
||||
@@ -60,29 +53,75 @@ class Semester:
|
||||
str: the new semester value
|
||||
"""
|
||||
assert isinstance(value, int), "Value must be an integer"
|
||||
logger.debug(f"Offsetting semester by {value}")
|
||||
if value == 0:
|
||||
return self
|
||||
if value > 0:
|
||||
if value % 2 == 0:
|
||||
return Semester(self._year + value // 2, self._semester)
|
||||
return Semester(
|
||||
self._year - value // 2, self._semester - value // 2 + 1
|
||||
)
|
||||
else:
|
||||
semester = self._semester
|
||||
semester = "SoSe" if semester == "WiSe" else "WiSe"
|
||||
logger.debug(f"Semester is {semester}")
|
||||
return Semester(self._year + value // 2, semester)
|
||||
else:
|
||||
if value % 2 == 0:
|
||||
return Semester(self._year - value // 2, self._semester)
|
||||
return Semester(self.year + value // 2, self._semester)
|
||||
else:
|
||||
semester = self._semester
|
||||
semester = "SoSe" if semester == "WiSe" else "WiSe"
|
||||
return Semester(self._year + value // 2, semester)
|
||||
|
||||
def isPastSemester(self, semester) -> bool:
|
||||
"""Checks if the current Semester is a past Semester compared to the given Semester
|
||||
|
||||
Args:
|
||||
semester (str): The semester to compare to
|
||||
|
||||
Returns:
|
||||
bool: True if the current semester is in the past, False otherwise
|
||||
"""
|
||||
if self.year < semester.year:
|
||||
return True
|
||||
if self.year == semester.year:
|
||||
if self.semester == "WiSe" and semester.semester == "SoSe":
|
||||
return True
|
||||
return False
|
||||
|
||||
def isFutureSemester(self, semester: "Semester") -> bool:
|
||||
"""Checks if the current Semester is a future Semester compared to the given Semester
|
||||
|
||||
Args:
|
||||
semester (str): The semester to compare to
|
||||
|
||||
Returns:
|
||||
bool: True if the current semester is in the future, False otherwise
|
||||
"""
|
||||
if self.year > semester.year:
|
||||
return True
|
||||
if self.year == semester.year:
|
||||
if self.semester == "SoSe" and semester.semester == "WiSe":
|
||||
return True
|
||||
return False
|
||||
|
||||
def from_string(self, val):
|
||||
self.value = val
|
||||
self._year = int(val[-2:])
|
||||
self._semester = val[:4]
|
||||
return self
|
||||
|
||||
@property
|
||||
def next(self):
|
||||
return self.offset(1)
|
||||
|
||||
@property
|
||||
def previous(self):
|
||||
return self.offset(-1)
|
||||
return self.offset(-1)
|
||||
|
||||
@property
|
||||
def year(self):
|
||||
return self._year
|
||||
|
||||
@property
|
||||
def semester(self):
|
||||
return self._semester
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
import yaml
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
class NoResultError(Exception):
|
||||
def __init__(self, message):
|
||||
self.message = f"The query: {message} returned no results"
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
|
||||
# import basic error classes
|
||||
from .DatabaseErrors import *
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from .log import MyLogger, logger
|
||||
|
||||
from .dataclass import ApparatData, BookData, Prof, Apparat, ELSA
|
||||
from .thread_bookgrabber import BookGrabber
|
||||
from .threads_autoadder import AutoAdder
|
||||
from .threads_availchecker import AvailChecker
|
||||
from .c_sort import custom_sort
|
||||
from .c_sort import custom_sort, sort_semesters_list
|
||||
from .constants import APP_NRS, PROF_TITLES, SEMAP_MEDIA_ACCOUNTS
|
||||
from .csvparser import csv_to_list
|
||||
from .wordparser import elsa_word_to_csv, word_docx_to_csv
|
||||
|
||||
@@ -1,59 +1,86 @@
|
||||
from typing import List, Tuple
|
||||
|
||||
from natsort import natsorted
|
||||
|
||||
|
||||
def custom_sort(unsorted: List[Tuple[str, int, int]]) -> List[Tuple[str, int, int]]:
|
||||
"""Sort a list of semesters in the format "SoSe n" and "WiSe n/n+1" in the correct order.
|
||||
Where n == year in 2 digit format
|
||||
|
||||
Args:
|
||||
----
|
||||
unsorted (list[tuple]): List of semesters in the format "SoSe n" and "WiSe n/n+1"
|
||||
|
||||
Returns:
|
||||
-------
|
||||
ret (list[tuple]): Sorted list in correct order of WiSe n/n+1 and SoSe n
|
||||
def parse_semester(semester: str):
|
||||
"""
|
||||
summer = natsorted([i for i in unsorted if "SoSe" in i[0]])
|
||||
winter = natsorted([i for i in unsorted if "WiSe" in i[0]])
|
||||
summer = natsorted(summer, key=lambda x: x[0])
|
||||
winter = natsorted(winter, key=lambda x: x[0])
|
||||
Parses the semester string into a sortable format.
|
||||
Returns a tuple of (year, type), where type is 0 for SoSe and 1 for WiSe.
|
||||
"""
|
||||
if semester.startswith("SoSe"):
|
||||
return int(semester.split()[1]), 0
|
||||
elif semester.startswith("WiSe"):
|
||||
year_part = semester.split()[1]
|
||||
start_year, _ = map(int, year_part.split("/"))
|
||||
return start_year, 1
|
||||
else:
|
||||
raise ValueError(f"Invalid semester format: {semester}")
|
||||
|
||||
# Merge the lists
|
||||
ret = []
|
||||
i = 0
|
||||
j = 0
|
||||
while i < len(summer) and j < len(winter):
|
||||
if summer[i][0][5:] <= winter[j][0][5:]:
|
||||
ret.append(summer[i])
|
||||
i += 1
|
||||
|
||||
def custom_sort(entries):
|
||||
"""
|
||||
Sorts the list of tuples based on the custom schema.
|
||||
|
||||
:param entries: List of tuples in the format (str, int, int).
|
||||
:return: Sorted list of tuples.
|
||||
"""
|
||||
return sorted(
|
||||
entries,
|
||||
key=lambda entry: (
|
||||
parse_semester(entry[0]), # Sort by semester parsed as (year, type)
|
||||
entry[1], # Then by the second element of the tuple
|
||||
entry[2], # Finally by the third element of the tuple
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def parse_semester(semester: str):
|
||||
"""
|
||||
Parses the semester string into a sortable format.
|
||||
Returns a tuple of (year, type), where type is 0 for SoSe and 1 for WiSe.
|
||||
"""
|
||||
if semester.startswith("SoSe"):
|
||||
return int(semester.split()[1]), 0
|
||||
elif semester.startswith("WiSe"):
|
||||
year_part = semester.split()[1]
|
||||
if "/" in year_part:
|
||||
start_year, _ = map(int, year_part.split("/"))
|
||||
else:
|
||||
ret.append(winter[j])
|
||||
j += 1
|
||||
start_year = int(year_part)
|
||||
return start_year, 1
|
||||
else:
|
||||
raise ValueError(f"Invalid semester format: {semester}")
|
||||
|
||||
# Append the remaining items
|
||||
while i < len(summer):
|
||||
ret.append(summer[i])
|
||||
i += 1
|
||||
while j < len(winter):
|
||||
ret.append(winter[j])
|
||||
j += 1
|
||||
|
||||
return ret
|
||||
def sort_semesters_list(semesters: list) -> list:
|
||||
"""
|
||||
Sorts a list of semester strings based on year and type.
|
||||
|
||||
# Test the function
|
||||
|
||||
pass
|
||||
:param semesters: List of semester strings (e.g., "SoSe 24", "WiSe 22/23").
|
||||
:return: Sorted list of semester strings.
|
||||
"""
|
||||
return sorted(semesters, key=parse_semester)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unsorted = [
|
||||
("WiSe 23/24", 7, 5),
|
||||
("SoSe 23", 5, 0),
|
||||
("SoSe 22", 1, 0),
|
||||
("WiSe 22/23", 1, 0),
|
||||
("SoSe 15", 1, 0),
|
||||
"SoSe 24",
|
||||
"WiSe 22/23",
|
||||
"WiSe 23/24",
|
||||
"WiSe 20/21",
|
||||
"SoSe 23",
|
||||
"SoSe 20",
|
||||
"WiSe 7/8",
|
||||
"WiSe 14/15",
|
||||
"WiSe 13/14",
|
||||
"SoSe 8",
|
||||
"WiSe 19/20",
|
||||
"WiSe 12/13",
|
||||
"WiSe 21/22",
|
||||
"WiSe 18/19",
|
||||
"WiSe 11/12",
|
||||
"WiSe 9/10",
|
||||
"WiSe 6/7",
|
||||
"SoSe 7",
|
||||
"WiSe 16/17",
|
||||
"WiSe 24/25",
|
||||
"SoSe 25",
|
||||
]
|
||||
|
||||
# print(custom_sort(unsorted))
|
||||
print(sort_semesters_list(unsorted))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
from enum import Enum
|
||||
|
||||
APP_NRS = [i for i in range(1, 181)]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import csv
|
||||
|
||||
import chardet
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from enum import Enum
|
||||
|
||||
|
||||
@dataclass
|
||||
class Prof:
|
||||
id: int = None
|
||||
_title: str = None
|
||||
firstname: str= None
|
||||
lastname: str= None
|
||||
fullname: str= None
|
||||
mail: str= None
|
||||
telnr: str= None
|
||||
|
||||
#add function that sets the data based on a dict
|
||||
firstname: str = None
|
||||
lastname: str = None
|
||||
fullname: str = None
|
||||
mail: str = None
|
||||
telnr: str = None
|
||||
|
||||
# add function that sets the data based on a dict
|
||||
def from_dict(self, data: dict):
|
||||
for key, value in data.items():
|
||||
if hasattr(self, key):
|
||||
@@ -28,7 +30,8 @@ class Prof:
|
||||
@title.setter
|
||||
def title(self, value):
|
||||
self._title = value
|
||||
#add function that sets the data from a tuple
|
||||
|
||||
# add function that sets the data from a tuple
|
||||
def from_tuple(self, data: tuple):
|
||||
setattr(self, "id", data[0])
|
||||
setattr(self, "_title", data[1])
|
||||
@@ -40,40 +43,18 @@ class Prof:
|
||||
return self
|
||||
|
||||
def name(self, comma=False):
|
||||
if self.firstname is None and self.lastname is None:
|
||||
if "," in self.fullname:
|
||||
self.firstname = self.fullname.split(",")[1].strip()
|
||||
self.lastname = self.fullname.split(",")[0].strip()
|
||||
else:
|
||||
return self.fullname
|
||||
|
||||
if comma:
|
||||
return f"{self.lastname}, {self.firstname}"
|
||||
return f"{self.lastname} {self.firstname}"
|
||||
|
||||
|
||||
@dataclass
|
||||
class ApparatData:
|
||||
prof_title: str | None = None
|
||||
profname: str | None = None
|
||||
dauerapp: bool = False
|
||||
appnr: int | None = None
|
||||
appname: str | None = None
|
||||
app_fach: str | None = None
|
||||
semester: str | None = None
|
||||
erstellsemester: str | None = None
|
||||
prof_mail: str | None = None
|
||||
prof_tel: int | None = None
|
||||
deleted: int = 0
|
||||
prof_adis_id: int | None = None
|
||||
apparat_adis_id: int | None = None
|
||||
@property
|
||||
def prof_details(self) -> Prof:
|
||||
return Prof().from_dict({
|
||||
"title": self.prof_title,
|
||||
"firstname": self.profname.split(',')[1].strip(),
|
||||
"lastname": self.profname.split(',')[0].strip(),
|
||||
"mail": self.prof_mail,
|
||||
"telnr": self.prof_tel,
|
||||
"fullname": f"{self.profname.split(',')[0].strip()} {self.profname.split(',')[1].strip()}",
|
||||
})
|
||||
def translateToFullname(self):
|
||||
|
||||
return f"{self.profname.split(',')[0].strip()} {self.profname.split(',')[1].strip()}"
|
||||
|
||||
@dataclass
|
||||
class BookData:
|
||||
ppn: str | None = None
|
||||
@@ -132,7 +113,7 @@ class Subjects(Enum):
|
||||
FRENCH = (6, "Französisch")
|
||||
GEOGRAPHY = (7, "Geographie")
|
||||
HISTORY = (8, "Geschichte")
|
||||
HEALT_EDUCATION = (9, "Gesundheitspädagogik")
|
||||
HEALTH_EDUCATION = (9, "Gesundheitspädagogik")
|
||||
HTW = (10, "Haushalt / Textil")
|
||||
ART = (11, "Kunst")
|
||||
MATH_IT = (12, "Mathematik / Informatik")
|
||||
@@ -197,6 +178,13 @@ class Apparat:
|
||||
setattr(self, "konto", data[13])
|
||||
return self
|
||||
|
||||
@property
|
||||
def get_semester(self):
|
||||
if self.extend_until is not None:
|
||||
return self.extend_until
|
||||
else:
|
||||
return self.created_semester
|
||||
|
||||
|
||||
@dataclass
|
||||
class ELSA:
|
||||
@@ -211,3 +199,7 @@ class ELSA:
|
||||
setattr(self, "semester", data[2])
|
||||
setattr(self, "prof_id", data[3])
|
||||
return self
|
||||
@dataclass
|
||||
class ApparatData:
|
||||
prof: Prof = field(default_factory=Prof)
|
||||
apparat: Apparat = field(default_factory=Apparat)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import csv
|
||||
|
||||
import pandas as pd
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
import yaml
|
||||
|
||||
@@ -3,7 +3,7 @@ import sqlite3
|
||||
from PyQt6.QtCore import QThread
|
||||
from PyQt6.QtCore import pyqtSignal as Signal
|
||||
from src.backend.database import Database
|
||||
from src.logic.log import MyLogger
|
||||
|
||||
from src.logic.webrequest import BibTextTransformer, WebRequest
|
||||
|
||||
|
||||
@@ -16,8 +16,7 @@ class BookGrabber(QThread):
|
||||
def __init__(self, appnr):
|
||||
super(BookGrabber, self).__init__(parent=None)
|
||||
self.is_Running = True
|
||||
self.logger = MyLogger("Worker")
|
||||
self.logger.log_info("Starting worker thread")
|
||||
logger.info("Starting worker thread")
|
||||
self.data = None
|
||||
self.app_id = None
|
||||
self.prof_id = None
|
||||
@@ -35,9 +34,9 @@ class BookGrabber(QThread):
|
||||
self.data = data
|
||||
self.use_any = any_book
|
||||
self.use_exact = exact
|
||||
self.logger.log_info(f"Working on {len(self.data)} entries")
|
||||
logger.info(f"Working on {len(self.data)} entries")
|
||||
self.tstate = (self.app_id, self.prof_id, self.mode, self.data)
|
||||
self.logger.log_debug("State: " + str(self.tstate))
|
||||
logger.debug("State: " + str(self.tstate))
|
||||
# print(self.tstate)
|
||||
|
||||
def run(self):
|
||||
@@ -50,7 +49,7 @@ class BookGrabber(QThread):
|
||||
for entry in iterdata:
|
||||
# print(entry)
|
||||
signature = str(entry)
|
||||
self.logger.log_info("Processing entry: " + signature)
|
||||
logger.info("Processing entry: " + signature)
|
||||
|
||||
webdata = WebRequest().set_apparat(self.appnr).get_ppn(entry)
|
||||
if self.use_any:
|
||||
@@ -79,7 +78,7 @@ class BookGrabber(QThread):
|
||||
self.db.addBookToDatabase(bd, self.app_id, self.prof_id)
|
||||
# get latest book id
|
||||
self.book_id = self.db.getLastBookId()
|
||||
self.logger.log_info("Added book to database")
|
||||
logger.info("Added book to database")
|
||||
state = 0
|
||||
for result in transformer.RDS_DATA:
|
||||
# print(result.RDS_LOCATION)
|
||||
@@ -87,17 +86,17 @@ class BookGrabber(QThread):
|
||||
state = 1
|
||||
break
|
||||
|
||||
self.logger.log_info(f"State of {signature}: {state}")
|
||||
logger.info(f"State of {signature}: {state}")
|
||||
# print("updating availability of " + str(self.book_id) + " to " + str(state))
|
||||
try:
|
||||
self.db.setAvailability(self.book_id, state)
|
||||
except sqlite3.OperationalError as e:
|
||||
self.logger.log_error(f"Failed to update availability: {e}")
|
||||
logger.error(f"Failed to update availability: {e}")
|
||||
|
||||
# time.sleep(5)
|
||||
item += 1
|
||||
self.updateSignal.emit(item, len(self.data))
|
||||
self.logger.log_info("Worker thread finished")
|
||||
logger.info("Worker thread finished")
|
||||
# self.done.emit()
|
||||
self.quit()
|
||||
|
||||
@@ -111,17 +110,17 @@ class BookGrabber(QThread):
|
||||
# def __init__(self, app_id, prof_id, mode, data, parent=None):
|
||||
# super(BookGrabber, self).__init__(parent=None)
|
||||
# self.is_Running = True
|
||||
# self.logger = MyLogger("Worker")
|
||||
# self.logger.log_info("Starting worker thread")
|
||||
# logger = MyLogger("Worker")
|
||||
# logger.info("Starting worker thread")
|
||||
# self.data = data
|
||||
# self.logger.log_info(f"Working on {len(self.data)} entries")
|
||||
# logger.info(f"Working on {len(self.data)} entries")
|
||||
# self.app_id = app_id
|
||||
# self.prof_id = prof_id
|
||||
# self.mode = mode
|
||||
# self.book_id = None
|
||||
# self.state = (self.app_id, self.prof_id, self.mode, self.data)
|
||||
# # print(self.state)
|
||||
# self.logger.log_info("state: " + str(self.state))
|
||||
# logger.info("state: " + str(self.state))
|
||||
# # time.sleep(2)
|
||||
|
||||
# def resetValues(self):
|
||||
@@ -140,7 +139,7 @@ class BookGrabber(QThread):
|
||||
# for entry in iterdata:
|
||||
# # print(entry)
|
||||
# signature = str(entry)
|
||||
# self.logger.log_info("Processing entry: " + signature)
|
||||
# logger.info("Processing entry: " + signature)
|
||||
|
||||
# webdata = WebRequest().get_ppn(entry).get_data()
|
||||
# if webdata == "error":
|
||||
@@ -153,19 +152,19 @@ class BookGrabber(QThread):
|
||||
# self.db.addBookToDatabase(bd, self.app_id, self.prof_id)
|
||||
# # get latest book id
|
||||
# self.book_id = self.db.getLastBookId()
|
||||
# self.logger.log_info("Added book to database")
|
||||
# logger.info("Added book to database")
|
||||
# state = 0
|
||||
# # print(len(rds.items))
|
||||
# for rds_item in rds.items:
|
||||
# sign = rds_item.superlocation
|
||||
# loc = rds_item.location
|
||||
# # ic(sign, loc)
|
||||
# # ic(rds_item)
|
||||
# # logger.debug(sign, loc)
|
||||
# # logger.debug(rds_item)
|
||||
# if self.app_id in sign or self.app_id in loc:
|
||||
# state = 1
|
||||
# break
|
||||
|
||||
# self.logger.log_info(f"State of {signature}: {state}")
|
||||
# logger.info(f"State of {signature}: {state}")
|
||||
# # print(
|
||||
# "updating availability of "
|
||||
# + str(self.book_id)
|
||||
@@ -175,12 +174,12 @@ class BookGrabber(QThread):
|
||||
# try:
|
||||
# self.db.setAvailability(self.book_id, state)
|
||||
# except sqlite3.OperationalError as e:
|
||||
# self.logger.log_error(f"Failed to update availability: {e}")
|
||||
# logger.error(f"Failed to update availability: {e}")
|
||||
|
||||
# # time.sleep(5)
|
||||
# item += 1
|
||||
# self.updateSignal.emit(item, len(self.data))
|
||||
# self.logger.log_info("Worker thread finished")
|
||||
# logger.info("Worker thread finished")
|
||||
# # self.done.emit()
|
||||
# self.stop()
|
||||
# if not self.is_Running:
|
||||
|
||||
@@ -5,7 +5,7 @@ from PyQt6.QtCore import QThread
|
||||
from PyQt6.QtCore import pyqtSignal as Signal
|
||||
|
||||
from src.backend.database import Database
|
||||
from src.logic.log import MyLogger
|
||||
|
||||
|
||||
# from src.transformers import RDS_AVAIL_DATA
|
||||
|
||||
@@ -18,7 +18,6 @@ class AutoAdder(QThread):
|
||||
|
||||
def __init__(self, data=None, app_id=None, prof_id=None, parent=None):
|
||||
super().__init__(parent)
|
||||
self.logger = MyLogger("AutoAdder")
|
||||
self.data = data
|
||||
self.app_id = app_id
|
||||
self.prof_id = prof_id
|
||||
@@ -29,7 +28,7 @@ class AutoAdder(QThread):
|
||||
def run(self):
|
||||
self.db = Database()
|
||||
# show the dialog, start the thread to gather data and dynamically update progressbar and listwidget
|
||||
self.logger.log_info("Starting worker thread")
|
||||
logger.info("Starting worker thread")
|
||||
item = 0
|
||||
for entry in self.data:
|
||||
try:
|
||||
@@ -42,11 +41,11 @@ class AutoAdder(QThread):
|
||||
|
||||
except Exception as e:
|
||||
# print(e)
|
||||
self.logger.log_exception(
|
||||
logger.exception(
|
||||
f"The query failed with message {e} for signature {entry}"
|
||||
)
|
||||
continue
|
||||
if item == len(self.data):
|
||||
self.logger.log_info("Worker thread finished")
|
||||
logger.info("Worker thread finished")
|
||||
# teminate thread
|
||||
self.finished.emit()
|
||||
|
||||
@@ -5,7 +5,7 @@ from PyQt6.QtCore import QThread
|
||||
from PyQt6.QtCore import pyqtSignal as Signal
|
||||
|
||||
from src.backend.database import Database
|
||||
from src.logic.log import MyLogger
|
||||
|
||||
from src.logic.webrequest import BibTextTransformer, WebRequest
|
||||
|
||||
# from src.transformers import RDS_AVAIL_DATA
|
||||
@@ -21,9 +21,8 @@ class AvailChecker(QThread):
|
||||
if links is None:
|
||||
links = []
|
||||
super().__init__(parent)
|
||||
self.logger = MyLogger("AvailChecker")
|
||||
self.logger.log_info("Starting worker thread")
|
||||
self.logger.log_info(
|
||||
logger.info("Starting worker thread")
|
||||
logger.info(
|
||||
"Checking availability for "
|
||||
+ str(links)
|
||||
+ " with appnumber "
|
||||
@@ -33,7 +32,7 @@ class AvailChecker(QThread):
|
||||
self.links = links
|
||||
self.appnumber = appnumber
|
||||
self.books = books
|
||||
self.logger.log_info(
|
||||
logger.info(
|
||||
f"Started worker with appnumber: {self.appnumber} and links: {self.links} and {len(self.books)} books..."
|
||||
)
|
||||
time.sleep(2)
|
||||
@@ -43,7 +42,7 @@ class AvailChecker(QThread):
|
||||
state = 0
|
||||
count = 0
|
||||
for link in self.links:
|
||||
self.logger.log_info("Processing entry: " + str(link))
|
||||
logger.info("Processing entry: " + str(link))
|
||||
data = WebRequest().set_apparat(self.appnumber).get_ppn(link).get_data()
|
||||
transformer = BibTextTransformer("RDS")
|
||||
rds = transformer.get_data(data).return_data("rds_availability")
|
||||
@@ -60,14 +59,14 @@ class AvailChecker(QThread):
|
||||
if book["bookdata"].signature == link:
|
||||
book_id = book["id"]
|
||||
break
|
||||
self.logger.log_info(f"State of {link}: " + str(state))
|
||||
logger.info(f"State of {link}: " + str(state))
|
||||
# print("Updating availability of " + str(book_id) + " to " + str(state))
|
||||
self.db.setAvailability(book_id, state)
|
||||
count += 1
|
||||
self.updateProgress.emit(count, len(self.links))
|
||||
self.updateSignal.emit(item.callnumber, state)
|
||||
|
||||
self.logger.log_info("Worker thread finished")
|
||||
logger.info("Worker thread finished")
|
||||
# teminate thread
|
||||
|
||||
self.quit()
|
||||
|
||||
@@ -5,10 +5,9 @@ from bs4 import BeautifulSoup
|
||||
from ratelimit import limits, sleep_and_retry
|
||||
|
||||
from src.logic.dataclass import BookData
|
||||
from src.logic.log import MyLogger
|
||||
|
||||
from src.transformers import ARRAYData, BibTeXData, COinSData, RDSData, RISData
|
||||
|
||||
logger = MyLogger(__name__)
|
||||
|
||||
API_URL = "https://rds.ibs-bw.de/phfreiburg/opac/RDSIndexrecord/{}/"
|
||||
PPN_URL = "https://rds.ibs-bw.de/phfreiburg/opac/RDSIndex/Search?type0%5B%5D=allfields&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=au&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ti&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ct&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=isn&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=ta&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=co&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=py&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=pp&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=pu&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=si&lookfor0%5B%5D={}&join=AND&bool0%5B%5D=AND&type0%5B%5D=zr&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND&type0%5B%5D=cc&lookfor0%5B%5D=&join=AND&bool0%5B%5D=AND"
|
||||
@@ -37,19 +36,19 @@ class WebRequest:
|
||||
self.ppn = None
|
||||
self.data = None
|
||||
self.timeout = 5
|
||||
logger.log_info("Initialized WebRequest")
|
||||
logger.info("Initialized WebRequest")
|
||||
|
||||
@property
|
||||
def use_any_book(self):
|
||||
"""use any book that matches the search term"""
|
||||
self.use_any = True
|
||||
logger.log_info("Using any book")
|
||||
logger.info("Using any book")
|
||||
return self
|
||||
def set_apparat(self, apparat):
|
||||
self.apparat = apparat
|
||||
if int(self.apparat) < 10:
|
||||
self.apparat = f"0{self.apparat}"
|
||||
logger.log_info(f"Set apparat to {self.apparat}")
|
||||
logger.info(f"Set apparat to {self.apparat}")
|
||||
return self
|
||||
|
||||
def get_ppn(self, signature):
|
||||
@@ -81,7 +80,7 @@ class WebRequest:
|
||||
response = requests.get(link, timeout=self.timeout)
|
||||
return response.text
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.log_error(f"Request failed: {e}")
|
||||
logger.error(f"Request failed: {e}")
|
||||
return None
|
||||
def get_data(self):
|
||||
links = self.get_book_links(self.ppn)
|
||||
@@ -105,7 +104,7 @@ class WebRequest:
|
||||
return_data.append(data)
|
||||
return return_data
|
||||
else:
|
||||
logger.log_error("No <pre> tag found")
|
||||
logger.error("No <pre> tag found")
|
||||
raise ValueError("No <pre> tag found")
|
||||
if f"Semesterapparat-{self.apparat}" in item_location:
|
||||
pre_tag = soup.find_all("pre")
|
||||
@@ -116,7 +115,7 @@ class WebRequest:
|
||||
return_data.append(data)
|
||||
return return_data
|
||||
else:
|
||||
logger.log_error("No <pre> tag found")
|
||||
logger.error("No <pre> tag found")
|
||||
return return_data
|
||||
|
||||
def get_data_elsa(self):
|
||||
@@ -137,7 +136,7 @@ class WebRequest:
|
||||
return_data.append(data)
|
||||
return return_data
|
||||
else:
|
||||
logger.log_error("No <pre> tag found")
|
||||
logger.error("No <pre> tag found")
|
||||
return return_data
|
||||
|
||||
|
||||
@@ -155,7 +154,7 @@ class BibTextTransformer:
|
||||
self.field = None
|
||||
self.signature = None
|
||||
if mode not in self.valid_modes:
|
||||
logger.log_error(f"Mode {mode} not valid")
|
||||
logger.error(f"Mode {mode} not valid")
|
||||
raise ValueError(f"Mode {mode} not valid")
|
||||
self.data = None
|
||||
# self.bookdata = BookData(**self.data)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import pandas as pd
|
||||
from docx import Document
|
||||
import re
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
from pyzotero import zotero
|
||||
from dataclasses import dataclass
|
||||
from src.logic.webrequest import WebRequest, BibTextTransformer
|
||||
|
||||
122
src/transformers/schemas.py
Normal file
122
src/transformers/schemas.py
Normal file
@@ -0,0 +1,122 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Optional, Any, List
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import field as dataclass_field
|
||||
import json
|
||||
|
||||
|
||||
@dataclass
|
||||
class Item:
|
||||
superlocation: str | None = dataclass_field(default_factory=str)
|
||||
status: str | None = dataclass_field(default_factory=str)
|
||||
availability: str | None = dataclass_field(default_factory=str)
|
||||
notes: str | None = dataclass_field(default_factory=str)
|
||||
limitation: str | None = dataclass_field(default_factory=str)
|
||||
duedate: str | None = dataclass_field(default_factory=str)
|
||||
id: str | None = dataclass_field(default_factory=str)
|
||||
item_id: str | None = dataclass_field(default_factory=str)
|
||||
ilslink: str | None = dataclass_field(default_factory=str)
|
||||
number: int | None = dataclass_field(default_factory=int)
|
||||
barcode: str | None = dataclass_field(default_factory=str)
|
||||
reserve: str | None = dataclass_field(default_factory=str)
|
||||
callnumber: str | None = dataclass_field(default_factory=str)
|
||||
department: str | None = dataclass_field(default_factory=str)
|
||||
locationhref: str | None = dataclass_field(default_factory=str)
|
||||
location: str | None = dataclass_field(default_factory=str)
|
||||
|
||||
def from_dict(self, data: dict):
|
||||
"""Import data from dict"""
|
||||
data = data["items"]
|
||||
for entry in data:
|
||||
for key, value in entry.items():
|
||||
setattr(self, key, value)
|
||||
return self
|
||||
|
||||
|
||||
@dataclass
|
||||
class RDS_AVAIL_DATA:
|
||||
"""Class to store RDS availability data"""
|
||||
|
||||
library_sigil: str = dataclass_field(default_factory=str)
|
||||
items: List[Item] = dataclass_field(default_factory=list)
|
||||
|
||||
def import_from_dict(self, data: str):
|
||||
"""Import data from dict"""
|
||||
edata = json.loads(data)
|
||||
# library sigil is first key
|
||||
|
||||
self.library_sigil = str(list(edata.keys())[0])
|
||||
# get data from first key
|
||||
edata = edata[self.library_sigil]
|
||||
for location in edata:
|
||||
item = Item(superlocation=location).from_dict(edata[location])
|
||||
|
||||
self.items.append(item)
|
||||
return self
|
||||
|
||||
|
||||
@dataclass
|
||||
class RDS_DATA:
|
||||
"""Class to store RDS data"""
|
||||
|
||||
RDS_SIGNATURE: str = dataclass_field(default_factory=str)
|
||||
RDS_STATUS: str = dataclass_field(default_factory=str)
|
||||
RDS_LOCATION: str = dataclass_field(default_factory=str)
|
||||
RDS_URL: Any = dataclass_field(default_factory=str)
|
||||
RDS_HINT: Any = dataclass_field(default_factory=str)
|
||||
RDS_COMMENT: Any = dataclass_field(default_factory=str)
|
||||
RDS_HOLDING: Any = dataclass_field(default_factory=str)
|
||||
RDS_HOLDING_LEAK: Any = dataclass_field(default_factory=str)
|
||||
RDS_INTERN: Any = dataclass_field(default_factory=str)
|
||||
RDS_PROVENIENCE: Any = dataclass_field(default_factory=str)
|
||||
RDS_LOCAL_NOTATION: str = dataclass_field(default_factory=str)
|
||||
RDS_LEA: Any = dataclass_field(default_factory=str)
|
||||
|
||||
def import_from_dict(self, data: dict) -> RDS_DATA:
|
||||
"""Import data from dict"""
|
||||
for key, value in data.items():
|
||||
setattr(self, key, value)
|
||||
return self
|
||||
|
||||
|
||||
@dataclass
|
||||
class RDS_GENERIC_DATA:
|
||||
LibrarySigil: str = dataclass_field(default_factory=str)
|
||||
RDS_DATA: List[RDS_DATA] = dataclass_field(default_factory=list)
|
||||
|
||||
def import_from_dict(self, data: str) -> RDS_GENERIC_DATA:
|
||||
"""Import data from dict"""
|
||||
edata = json.loads(data)
|
||||
# library sigil is first key
|
||||
self.LibrarySigil = str(list(edata.keys())[0])
|
||||
# get data from first key
|
||||
edata = edata[self.LibrarySigil]
|
||||
for entry in edata:
|
||||
rds_data = RDS_DATA() # Create a new RDS_DATA instance
|
||||
# Populate the RDS_DATA instance from the entry
|
||||
# This assumes that the entry is a dictionary that matches the structure of the RDS_DATA class
|
||||
rds_data.import_from_dict(entry)
|
||||
self.RDS_DATA.append(rds_data) # Add the RDS_DATA instance to the list
|
||||
return self
|
||||
|
||||
|
||||
@dataclass
|
||||
class LoksatzData:
|
||||
type: Optional[str] = None
|
||||
adis_idn: Optional[str] = None
|
||||
t_idn: Optional[str] = None
|
||||
ktrl_nr: Optional[str] = None
|
||||
adis_isil: Optional[str] = None
|
||||
adis_sigel: Optional[str] = None
|
||||
bib_sigel: Optional[str] = None
|
||||
standort: Optional[str] = None
|
||||
signatur: Optional[str] = None
|
||||
ausleihcode: Optional[str] = None
|
||||
sig_katalog: Optional[str] = None
|
||||
erwerb_datum: Optional[str] = None
|
||||
medientypcode: Optional[str] = None
|
||||
bestellart: Optional[str] = None
|
||||
faecherstatistik: Optional[str] = None
|
||||
exemplar_stat: Optional[str] = None
|
||||
so_standort: Optional[str] = None
|
||||
@@ -8,10 +8,8 @@ from typing import Any, List, Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from src.logic.dataclass import BookData
|
||||
from src.logic.log import MyLogger
|
||||
|
||||
logger = MyLogger("transformers.py")
|
||||
from src.logic.dataclass import BookData
|
||||
|
||||
|
||||
###Pydatnic models
|
||||
@@ -135,7 +133,7 @@ class ARRAYData:
|
||||
|
||||
except Exception:
|
||||
# # print(f"ARRAYData.transform failed, {source}, {search}")
|
||||
logger.log_exception(f"ARRAYData.transform failed, no string {search}")
|
||||
logger.exception(f"ARRAYData.transform failed, no string {search}")
|
||||
return ""
|
||||
|
||||
def _get_list_entry(source: str, search: str, entry: str) -> str:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import pathlib
|
||||
|
||||
from .Ui_semesterapparat_ui import Ui_MainWindow as Ui_Semesterapparat
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
from .bookdata import BookDataUI as edit_bookdata_ui
|
||||
from .login import LoginDialog as login_ui
|
||||
from .mail import Mail_Dialog
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
from .dialog_sources.Ui_about import Ui_about
|
||||
from PyQt6 import QtWidgets
|
||||
from PyQt6.QtCore import PYQT_VERSION_STR
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
|
||||
from PyQt6 import QtWidgets
|
||||
from .dialog_sources.Ui_apparat_extend import Ui_Dialog
|
||||
from src import Icon
|
||||
from src.backend import generateSemesterByDate, generateSemesterByOffset
|
||||
from src.backend import Semester
|
||||
class ApparatExtendDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
def __init__(
|
||||
self,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
from PyQt6 import QtCore, QtWidgets
|
||||
|
||||
from src.logic.dataclass import BookData
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
from .dialog_sources.Ui_confirm_extend import Ui_extend_confirm
|
||||
from PyQt6 import QtWidgets
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\about.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.6.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\app_status.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.6.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\apparat_extend.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.7.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\confirm_extend.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.7.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\edit_bookdata.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.6.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_add_table_entry.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.7.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_generate_citation.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.6.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\elsa_generator_confirm.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.6.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\login.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.6.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\mail_preview.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.7.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\medianadder.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.7.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\newMailTemplateDesigner.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.6.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\parsed_titles.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.6.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\reminder.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.6.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\dialogs\dialog_sources\settings.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.7.1
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
|
||||
from .dialog_sources.Ui_elsa_add_table_entry import Ui_Dialog
|
||||
from src.logic.webrequest import WebRequest, BibTextTransformer
|
||||
from src import Icon
|
||||
from PyQt6 import QtWidgets
|
||||
from src.transformers.transformers import DictToTable
|
||||
from src.logic.zotero import ZoteroController
|
||||
from icecream import ic
|
||||
|
||||
zot = ZoteroController()
|
||||
dtt = DictToTable()
|
||||
@@ -117,7 +117,7 @@ class ElsaAddEntry(QtWidgets.QDialog, Ui_Dialog):
|
||||
if table["type"] == "zs":
|
||||
book = zot.createBook(table["isbn"])
|
||||
res_key = zot.createJournalArticle(book, table)
|
||||
ic(book)
|
||||
logger.debug(book)
|
||||
a_lastname = table["section_author"].split(";")[0].strip().split(",")[0]
|
||||
a_firstname = table["section_author"].split(";")[0].strip().split(",")[1]
|
||||
author = f"{a_lastname}, {a_firstname[0]}"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
from .dialog_sources.Ui_elsa_generate_citation import Ui_Dialog
|
||||
from PyQt6 import QtWidgets
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
from .dialog_sources.Ui_elsa_generator_confirm import Ui_Dialog
|
||||
from PyQt6 import QtCore, QtWidgets, QtGui
|
||||
|
||||
|
||||
@@ -2,16 +2,15 @@ import hashlib
|
||||
|
||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from src import Icon
|
||||
from src import Icon, logger
|
||||
from src.backend.admin_console import AdminCommands
|
||||
from src.backend.database import Database
|
||||
|
||||
from .dialog_sources.Ui_login import Ui_Dialog
|
||||
from src import MyLogger
|
||||
|
||||
|
||||
class LoginDialog(Ui_Dialog):
|
||||
def setupUi(self, Dialog):
|
||||
self.log = MyLogger("Login")
|
||||
Dialog.setObjectName("Dialog")
|
||||
Dialog.resize(218, 190)
|
||||
self.dialog = Dialog
|
||||
@@ -76,16 +75,20 @@ class LoginDialog(Ui_Dialog):
|
||||
if self.db.login(username, hashed_password):
|
||||
self.lresult = 1 # Indicate successful login
|
||||
self.lusername = username
|
||||
logger.success(f"User {username} logged in.")
|
||||
self.dialog.accept()
|
||||
|
||||
else:
|
||||
# Credentials are invalid, display a warning
|
||||
if username == "" or password == "":
|
||||
logger.warning("Invalid username or password. Login failed.")
|
||||
warning_dialog = QtWidgets.QMessageBox()
|
||||
warning_dialog.setIcon(QtWidgets.QMessageBox.Icon.Warning)
|
||||
warning_dialog.setText("Please enter a username and password.")
|
||||
warning_dialog.setWindowTitle("Login Failed")
|
||||
warning_dialog.exec()
|
||||
else:
|
||||
logger.warning("Invalid username or password. Login failed.")
|
||||
warning_dialog = QtWidgets.QMessageBox()
|
||||
warning_dialog.setIcon(QtWidgets.QMessageBox.Icon.Warning)
|
||||
warning_dialog.setText(
|
||||
|
||||
@@ -4,14 +4,12 @@ import sys
|
||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
from src import Icon, settings as config
|
||||
from src.logic.log import MyLogger
|
||||
|
||||
|
||||
from .dialog_sources.Ui_mail_preview import Ui_eMailPreview as MailPreviewDialog
|
||||
from .mailTemplate import MailTemplateDialog
|
||||
|
||||
|
||||
logger = MyLogger("Mail")
|
||||
|
||||
empty_signature = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
|
||||
<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style
|
||||
@@ -52,7 +50,7 @@ class Mail_Dialog(QtWidgets.QDialog, MailPreviewDialog):
|
||||
# prof_name,
|
||||
)
|
||||
|
||||
logger.log_info("Setting up mail dialog")
|
||||
logger.info("Setting up mail dialog")
|
||||
self.appid = app_id
|
||||
self.appname = app_name
|
||||
self.subject = app_subject
|
||||
@@ -84,7 +82,7 @@ class Mail_Dialog(QtWidgets.QDialog, MailPreviewDialog):
|
||||
self.btn_okay.clicked.connect(self.createAndSendMail)
|
||||
|
||||
def open_new_template(self):
|
||||
logger.log_info("Opening new template dialog")
|
||||
logger.info("Opening new template dialog")
|
||||
# TODO: implement new mail template dialog
|
||||
dialog = MailTemplateDialog()
|
||||
dialog.exec()
|
||||
@@ -101,9 +99,9 @@ Tel.: 0761/682-778 | 07617682-545"""
|
||||
|
||||
def load_mail_templates(self):
|
||||
# print("loading mail templates")
|
||||
logger.log_info("Loading mail templates")
|
||||
logger.info("Loading mail templates")
|
||||
mail_templates = os.listdir("mail_vorlagen")
|
||||
logger.log_info(f"Mail templates: {mail_templates}")
|
||||
logger.info(f"Mail templates: {mail_templates}")
|
||||
for template in mail_templates:
|
||||
self.comboBox.addItem(template)
|
||||
|
||||
@@ -121,10 +119,10 @@ Tel.: 0761/682-778 | 07617682-545"""
|
||||
return f"Guten Tag {name},"
|
||||
|
||||
def set_mail(self):
|
||||
logger.log_info("Setting mail")
|
||||
logger.info("Setting mail")
|
||||
email_template = self.comboBox.currentText()
|
||||
if email_template == "":
|
||||
logger.log_debug("No mail template selected")
|
||||
logger.debug("No mail template selected")
|
||||
return
|
||||
with open(f"mail_vorlagen/{email_template}", "r", encoding="utf-8") as f:
|
||||
mail_template = f.read()
|
||||
@@ -147,10 +145,10 @@ Tel.: 0761/682-778 | 07617682-545"""
|
||||
)
|
||||
|
||||
self.mail_body.setHtml(mail_html)
|
||||
logger.log_info(f"Mail template set to {email_template}")
|
||||
logger.info(f"Mail template set to {email_template}")
|
||||
|
||||
def createAndSendMail(self):
|
||||
logger.log_info("Sending mail")
|
||||
logger.info("Sending mail")
|
||||
import smtplib
|
||||
import ssl
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
@@ -188,7 +186,7 @@ Tel.: 0761/682-778 | 07617682-545"""
|
||||
# print("Mail sent")
|
||||
# end active process
|
||||
server.quit()
|
||||
logger.log_info("Mail sent, closing connection to server and dialog")
|
||||
logger.info("Mail sent, closing connection to server and dialog")
|
||||
# close the dialog
|
||||
|
||||
self.accept()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import os
|
||||
|
||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'ui\dialogs\mail_preview.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.3.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
from src import MyLogger
|
||||
|
||||
from .dialog_sources.Ui_medianadder import Ui_Dialog
|
||||
from src import Icon
|
||||
class MedienAdder(QtWidgets.QDialog, Ui_Dialog):
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file '/home/alexander/GitHub/Semesterapparate/ui/dialogs/new_subject.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.5.3
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
from PyQt6 import QtCore, QtWidgets
|
||||
|
||||
from src.logic import AutoAdder
|
||||
from src.logic.log import MyLogger
|
||||
|
||||
|
||||
from .dialog_sources.Ui_parsed_titles import Ui_Form
|
||||
|
||||
logger = MyLogger("AutoTitleAdder")
|
||||
|
||||
|
||||
class ParsedTitles(QtWidgets.QWidget, Ui_Form):
|
||||
def __init__(self, parent=None):
|
||||
@@ -35,7 +33,7 @@ class ParsedTitles(QtWidgets.QWidget, Ui_Form):
|
||||
self.worker = None
|
||||
|
||||
def start(self):
|
||||
logger.log_info("Starting AutoAdder")
|
||||
logger.info("Starting AutoAdder")
|
||||
|
||||
self.worker = AutoAdder(
|
||||
data=self.signatures,
|
||||
@@ -54,8 +52,8 @@ class ParsedTitles(QtWidgets.QWidget, Ui_Form):
|
||||
self.worker.start()
|
||||
|
||||
def on_completion(self):
|
||||
logger.log_info("AutoAdder finished")
|
||||
logger.log_info("Returning data")
|
||||
logger.info("AutoAdder finished")
|
||||
logger.info("Returning data")
|
||||
|
||||
# create a function that closes the dialog
|
||||
|
||||
@@ -64,7 +62,7 @@ class ParsedTitles(QtWidgets.QWidget, Ui_Form):
|
||||
length = self.listWidget.count()
|
||||
# print(f"Length of listWidget: {length}")
|
||||
if length == 0:
|
||||
logger.log_info("AutoAdder finished")
|
||||
logger.info("AutoAdder finished")
|
||||
self.buttonBox.accepted.emit()
|
||||
|
||||
def update_lists(self, signal):
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file '/home/alexander/GitHub/Semesterapparate/ui/dialogs/parsed_titles.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.5.3
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'ui\dialogs\confirm_extend.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.3.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
from PyQt6 import QtWidgets
|
||||
|
||||
from .dialog_sources.Ui_reminder import Ui_Erinnerung as Ui_Dialog
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
from src import Icon, settings
|
||||
from .dialog_sources.Ui_settings import Ui_Dialog as _settings
|
||||
|
||||
@@ -7,16 +7,15 @@ import tempfile
|
||||
import webbrowser
|
||||
from pathlib import Path
|
||||
|
||||
from icecream import ic
|
||||
from natsort import natsorted
|
||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
from PyQt6.QtCore import QThread
|
||||
from PyQt6.QtGui import QRegularExpressionValidator
|
||||
|
||||
from src import Icon, settings
|
||||
from src import Icon, settings, logger
|
||||
from src.backend import (
|
||||
Database,
|
||||
generateSemesterByDate,
|
||||
Semester,
|
||||
recreateFile,
|
||||
tempdelete,
|
||||
)
|
||||
@@ -27,9 +26,10 @@ from src.logic import (
|
||||
AvailChecker,
|
||||
BookData,
|
||||
BookGrabber,
|
||||
MyLogger,
|
||||
csv_to_list,
|
||||
word_docx_to_csv,
|
||||
Prof,
|
||||
Apparat,
|
||||
)
|
||||
from src.ui import (
|
||||
About,
|
||||
@@ -50,7 +50,7 @@ from src.ui import (
|
||||
ElsaDialog,
|
||||
UserCreate,
|
||||
EditUser,
|
||||
EditProf
|
||||
EditProf,
|
||||
)
|
||||
from src.utils import SemesterDocument
|
||||
|
||||
@@ -60,8 +60,7 @@ valid_input = (0, 0, 0, 0, 0, 0)
|
||||
class Ui(Ui_Semesterapparat):
|
||||
# use the Ui_MainWindow class from mainwindow.py
|
||||
def __init__(self, MainWindow, username: str) -> None:
|
||||
self.logger = MyLogger("Ui")
|
||||
self.logger.log_info("Starting Semesterapparatsmanagement")
|
||||
logger.info("Starting Semesterapparatsmanagement")
|
||||
super().__init__()
|
||||
self.active_user = username
|
||||
self.setupUi(MainWindow)
|
||||
@@ -172,7 +171,6 @@ class Ui(Ui_Semesterapparat):
|
||||
self.app_group_box.setEnabled(False)
|
||||
self.line_2.hide()
|
||||
self.progress_label.hide()
|
||||
# self.message_frame.hide()
|
||||
self.btn_reserve.hide()
|
||||
self.label_20.hide()
|
||||
self.line_3.hide()
|
||||
@@ -247,7 +245,7 @@ class Ui(Ui_Semesterapparat):
|
||||
apps.append(data)
|
||||
print(apps)
|
||||
doc = SemesterDocument(
|
||||
semester=self.generateSemester(today=True),
|
||||
semester=Semester(),
|
||||
filename="Semesterapparate",
|
||||
apparats=apps,
|
||||
)
|
||||
@@ -372,14 +370,12 @@ class Ui(Ui_Semesterapparat):
|
||||
"""Generates the current semester.
|
||||
|
||||
Args:
|
||||
-----
|
||||
today (bool, optional): If True, the current semester is generated. Defaults to False.
|
||||
Returns:
|
||||
--------
|
||||
str: The current semester
|
||||
"""
|
||||
if today:
|
||||
return generateSemesterByDate()
|
||||
return Semester()
|
||||
currentYear = self.sem_year.text()
|
||||
currentYear = int(currentYear[-2:])
|
||||
|
||||
@@ -387,7 +383,7 @@ class Ui(Ui_Semesterapparat):
|
||||
if semester == "SoSe":
|
||||
return "SoSe " + str(currentYear)
|
||||
else:
|
||||
return f"WiSe {currentYear}/{currentYear+1}"
|
||||
return f"WiSe {currentYear}/{currentYear + 1}"
|
||||
|
||||
def open_apparat(self, apparat):
|
||||
if self.load_app_data(apparat):
|
||||
@@ -402,41 +398,29 @@ class Ui(Ui_Semesterapparat):
|
||||
|
||||
def populate_frame(self, appdata: ApparatData):
|
||||
# populate the frame with the data from the database
|
||||
self.drpdwn_app_nr.setCurrentText(str(appdata.appnr))
|
||||
self.prof_title.setText(appdata.prof_title)
|
||||
prof_name = appdata.profname.split(" ")
|
||||
if len(prof_name) > 2:
|
||||
fname = " ".join(prof_name[1:])
|
||||
lname = prof_name[0]
|
||||
prof_name = f"{lname}, {fname}"
|
||||
else:
|
||||
prof_name = ", ".join(prof_name)
|
||||
self.drpdwn_app_nr.setCurrentText(str(appdata.apparat.appnr))
|
||||
self.prof_title.setText(appdata.prof.title)
|
||||
prof_name = appdata.prof.name(True)
|
||||
|
||||
self.drpdwn_prof_name.setCurrentText(prof_name)
|
||||
self.prof_mail.setText(appdata.prof_mail)
|
||||
self.prof_tel_nr.setText(appdata.prof_tel)
|
||||
self.app_name.setText(appdata.appname)
|
||||
self.prof_mail.setText(appdata.prof.mail)
|
||||
self.prof_tel_nr.setText(appdata.prof.telnr)
|
||||
self.app_name.setText(appdata.apparat.name)
|
||||
# print("changing dropdown app_fach from '' to ", appdata.app_fach)
|
||||
self.app_fach.setCurrentText(appdata.app_fach)
|
||||
self.app_fach.setCurrentText(appdata.apparat.subject)
|
||||
# print("changed dropdown app_fach to ", self.app_fach.currentText())
|
||||
if appdata.semester is not None:
|
||||
self.sem_sommer.setChecked(
|
||||
True if appdata.semester.split(" ")[0] == "SoSe" else False
|
||||
)
|
||||
self.sem_winter.setChecked(
|
||||
True if appdata.semester.split(" ")[0] == "WiSe" else False
|
||||
)
|
||||
self.sem_year.setText(appdata.semester.split(" ")[1])
|
||||
else:
|
||||
self.sem_sommer.setChecked(
|
||||
True if appdata.erstellsemester.split(" ")[0] == "SoSe" else False
|
||||
)
|
||||
self.sem_winter.setChecked(
|
||||
True if appdata.erstellsemester.split(" ")[0] == "WiSe" else False
|
||||
)
|
||||
self.sem_year.setText(appdata.erstellsemester.split(" ")[1])
|
||||
self.check_eternal_app.setChecked(appdata.dauerapp)
|
||||
self.prof_id_adis.setText(str(appdata.prof_adis_id))
|
||||
self.apparat_id_adis.setText(str(appdata.apparat_adis_id))
|
||||
self.sem_year.setText(appdata.apparat.get_semester.split(" ")[1])
|
||||
match appdata.apparat.get_semester.split(" ")[0]:
|
||||
case "SoSe":
|
||||
self.sem_sommer.setChecked(True)
|
||||
self.sem_winter.setChecked(False)
|
||||
case "WiSe":
|
||||
self.sem_sommer.setChecked(False)
|
||||
self.sem_winter.setChecked(True)
|
||||
|
||||
self.check_eternal_app.setChecked(appdata.apparat.eternal)
|
||||
self.prof_id_adis.setText(str(appdata.apparat.prof_id_adis))
|
||||
self.apparat_id_adis.setText(str(appdata.apparat.apparat_id_adis))
|
||||
self.app_group_box.setEnabled(True)
|
||||
self.validateLoadedData()
|
||||
|
||||
@@ -449,25 +433,26 @@ class Ui(Ui_Semesterapparat):
|
||||
self.validate_semester()
|
||||
|
||||
def update_apparat(self):
|
||||
appdata = ApparatData()
|
||||
appdata.app_fach = self.app_fach.currentText()
|
||||
appdata.appname = self.app_name.text()
|
||||
appdata.appnr = self.active_apparat
|
||||
appdata.dauerapp = self.check_eternal_app.isChecked()
|
||||
appdata.prof_mail = self.prof_mail.text()
|
||||
appdata.prof_tel = self.prof_tel_nr.text()
|
||||
appdata.prof_title = self.prof_title.text()
|
||||
appdata.profname = self.drpdwn_prof_name.currentText()
|
||||
appdata.semester = (
|
||||
prof = Prof()
|
||||
app = Apparat()
|
||||
app.subject = self.app_fach.currentText()
|
||||
app.name = self.app_name.text()
|
||||
app.appnr = self.active_apparat
|
||||
app.eternal = self.check_eternal_app.isChecked()
|
||||
prof.mail = self.prof_mail.text()
|
||||
prof.telnr = self.prof_tel_nr.text()
|
||||
prof.title = self.prof_title.text()
|
||||
prof.fullname = self.drpdwn_prof_name.currentText().replace(",", "")
|
||||
app.created_semester = (
|
||||
self.sem_sommer.text() + " " + self.sem_year.text()
|
||||
if self.sem_sommer.isChecked()
|
||||
else self.sem_winter.text() + " " + self.sem_year.text()
|
||||
)
|
||||
appdata.prof_adis_id = self.prof_id_adis.text()
|
||||
prof_id = self.db.getProfByName(appdata.prof_details.fullname).id
|
||||
app.prof_id_adis = self.prof_id_adis.text()
|
||||
prof_id = self.db.getProfByName(prof.fullname).id
|
||||
self.add_files(prof_id)
|
||||
appdata.apparat_adis_id = self.apparat_id_adis.text()
|
||||
|
||||
app.apparat_id_adis = self.apparat_id_adis.text()
|
||||
appdata = ApparatData(prof=prof, apparat=app)
|
||||
self.db.updateApparat(appdata)
|
||||
|
||||
self.update_app_media_list()
|
||||
@@ -597,7 +582,7 @@ class Ui(Ui_Semesterapparat):
|
||||
return
|
||||
selected_prof = self.drpdwn_prof_name.currentText()
|
||||
data = self.db.getProfData(selected_prof)
|
||||
# ic(data)
|
||||
# logger.debug(data)
|
||||
prof_title = data.title
|
||||
if prof_title == "None":
|
||||
prof_title = "Kein Titel"
|
||||
@@ -701,13 +686,13 @@ class Ui(Ui_Semesterapparat):
|
||||
|
||||
def update_progress_label(self, curr, total):
|
||||
text = f"Medium {curr}/{total}"
|
||||
self.logger.log_info(text)
|
||||
logger.info(text)
|
||||
self.progress_label.setText(text)
|
||||
# update tableWidget_apparat_media
|
||||
self.update_app_media_list()
|
||||
|
||||
def hide_progress_label(self):
|
||||
self.logger.log_info("Finished adding media, hiding progress label")
|
||||
logger.info("Finished adding media, hiding progress label")
|
||||
self.progress_label.hide()
|
||||
self.progress_label.setText("Bitte warten...")
|
||||
self.line_2.hide()
|
||||
@@ -734,7 +719,7 @@ class Ui(Ui_Semesterapparat):
|
||||
|
||||
app_id = self.active_apparat
|
||||
prof_id = self.db.getProfId(self.profdata)
|
||||
ic(prof_id)
|
||||
logger.debug(prof_id)
|
||||
# check if app_id is in database
|
||||
if self.db.checkApparatExistsById(app_id) is False:
|
||||
# create apparat
|
||||
@@ -1066,7 +1051,7 @@ class Ui(Ui_Semesterapparat):
|
||||
data = __open_dialog(signatures)
|
||||
# add the data to the database
|
||||
for book in data:
|
||||
if type(book) != BookData:
|
||||
if not isinstance(book, BookData):
|
||||
continue
|
||||
self.db.addBookToDatabase(
|
||||
bookdata=book, app_id=app_id, prof_id=prof_id
|
||||
@@ -1083,7 +1068,7 @@ class Ui(Ui_Semesterapparat):
|
||||
if data == []:
|
||||
return
|
||||
for book in data:
|
||||
if type(book) != BookData:
|
||||
if not isinstance(book, BookData):
|
||||
continue
|
||||
self.db.addBookToDatabase(
|
||||
bookdata=book, app_id=app_id, prof_id=prof_id
|
||||
@@ -1099,10 +1084,10 @@ class Ui(Ui_Semesterapparat):
|
||||
"Bitte warten, bis alle Medien hinzugefügt wurden"
|
||||
)
|
||||
app_id = self.active_apparat
|
||||
ic(self.profdata)
|
||||
logger.debug(self.profdata)
|
||||
prof_id = self.db.getProfId(self.profdata)
|
||||
|
||||
ic(prof_id)
|
||||
logger.debug(prof_id)
|
||||
# check if apparat in database
|
||||
|
||||
# if app_id not in database, create apparat
|
||||
@@ -1110,7 +1095,7 @@ class Ui(Ui_Semesterapparat):
|
||||
if not self.db.checkApparatExistsById(app_id):
|
||||
# create apparat
|
||||
# print("Creating apparat")
|
||||
if self.btn_save_apparat(False) == False:
|
||||
if not self.btn_save_apparat(False):
|
||||
return
|
||||
created = True
|
||||
if self.dokument_list.rowCount() == 0:
|
||||
@@ -1155,7 +1140,7 @@ class Ui(Ui_Semesterapparat):
|
||||
]
|
||||
|
||||
signatures = [i for i in signatures if i != ""]
|
||||
# ic(signatures)
|
||||
# logger.debug(signatures)
|
||||
# print("starting thread")
|
||||
if prof_id is None:
|
||||
prof_id = self.db.getProfId(self.profdata)
|
||||
@@ -1218,23 +1203,29 @@ class Ui(Ui_Semesterapparat):
|
||||
if not self.validate_fields():
|
||||
self.confirm_popup("Bitte alle Pflichtfelder ausfüllen!", title="Fehler")
|
||||
return False
|
||||
appd = ApparatData()
|
||||
appd.appnr = self.active_apparat
|
||||
appd.prof_title = self.prof_title.text()
|
||||
appd.profname = self.drpdwn_prof_name.currentText()
|
||||
appd.appname = self.app_name.text()
|
||||
appd.semester = self.generateSemester()
|
||||
appd.dauerapp = 1 if self.check_eternal_app.isChecked() else 0
|
||||
appd.prof_tel = self.prof_tel_nr.text()
|
||||
appd.prof_mail = self.prof_mail.text()
|
||||
appd.app_fach = self.app_fach.currentText()
|
||||
appd.erstellsemester = self.generateSemester()
|
||||
appd.deleted = 0
|
||||
appd.prof_adis_id = self.prof_id_adis.text()
|
||||
appd.apparat_adis_id = self.apparat_id_adis.text()
|
||||
prof = Prof(
|
||||
fullname=self.drpdwn_prof_name.currentText(),
|
||||
telnr=self.prof_tel_nr.text(),
|
||||
mail=self.prof_mail.text(),
|
||||
)
|
||||
prof.title = self.prof_title.text()
|
||||
apparat = Apparat(
|
||||
appnr=self.active_apparat,
|
||||
name=self.app_name.text(),
|
||||
created_semester=self.generateSemester(),
|
||||
eternal=1 if self.check_eternal_app.isChecked() else 0,
|
||||
subject=self.app_fach.currentText(),
|
||||
deleted=0,
|
||||
prof_id_adis=self.prof_id_adis.text(),
|
||||
apparat_id_adis=self.apparat_id_adis.text(),
|
||||
)
|
||||
|
||||
appd = ApparatData(prof=prof, apparat=apparat)
|
||||
|
||||
error = self.db.createApparat(appd)
|
||||
|
||||
if error:
|
||||
self.confirm_popup(error.__str__(), title="Fehler")
|
||||
return False
|
||||
if self.dokument_list.rowCount() > 0:
|
||||
self.add_files()
|
||||
if error is not None:
|
||||
@@ -1251,15 +1242,16 @@ class Ui(Ui_Semesterapparat):
|
||||
|
||||
if self.check_send_mail.isChecked():
|
||||
self.contact_prof(
|
||||
apparat=appd.appnr,
|
||||
apparat=appd.apparat.appnr,
|
||||
mail="Information zum Semesterapparat",
|
||||
location="",
|
||||
pid=appd.profname,
|
||||
pid=appd.prof.fullname,
|
||||
)
|
||||
if clear_fields:
|
||||
# print("clearing fields")
|
||||
self.__clear_fields()
|
||||
return True
|
||||
|
||||
def send_mail_preview(self):
|
||||
pass
|
||||
|
||||
@@ -1270,12 +1262,12 @@ class Ui(Ui_Semesterapparat):
|
||||
@property
|
||||
def profdata(self):
|
||||
return {
|
||||
"title":self.prof_title.text(),
|
||||
"title": self.prof_title.text(),
|
||||
"profname": self.drpdwn_prof_name.currentText(),
|
||||
"prof_mail":self.prof_mail.text(),
|
||||
"prof_tel":self.prof_tel_nr.text()
|
||||
"prof_mail": self.prof_mail.text(),
|
||||
"prof_tel": self.prof_tel_nr.text(),
|
||||
}
|
||||
|
||||
|
||||
def add_files(self, prof_id=None):
|
||||
files = []
|
||||
for i in range(self.dokument_list.rowCount()):
|
||||
@@ -1304,12 +1296,13 @@ class Ui(Ui_Semesterapparat):
|
||||
|
||||
def update_apparat_list(self):
|
||||
self.tableWidget_apparate.setRowCount(0)
|
||||
|
||||
|
||||
for apparat in self.apparats:
|
||||
self.insert_apparat_into_table(apparat)
|
||||
logger.info("Inserted {} apparats into table".format(len(self.apparats)))
|
||||
|
||||
def insert_apparat_into_table(self, apparat):
|
||||
# ic(apparat)
|
||||
# logger.debug(apparat)
|
||||
def __dauer_check(apparat):
|
||||
return "Ja" if apparat[7] == 1 else "Nein"
|
||||
|
||||
@@ -1339,7 +1332,6 @@ class Ui(Ui_Semesterapparat):
|
||||
self.tableWidget_apparate.setItem(
|
||||
0, 5, QtWidgets.QTableWidgetItem(str(apparat[13]))
|
||||
)
|
||||
self.logger.log_info(f"Inserted apparat {apparat[4]}")
|
||||
|
||||
def open_context_menu(self, position):
|
||||
menu = QtWidgets.QMenu()
|
||||
@@ -1357,7 +1349,7 @@ class Ui(Ui_Semesterapparat):
|
||||
return
|
||||
pid = self.__get_table_data_field(self.tableWidget_apparate, pos[0], 2)
|
||||
app_id = self.__get_table_data_field(self.tableWidget_apparate, pos[0], 0)
|
||||
ic(pos, pid)
|
||||
logger.debug(pos, pid)
|
||||
extend_action.triggered.connect(self.extend_apparat)
|
||||
delete_action.triggered.connect(lambda: self.delete_apparat(pos))
|
||||
# pass pos to contact_prof
|
||||
@@ -1368,7 +1360,7 @@ class Ui(Ui_Semesterapparat):
|
||||
menu.exec(self.tableWidget_apparate.mapToGlobal(position))
|
||||
|
||||
def reminder(self):
|
||||
self.logger.log_info("Opening reminder dialog")
|
||||
logger.info("Opening reminder dialog")
|
||||
reminder = reminder_ui()
|
||||
reminder.exec()
|
||||
tableposition = self.tableWidget_apparate.currentRow()
|
||||
@@ -1385,17 +1377,17 @@ class Ui(Ui_Semesterapparat):
|
||||
self.calendarWidget.updateCells()
|
||||
# self.db.update_bookdata(data, book_id)
|
||||
# self.db.update_bookdata(data)
|
||||
self.logger.log_info("Commited message to database")
|
||||
logger.info("Commited message to database")
|
||||
# self.update_app_media_list()
|
||||
|
||||
def get_reminders(self):
|
||||
messages = self.db.getAllMessages()
|
||||
self.logger.log_info(f"Got {len(messages)} messages from database")
|
||||
logger.info(f"Got {len(messages)} messages from database")
|
||||
self.calendarWidget.setMessages(messages)
|
||||
self.calendarWidget.updateCells()
|
||||
|
||||
def open_reminder(self):
|
||||
if settings.mail.use_user_name == False:
|
||||
if not settings.mail.use_user_name:
|
||||
print("False")
|
||||
selected_date = self.calendarWidget.selectedDate().toString("yyyy-MM-dd")
|
||||
# # print(selected_date)
|
||||
@@ -1542,6 +1534,7 @@ class Ui(Ui_Semesterapparat):
|
||||
prof_id=self.db.getProfId(self.profdata),
|
||||
)
|
||||
print(medium.adis_idn, medium.signature)
|
||||
|
||||
def edit_medium(self):
|
||||
book = self.tableWidget_apparat_media.item(
|
||||
self.tableWidget_apparat_media.currentRow(), 1
|
||||
@@ -1592,7 +1585,7 @@ class Ui(Ui_Semesterapparat):
|
||||
prof_id=prof_id,
|
||||
signature=signature,
|
||||
)
|
||||
message = f'Soll das Medium "{self.tableWidget_apparat_media.item(self.tableWidget_apparat_media.currentRow(),0).text()}" wirklich gelöscht werden?'
|
||||
message = f'Soll das Medium "{self.tableWidget_apparat_media.item(self.tableWidget_apparat_media.currentRow(), 0).text()}" wirklich gelöscht werden?'
|
||||
state = self.confirm_popup(message, title="Löschen?")
|
||||
# print(state)
|
||||
if state == 1:
|
||||
@@ -1642,12 +1635,12 @@ class Ui(Ui_Semesterapparat):
|
||||
return
|
||||
|
||||
def __get_table_data_field(self, table, row, column):
|
||||
ic(row, column)
|
||||
logger.debug(row, column)
|
||||
row = int(row)
|
||||
return table.item(row, column).text()
|
||||
|
||||
def __contact_dialog(self, apparat, location: tuple | str, mail=None, pid=""):
|
||||
ic(location, pid, apparat)
|
||||
logger.debug(location, pid, apparat)
|
||||
|
||||
active_apparat_id = (
|
||||
self.drpdwn_app_nr.currentText() if apparat is None else apparat
|
||||
@@ -1674,7 +1667,7 @@ class Ui(Ui_Semesterapparat):
|
||||
app_subject = self.app_fach.currentText()
|
||||
else:
|
||||
app_subject = self.db.getApparatData(active_apparat_id, app_name)
|
||||
app_subject = app_subject.app_fach
|
||||
app_subject = app_subject.apparat.subject
|
||||
# profname = f"{profname.split(" ")[1]} {profname.split(" ")[0]}"
|
||||
# print(pid)
|
||||
if prof_id:
|
||||
@@ -1696,8 +1689,8 @@ class Ui(Ui_Semesterapparat):
|
||||
self.mail_thread.show()
|
||||
|
||||
def contact_prof(self, apparat="", location="", mail="", pid=""):
|
||||
ic(apparat)
|
||||
ic(location)
|
||||
logger.debug(apparat)
|
||||
logger.debug(location)
|
||||
if self.active_apparat == "":
|
||||
if apparat is False:
|
||||
self.confirm_popup(
|
||||
@@ -1733,8 +1726,8 @@ class Ui(Ui_Semesterapparat):
|
||||
def launch_gui():
|
||||
# print("trying to login")
|
||||
# print("checking if database available")
|
||||
log = MyLogger("login")
|
||||
log.log_info("Starting login dialog")
|
||||
|
||||
logger.info("Starting login dialog")
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
login_dialog = QtWidgets.QDialog()
|
||||
ui = login_ui()
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from src import logger
|
||||
from PyQt6 import QtWidgets, QtCore
|
||||
from PyQt6.QtCore import QDate
|
||||
from PyQt6.QtGui import QColor, QPen
|
||||
from src.backend import Database
|
||||
import darkdetect
|
||||
from icecream import ic
|
||||
|
||||
color = "#ddfb00" if darkdetect.isDark() else "#2204ff"
|
||||
pen = QPen(QColor(color))
|
||||
@@ -22,7 +22,7 @@ class MessageCalendar(QtWidgets.QCalendarWidget):
|
||||
def getMessages(self):
|
||||
# Get the messages from the database
|
||||
messages = Database().getAllMessages()
|
||||
ic(messages)
|
||||
logger.debug(messages)
|
||||
self.setMessages(messages)
|
||||
|
||||
def deleteMessage(self, id):
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
__all__ = ["filepicker"]
|
||||
from .collapse import StatusWidget
|
||||
from .filepicker import FilePicker
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
from PyQt6 import QtWidgets, QtCore, QtGui
|
||||
from PyQt6.QtCore import pyqtSignal
|
||||
from .widget_sources.Ui_admin_create_user import Ui_Dialog
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
|
||||
from .widget_sources.Ui_admin_edit_prof import Ui_Dialog#
|
||||
from PyQt6 import QtWidgets, QtCore
|
||||
from PyQt6.QtCore import pyqtSignal
|
||||
from icecream import ic
|
||||
from src.backend import Database
|
||||
from src import logger
|
||||
from src.logic import Prof
|
||||
from src.backend import Database
|
||||
class EditProf(QtWidgets.QDialog, Ui_Dialog):
|
||||
def __init__(self):
|
||||
super(EditProf, self).__init__()
|
||||
@@ -59,7 +60,7 @@ class EditProf(QtWidgets.QDialog, Ui_Dialog):
|
||||
else:
|
||||
self.faculty_member_old_telnr.setText(data.telnr)
|
||||
self.faculty_member_oldmail.setText(data.mail)
|
||||
ic(data)
|
||||
logger.debug(data)
|
||||
(
|
||||
self.edit_faculty_member_title.setText(data.title)
|
||||
if data.title is not None
|
||||
@@ -83,7 +84,7 @@ class EditProf(QtWidgets.QDialog, Ui_Dialog):
|
||||
olddata = self.db.getProfByName(
|
||||
self.edit_faculty_member_select_member.currentText()
|
||||
)
|
||||
ic(olddata)
|
||||
logger.debug(olddata)
|
||||
data = olddata
|
||||
oldlname = data.lastname
|
||||
oldfname = data.firstname
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
from .widget_sources.Ui_admin_edit_user import Ui_Dialog
|
||||
from PyQt6 import QtWidgets, QtCore
|
||||
from PyQt6.QtCore import pyqtSignal
|
||||
from icecream import ic
|
||||
from src.backend import Database
|
||||
from src.backend import AdminCommands
|
||||
admin = AdminCommands()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
from .widget_sources.Ui_calendar_entry import Ui_Dialog
|
||||
from PyQt6 import QtWidgets, QtCore
|
||||
from PyQt6.QtCore import pyqtSignal, QDate
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# import pysignal pyslot
|
||||
from PyQt6.QtCore import pyqtSignal as Signal
|
||||
from PyQt6.QtWidgets import (
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import os
|
||||
from natsort import natsorted
|
||||
from icecream import ic
|
||||
from .widget_sources.Ui_elsa_maindialog import Ui_Dialog
|
||||
from PyQt6 import QtCore, QtWidgets, QtGui
|
||||
from PyQt6.QtGui import QRegularExpressionValidator
|
||||
from PyQt6.QtCore import QDate
|
||||
from src import Icon
|
||||
from src.backend import recreateElsaFile, generateSemesterByDate, Database
|
||||
from src.logic import elsa_word_to_csv, MyLogger, Prof
|
||||
from src.logic.log import log
|
||||
from src import Icon, logger
|
||||
from src.backend import recreateElsaFile, Semester, Database
|
||||
from src.logic import elsa_word_to_csv, Prof
|
||||
from src.ui import popus_confirm
|
||||
from src.ui.dialogs import ElsaAddEntry
|
||||
from src.ui.widgets import FilePicker
|
||||
@@ -39,6 +37,23 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
self.quote_entry.clicked.connect(self.elsa_table_entry)
|
||||
self.quote_entry.setEnabled(False)
|
||||
self.newProf.hide()
|
||||
self.splitter = QtWidgets.QSplitter(QtCore.Qt.Orientation.Horizontal)
|
||||
self.splitter.addWidget(self.media_table)
|
||||
self.splitter.addWidget(self.statistics)
|
||||
self.results.layout().removeWidget(self.media_table)
|
||||
self.results.layout().removeWidget(self.statistics)
|
||||
self.results.layout().addWidget(self.splitter)
|
||||
self.elsa_statistics_table.setColumnCount(2)
|
||||
# set header to occupy the whole width and auto scale based on table width
|
||||
self.elsa_statistics_table.horizontalHeader().setStretchLastSection(True)
|
||||
self.elsa_statistics_table.horizontalHeader().setSectionResizeMode(
|
||||
QtWidgets.QHeaderView.ResizeMode.Stretch
|
||||
)
|
||||
# if table size gets smaller, set horitzontal headers text to be left aligned
|
||||
self.elsa_statistics_table.horizontalHeader().setDefaultAlignment(
|
||||
QtCore.Qt.AlignmentFlag.AlignLeft
|
||||
)
|
||||
# self.table_elsa_list.
|
||||
Icon("person", self.prof_icon)
|
||||
# validators
|
||||
# prof mail
|
||||
@@ -55,12 +70,12 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
)
|
||||
|
||||
##Variables
|
||||
self.logger = MyLogger("ElsaDialog")
|
||||
self.db = Database()
|
||||
self.graph_data = {"x": [generateSemesterByDate()], "y": [0]}
|
||||
self.graph_data = {"x": [Semester().value], "y": [0]}
|
||||
self.createProf = False
|
||||
self.profs = self.getProfs()
|
||||
|
||||
self.elsa_prof.addItems(self.getProfs())
|
||||
self.elsa_prof.addItems([prof[0] for prof in self.profs])
|
||||
self.elsa_prof.addItem("")
|
||||
self.elsa_prof.setCurrentText("")
|
||||
# implement a check for the prof name. if name is not in list and has schema of lastname, firstname, show newProf frame
|
||||
@@ -70,7 +85,7 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
self.newProf_title.textChanged.connect(self.checkProfData)
|
||||
|
||||
self.loadFrame()
|
||||
log.info("Elsa Dialog loaded")
|
||||
logger.info("Elsa Dialog loaded")
|
||||
# self.show()
|
||||
|
||||
def checkProfData(self):
|
||||
@@ -84,14 +99,20 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
):
|
||||
self.elsa_save.setEnabled(True)
|
||||
self.elsa_save.setToolTip("")
|
||||
self.newProf_mail.setToolTip("")
|
||||
self.newProf_telnr.setToolTip("")
|
||||
else:
|
||||
self.elsa_save.setEnabled(False)
|
||||
self.elsa_save.setToolTip("Bitte erst Daten eingeben")
|
||||
self.newProf_mail.setToolTip("Bitte geben Sie eine gültige E-Mail ein")
|
||||
self.newProf_telnr.setToolTip(
|
||||
"Bitte geben Sie eine gültige Telefonnummer ein"
|
||||
)
|
||||
|
||||
def checkProf(self):
|
||||
if (
|
||||
", " in self.elsa_prof.currentText()
|
||||
and self.elsa_prof.currentText() not in self.getProfs()
|
||||
and self.elsa_prof.currentText() not in [prof[0] for prof in self.profs]
|
||||
):
|
||||
self.newProf.show()
|
||||
self.elsa_save.setEnabled(False)
|
||||
@@ -105,7 +126,9 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
|
||||
def getProfs(self):
|
||||
profs = self.db.getProfs()
|
||||
profs = [f"{prof.lastname}, {prof.firstname}" for prof in profs]
|
||||
profs = [
|
||||
("{}, {}".format(prof.lastname, prof.firstname), prof.id) for prof in profs
|
||||
]
|
||||
|
||||
profs = list(set(profs))
|
||||
profs.sort()
|
||||
@@ -161,7 +184,7 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
self.elsa_date.setText(QDate.currentDate().toString("dd.MM.yyyy"))
|
||||
|
||||
def addSemester(self):
|
||||
self.elsa_semester.setText(generateSemesterByDate())
|
||||
self.elsa_semester.setText(Semester().value)
|
||||
|
||||
def update_elsa(self):
|
||||
prof = self.elsa_prof.currentText()
|
||||
@@ -205,11 +228,14 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
fullname=f"{prof.split(", ")[0]} {prof.split(", ")[1]}",
|
||||
)
|
||||
prof_id = self.db.getProfId(profdata)
|
||||
ic(profdata, prof_id)
|
||||
logger.debug(profdata, prof_id)
|
||||
|
||||
if prof_id is None:
|
||||
self.db.createProf(profdata)
|
||||
prof_id = self.db.getProfId(prof)
|
||||
self.profs.append(
|
||||
"f{}, {}".format(profdata.lastname, profdata.firstname), prof_id
|
||||
)
|
||||
elsa_id = self.db.createElsaApparat(
|
||||
date,
|
||||
prof_id,
|
||||
@@ -228,12 +254,12 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
files,
|
||||
elsa_id,
|
||||
)
|
||||
log.info("Stored {} files in the database", len(files))
|
||||
logger.info("Stored {} files in the database", len(files))
|
||||
self.cancel_elsa_creation()
|
||||
self.refresh_elsa_table()
|
||||
self.elsa_prof.setCurrentText("")
|
||||
self.quote_entry.setEnabled(False)
|
||||
log.info("Saved apparat to database, id {}", elsa_id)
|
||||
logger.info("Saved apparat to database, id {}", elsa_id)
|
||||
|
||||
def refresh_elsa_table(self):
|
||||
self.elsa_table.setRowCount(0)
|
||||
@@ -253,13 +279,13 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
|
||||
def open_elsa(self):
|
||||
prof = self.elsa_table.item(self.elsa_table.currentRow(), 0).text()
|
||||
print(prof)
|
||||
logger.info("prof", prof)
|
||||
date = self.elsa_table.item(self.elsa_table.currentRow(), 1).text()
|
||||
semester = self.elsa_table.item(self.elsa_table.currentRow(), 2).text()
|
||||
self.elsa_update.setEnabled(True)
|
||||
self.elsa_save.setEnabled(False)
|
||||
if self.elsa_prof.currentText() == prof and date == self.elsa_date.text():
|
||||
self.logger.log_info("Same prof, stopping")
|
||||
logger.debug("Same prof, stopping")
|
||||
return
|
||||
self.create_frame_elsa.setEnabled(True)
|
||||
self.dokument_list_elsa.setRowCount(0)
|
||||
@@ -269,24 +295,21 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
elsa_apparats = self.db.getElsaApparats()
|
||||
elsa_id = None
|
||||
for apparat in elsa_apparats:
|
||||
print(apparat)
|
||||
if (
|
||||
apparat[1] == date
|
||||
and apparat[2] == semester
|
||||
and apparat[3] == self.db.getProfId({"profname": prof})
|
||||
):
|
||||
elsa_id = apparat[0]
|
||||
# print(elsa_id)
|
||||
break
|
||||
self.elsa_date.setText(date)
|
||||
self.elsa_semester.setText(semester)
|
||||
self.elsa_prof.setCurrentText(prof)
|
||||
ic(elsa_id)
|
||||
logger.info("Elsa ID is {}", elsa_id)
|
||||
if elsa_id is None:
|
||||
return
|
||||
documents = self.db.getElsaFiles(elsa_id)
|
||||
for document in documents:
|
||||
# print(document)
|
||||
self.dokument_list_elsa.insertRow(0)
|
||||
self.dokument_list_elsa.setItem(
|
||||
0, 0, QtWidgets.QTableWidgetItem(document[0])
|
||||
@@ -340,13 +363,11 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
self.table_elsa_list.setItem(0, 11, QtWidgets.QTableWidgetItem(scan["type"]))
|
||||
|
||||
def addDokumentElsa(self):
|
||||
# print("Add document")
|
||||
picker = FilePicker()
|
||||
files = picker.pick_files()
|
||||
datalist = []
|
||||
for file in files:
|
||||
data = {}
|
||||
# print(file)
|
||||
filename = file.split("/")[-1]
|
||||
filetype = filename.split(".")[-1]
|
||||
self.dokument_list_elsa.insertRow(0)
|
||||
@@ -360,27 +381,6 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
data["path"] = file
|
||||
data["type"] = filetype
|
||||
datalist.append(data)
|
||||
# elsa_id = self.db.getElsaId(
|
||||
# self.elsa_prof.currentText(),
|
||||
# self.elsa_semester.text(),
|
||||
# self.elsa_date.text(),
|
||||
# )
|
||||
# # print(elsa_id)
|
||||
# if elsa_id is None:
|
||||
# # create elsa
|
||||
# self.db.createElsaApparat(
|
||||
# self.elsa_date.text(),
|
||||
# self.elsa_prof.currentText(),
|
||||
# self.elsa_semester.text(),
|
||||
# )
|
||||
# elsa_id = self.db.getElsaId(
|
||||
# self.elsa_prof.currentText(),
|
||||
# self.elsa_semester.text(),
|
||||
# self.elsa_date.text(),
|
||||
# )
|
||||
# self.db.insertElsaFile(datalist, elsa_id)
|
||||
# self.elsa_save.setEnabled(False)
|
||||
# self.refresh_elsa_table()
|
||||
|
||||
def parseDokumentElsa(self):
|
||||
if self.dokument_list_elsa.rowCount() == 0:
|
||||
@@ -389,7 +389,6 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
# get the file path of the selected file based on it's row
|
||||
row = self.dokument_list_elsa.currentRow()
|
||||
file = self.dokument_list_elsa.item(row, 3).text()
|
||||
# print(file)
|
||||
if file == "Database":
|
||||
filename = self.dokument_list_elsa.item(row, 0).text()
|
||||
filetype = self.dokument_list_elsa.item(row, 1).text()
|
||||
@@ -397,14 +396,13 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
file = recreateElsaFile(
|
||||
filename=filename, filetype=filetype, open=False
|
||||
)
|
||||
# print(file)
|
||||
data, _ = elsa_word_to_csv(file)
|
||||
elsa_id = self.db.getElsaId(
|
||||
self.db.getProfId(Prof(fullname=self.elsa_prof.currentText())),
|
||||
self.elsa_semester.text(),
|
||||
self.elsa_date.text(),
|
||||
)
|
||||
ic(
|
||||
logger.debug(
|
||||
elsa_id,
|
||||
self.elsa_prof.currentText(),
|
||||
self.elsa_semester.text(),
|
||||
@@ -441,14 +439,13 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
try:
|
||||
self.elsa_statistics.removeTab(1)
|
||||
except:
|
||||
self.logger.log_debug("No tab to remove")
|
||||
logger.debug("No tab to remove")
|
||||
self.elsa_table.setRowCount(0)
|
||||
elsa_apparats = self.db.getElsaApparats()
|
||||
elsa_apparats = natsorted(elsa_apparats, key=lambda x: x[2], reverse=True)
|
||||
# x = semester, y = number of apparats
|
||||
|
||||
for apparat in elsa_apparats:
|
||||
# print(apparat)
|
||||
data = self.insert_elsa_into_table(apparat)
|
||||
semester = data[0]
|
||||
number = data[1]
|
||||
@@ -466,7 +463,7 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
generateMissing,
|
||||
"Anzahl der Apparate",
|
||||
)
|
||||
ic(self.graph_data)
|
||||
logger.debug(self.graph_data)
|
||||
self.elsa_statistics_table.setRowCount(0)
|
||||
for i in range(len(self.graph_data["x"])):
|
||||
self.elsa_statistics_table.insertRow(0)
|
||||
@@ -479,7 +476,7 @@ class ElsaDialog(QtWidgets.QDialog, Ui_Dialog):
|
||||
self.elsa_statistics.addTab(graph, "Graph")
|
||||
|
||||
def launch():
|
||||
log.debug("Launching Elsa Dialog")
|
||||
logger.debug("Launching Elsa Dialog")
|
||||
app = QtWidgets.QApplication([])
|
||||
window = ElsaDialog()
|
||||
window.show()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import random
|
||||
from typing import Union
|
||||
|
||||
|
||||
@@ -1,31 +1,28 @@
|
||||
from .widget_sources.Ui_search_statistic_page import Ui_Dialog
|
||||
from PyQt6 import QtWidgets, QtGui, QtCore
|
||||
from PyQt6.QtCore import pyqtSignal
|
||||
from src.backend import Database, generateSemesterByDate
|
||||
from src.logic import custom_sort, Prof
|
||||
from src import MyLogger
|
||||
from src.backend import Database, Semester
|
||||
from src import logger
|
||||
from src.logic import custom_sort, Prof, sort_semesters_list
|
||||
from src.ui import ApparatExtendDialog
|
||||
from src.ui.dialogs import Mail_Dialog
|
||||
from src.ui.widgets import DataGraph, StatusWidget
|
||||
|
||||
from natsort import natsorted
|
||||
from icecream import ic
|
||||
|
||||
|
||||
class MyComboBox(QtWidgets.QComboBox):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
|
||||
|
||||
class SearchStatisticPage(QtWidgets.QDialog, Ui_Dialog):
|
||||
apparat_open = pyqtSignal(str)
|
||||
reloadSignal = pyqtSignal()
|
||||
refreshSignal = pyqtSignal()
|
||||
|
||||
def __init__(self):
|
||||
self.logger = MyLogger("SearchStatisticPage")
|
||||
self.logger.log_info("SearchStatisticPage started")
|
||||
logger.info("SearchStatisticPage started")
|
||||
super().__init__()
|
||||
self.setupUi(self)
|
||||
self.book_search_result.horizontalHeader().setSectionResizeMode(
|
||||
@@ -51,7 +48,14 @@ class SearchStatisticPage(QtWidgets.QDialog, Ui_Dialog):
|
||||
self.tableWidget.resizeRowsToContents()
|
||||
self.db = Database()
|
||||
self.box_appnrs.addItems(str(i) for i in self.db.getUnavailableApparatNumbers())
|
||||
|
||||
self.splitter = QtWidgets.QSplitter(QtCore.Qt.Orientation.Horizontal)
|
||||
# insert splitter in apparatResult to allow resizing of the columns
|
||||
self.splitter.addWidget(self.app_results)
|
||||
self.splitter.addWidget(self.stats)
|
||||
self.apparatResult.layout().removeWidget(self.stats)
|
||||
self.apparatResult.layout().removeWidget(self.app_results)
|
||||
self.apparatResult.layout().addWidget(self.splitter)
|
||||
self.semester = Semester().value
|
||||
self.populate_tab()
|
||||
|
||||
def restore_apparat(self):
|
||||
@@ -90,15 +94,15 @@ class SearchStatisticPage(QtWidgets.QDialog, Ui_Dialog):
|
||||
extend.exec()
|
||||
if extend.result() == QtWidgets.QDialog.DialogCode.Accepted:
|
||||
data = extend.get_data()
|
||||
ic(data)
|
||||
logger.debug(data)
|
||||
app_name = self.tableWidget.item(self.tableWidget.currentRow(), 1).text()
|
||||
app_id = self.db.getApparatId(app_name)
|
||||
self.db.setNewSemesterDate(app_id, data["semester"], data["dauerapp"])
|
||||
#remove the row
|
||||
# remove the row
|
||||
self.tableWidget.removeRow(self.tableWidget.currentRow())
|
||||
self.refreshSignal.emit()
|
||||
def tabW2_changed(self):
|
||||
|
||||
def tabW2_changed(self):
|
||||
if self.tabWidget_2.currentIndex() == 0:
|
||||
self.stackedWidget_4.setCurrentIndex(0)
|
||||
else:
|
||||
@@ -113,12 +117,11 @@ class SearchStatisticPage(QtWidgets.QDialog, Ui_Dialog):
|
||||
"title": title if title != "" else None,
|
||||
}
|
||||
params = {key: value for key, value in params.items() if value is not None}
|
||||
# ic(params)
|
||||
logger.debug(params)
|
||||
retdata = self.db.searchBook(params)
|
||||
if retdata is None:
|
||||
return
|
||||
for book in retdata:
|
||||
|
||||
self.book_search_result.insertRow(0)
|
||||
self.book_search_result.setItem(
|
||||
0, 0, QtWidgets.QTableWidgetItem(book[0].title)
|
||||
@@ -145,10 +148,9 @@ class SearchStatisticPage(QtWidgets.QDialog, Ui_Dialog):
|
||||
|
||||
selected_apparats.append(data)
|
||||
# delete all selected apparats
|
||||
ic(selected_apparats)
|
||||
logger.debug(selected_apparats)
|
||||
dialogs = []
|
||||
for i in selected_apparats:
|
||||
|
||||
app_id = i["app_id"]
|
||||
app_name = i["app_name"]
|
||||
prof_name = i["prof_name"]
|
||||
@@ -206,7 +208,7 @@ class SearchStatisticPage(QtWidgets.QDialog, Ui_Dialog):
|
||||
self.box_dauerapp.setEnabled(True)
|
||||
|
||||
def populate_tab(self, table_or_graph=0):
|
||||
self.logger.log_info("populate_tab started")
|
||||
logger.info("populate_tab started")
|
||||
# add default values to the dropdowns
|
||||
self.box_appnrs.clear()
|
||||
self.box_appnrs.addItem("")
|
||||
@@ -232,9 +234,13 @@ class SearchStatisticPage(QtWidgets.QDialog, Ui_Dialog):
|
||||
apparats = [str(apparat) for apparat in apparats]
|
||||
self.box_appnrs.addItems(apparats)
|
||||
persons = self.db.getProfs()
|
||||
self.box_person.addItems([f"{person.lastname}, {person.firstname}" for person in persons])
|
||||
persons = sorted(persons, key=lambda x: x.lastname)
|
||||
self.box_person.addItems(
|
||||
[f"{person.lastname}, {person.firstname}" for person in persons]
|
||||
)
|
||||
self.box_fach.addItems(subject[1] for subject in self.db.getSubjects())
|
||||
semester = self.db.getSemersters()
|
||||
semester = self.db.getSemesters()
|
||||
semester = sort_semesters_list(semester)
|
||||
self.box_erstellsemester.addItems(semester)
|
||||
self.box_semester.addItems(semester)
|
||||
self.statistics_table.setRowCount(0)
|
||||
@@ -269,7 +275,7 @@ class SearchStatisticPage(QtWidgets.QDialog, Ui_Dialog):
|
||||
# place the graph into tabWidget_3
|
||||
self.tabWidget_3.addTab(graph, "Graph")
|
||||
self.tabWidget_3.setCurrentIndex(table_or_graph)
|
||||
self.logger.log_info("populate_tab finished")
|
||||
logger.info("populate_tab finished")
|
||||
|
||||
def delete_selected_apparats(self):
|
||||
# get all selected apparats
|
||||
@@ -281,9 +287,9 @@ class SearchStatisticPage(QtWidgets.QDialog, Ui_Dialog):
|
||||
selected_apparat_rows.append(i)
|
||||
# delete all selected apparats
|
||||
# # print(selected_apparats)
|
||||
self.logger.log_info(f"Deleting apparats: {selected_apparats}")
|
||||
logger.info(f"Deleting apparats: {selected_apparats}")
|
||||
for apparat in selected_apparats:
|
||||
self.db.deleteApparat(apparat, generateSemesterByDate())
|
||||
self.db.deleteApparat(apparat, self.semester)
|
||||
for row in selected_apparat_rows:
|
||||
# set the background of the row to red
|
||||
for j in range(5):
|
||||
@@ -295,10 +301,10 @@ class SearchStatisticPage(QtWidgets.QDialog, Ui_Dialog):
|
||||
def statistics(self):
|
||||
"""Generate the statistics based on the selected filters."""
|
||||
self.tableWidget.setRowCount(0)
|
||||
active_semseter = generateSemesterByDate()
|
||||
active_semseter = self.semester
|
||||
self.db_err_message.setText("")
|
||||
self.btn_del_select_apparats.setEnabled(True)
|
||||
self.btn_notify_for_deletion.setEnabled(True)
|
||||
self.btn_del_select_apparats.setEnabled(False)
|
||||
self.btn_notify_for_deletion.setEnabled(False)
|
||||
params = {
|
||||
"appnr": (
|
||||
self.box_appnrs.currentText()
|
||||
@@ -306,7 +312,7 @@ class SearchStatisticPage(QtWidgets.QDialog, Ui_Dialog):
|
||||
else None
|
||||
),
|
||||
"prof_id": (
|
||||
self.db.getProfId(self.box_person.currentText())
|
||||
self.db.getProfId(Prof(fullname=self.box_person.currentText()))
|
||||
if self.box_person.currentText() != ""
|
||||
else None
|
||||
),
|
||||
@@ -348,29 +354,22 @@ class SearchStatisticPage(QtWidgets.QDialog, Ui_Dialog):
|
||||
self.db_err_message.setText("Keine Ergebnisse gefunden")
|
||||
return
|
||||
data = []
|
||||
sem_year = active_semseter.split(" ")[1]
|
||||
sem_time = active_semseter.split(" ")[0]
|
||||
if sem_time == "WiSe":
|
||||
sem_year = int(sem_year.split("/")[0])
|
||||
else:
|
||||
sem_year = int(sem_year)
|
||||
|
||||
for entry in result:
|
||||
if "deletable" in params.keys():
|
||||
entry_sem_time = entry[5].split(" ")[0]
|
||||
entry_sem_year = entry[5].split(" ")[1]
|
||||
if entry_sem_time == "SoSe":
|
||||
entry_sem_year = int(entry_sem_year)
|
||||
if (entry_sem_year < sem_year) or (
|
||||
sem_time == "WiSe" and entry_sem_year == sem_year
|
||||
):
|
||||
data.append(entry)
|
||||
else:
|
||||
entry_sem_year = int(entry_sem_year.split("/")[0])
|
||||
if entry_sem_year < sem_year:
|
||||
data.append(entry)
|
||||
sem = Semester().from_string(
|
||||
entry[8] if entry[8] is not None else entry[5]
|
||||
)
|
||||
logger.info(f"Semester: {sem}")
|
||||
if sem.isPastSemester(Semester()):
|
||||
data.append(entry)
|
||||
else:
|
||||
data.append(entry)
|
||||
self.tableWidget.setRowCount(len(data))
|
||||
if len(data) > 0:
|
||||
self.btn_del_select_apparats.setEnabled(True)
|
||||
self.btn_notify_for_deletion.setEnabled(True)
|
||||
|
||||
for i in range(len(data)):
|
||||
# set the items 0 = clickable checkbox, 1 = appname, 2 = profname, 3 = fach
|
||||
self.tableWidget.setItem(i, 0, QtWidgets.QTableWidgetItem(""))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\widgets\widget_sources\admin_create_user.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.7.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\widgets\widget_sources\admin_edit_prof.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.7.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\widgets\widget_sources\admin_edit_user.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.7.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\widgets\widget_sources\calendar_entry.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.7.1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\widgets\widget_sources\elsa_maindialog.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.7.1
|
||||
@@ -187,15 +188,36 @@ class Ui_Dialog(object):
|
||||
self.verticalLayout.addWidget(self.create_frame_elsa)
|
||||
self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
|
||||
self.quote_entry = QtWidgets.QPushButton(parent=Dialog)
|
||||
self.quote_entry.setObjectName("quote_entry")
|
||||
self.horizontalLayout_6.addWidget(self.quote_entry)
|
||||
spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
||||
self.horizontalLayout_6.addItem(spacerItem5)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_6)
|
||||
self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
|
||||
self.table_elsa_list = QtWidgets.QTableWidget(parent=Dialog)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_5)
|
||||
self.results = QtWidgets.QWidget(parent=Dialog)
|
||||
self.results.setObjectName("results")
|
||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.results)
|
||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
||||
self.statistics = QtWidgets.QWidget(parent=self.results)
|
||||
self.statistics.setObjectName("statistics")
|
||||
self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.statistics)
|
||||
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
|
||||
self.media_table = QtWidgets.QWidget(parent=self.statistics)
|
||||
self.media_table.setObjectName("media_table")
|
||||
self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.media_table)
|
||||
self.verticalLayout_4.setObjectName("verticalLayout_4")
|
||||
self.horizontalLayout_9 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_9.setObjectName("horizontalLayout_9")
|
||||
self.quote_entry = QtWidgets.QPushButton(parent=self.media_table)
|
||||
self.quote_entry.setObjectName("quote_entry")
|
||||
self.horizontalLayout_9.addWidget(self.quote_entry)
|
||||
spacerItem5 = QtWidgets.QSpacerItem(
|
||||
40,
|
||||
20,
|
||||
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||
)
|
||||
self.horizontalLayout_9.addItem(spacerItem5)
|
||||
self.verticalLayout_4.addLayout(self.horizontalLayout_9)
|
||||
self.table_elsa_list = QtWidgets.QTableWidget(parent=self.media_table)
|
||||
self.table_elsa_list.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.table_elsa_list.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
|
||||
self.table_elsa_list.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectItems)
|
||||
@@ -230,13 +252,14 @@ class Ui_Dialog(object):
|
||||
self.table_elsa_list.setHorizontalHeaderItem(11, item)
|
||||
self.table_elsa_list.horizontalHeader().setDefaultSectionSize(85)
|
||||
self.table_elsa_list.horizontalHeader().setMinimumSectionSize(31)
|
||||
self.horizontalLayout_5.addWidget(self.table_elsa_list)
|
||||
self.elsa_statistics = QtWidgets.QTabWidget(parent=Dialog)
|
||||
self.verticalLayout_4.addWidget(self.table_elsa_list)
|
||||
self.horizontalLayout_7.addWidget(self.media_table)
|
||||
self.elsa_statistics = QtWidgets.QTabWidget(parent=self.statistics)
|
||||
self.elsa_statistics.setObjectName("elsa_statistics")
|
||||
self.tab = QtWidgets.QWidget()
|
||||
self.tab.setObjectName("tab")
|
||||
self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.tab)
|
||||
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
|
||||
self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.tab)
|
||||
self.horizontalLayout_8.setObjectName("horizontalLayout_8")
|
||||
self.elsa_statistics_table = QtWidgets.QTableWidget(parent=self.tab)
|
||||
self.elsa_statistics_table.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.elsa_statistics_table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||
@@ -250,14 +273,16 @@ class Ui_Dialog(object):
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.elsa_statistics_table.setHorizontalHeaderItem(1, item)
|
||||
self.elsa_statistics_table.horizontalHeader().setDefaultSectionSize(169)
|
||||
self.horizontalLayout_7.addWidget(self.elsa_statistics_table)
|
||||
self.horizontalLayout_8.addWidget(self.elsa_statistics_table)
|
||||
self.elsa_statistics.addTab(self.tab, "")
|
||||
self.horizontalLayout_5.addWidget(self.elsa_statistics)
|
||||
self.horizontalLayout_5.setStretch(0, 7)
|
||||
self.horizontalLayout_5.setStretch(1, 3)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_5)
|
||||
self.horizontalLayout_7.addWidget(self.elsa_statistics)
|
||||
self.horizontalLayout_3.addWidget(self.statistics)
|
||||
self.results_table = QtWidgets.QWidget(parent=self.results)
|
||||
self.results_table.setObjectName("results_table")
|
||||
self.horizontalLayout_3.addWidget(self.results_table)
|
||||
self.verticalLayout.addWidget(self.results)
|
||||
self.verticalLayout.setStretch(0, 1)
|
||||
self.verticalLayout.setStretch(3, 2)
|
||||
self.verticalLayout.setStretch(4, 2)
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
self.elsa_statistics.setCurrentIndex(0)
|
||||
@@ -277,12 +302,8 @@ class Ui_Dialog(object):
|
||||
Dialog.setTabOrder(self.seperateEntries, self.check_file_elsa)
|
||||
Dialog.setTabOrder(self.check_file_elsa, self.elsa_save)
|
||||
Dialog.setTabOrder(self.elsa_save, self.elsa_update)
|
||||
Dialog.setTabOrder(self.elsa_update, self.quote_entry)
|
||||
Dialog.setTabOrder(self.quote_entry, self.elsa_statistics)
|
||||
Dialog.setTabOrder(self.elsa_statistics, self.table_elsa_list)
|
||||
Dialog.setTabOrder(self.table_elsa_list, self.elsa_table)
|
||||
Dialog.setTabOrder(self.elsa_table, self.elsa_statistics_table)
|
||||
Dialog.setTabOrder(self.elsa_statistics_table, self.dokument_list_elsa)
|
||||
Dialog.setTabOrder(self.elsa_update, self.elsa_table)
|
||||
Dialog.setTabOrder(self.elsa_table, self.dokument_list_elsa)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'c:\Users\aky547\GitHub\SemesterapparatsManager\src\ui\widgets\widget_sources\search_statistic_page.ui'
|
||||
#
|
||||
# Created by: PyQt6 UI code generator 6.7.1
|
||||
@@ -12,7 +13,7 @@ from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
Dialog.setObjectName("Dialog")
|
||||
Dialog.resize(1244, 767)
|
||||
Dialog.resize(1250, 767)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.tabWidget_2 = QtWidgets.QTabWidget(parent=Dialog)
|
||||
@@ -150,24 +151,26 @@ class Ui_Dialog(object):
|
||||
self.apparatResult.setObjectName("apparatResult")
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout(self.apparatResult)
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.verticalLayout_4 = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout_4.setObjectName("verticalLayout_4")
|
||||
self.app_results = QtWidgets.QWidget(parent=self.apparatResult)
|
||||
self.app_results.setObjectName("app_results")
|
||||
self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.app_results)
|
||||
self.verticalLayout_7.setObjectName("verticalLayout_7")
|
||||
self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
|
||||
self.verticalLayout_5 = QtWidgets.QVBoxLayout()
|
||||
self.verticalLayout_5.setObjectName("verticalLayout_5")
|
||||
self.horizontalLayout_7.addLayout(self.verticalLayout_5)
|
||||
self.btn_del_select_apparats = QtWidgets.QPushButton(parent=self.apparatResult)
|
||||
self.btn_del_select_apparats = QtWidgets.QPushButton(parent=self.app_results)
|
||||
self.btn_del_select_apparats.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
|
||||
self.btn_del_select_apparats.setObjectName("btn_del_select_apparats")
|
||||
self.horizontalLayout_7.addWidget(self.btn_del_select_apparats)
|
||||
self.btn_notify_for_deletion = QtWidgets.QPushButton(parent=self.apparatResult)
|
||||
self.btn_notify_for_deletion = QtWidgets.QPushButton(parent=self.app_results)
|
||||
self.btn_notify_for_deletion.setObjectName("btn_notify_for_deletion")
|
||||
self.horizontalLayout_7.addWidget(self.btn_notify_for_deletion)
|
||||
spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
||||
self.horizontalLayout_7.addItem(spacerItem4)
|
||||
self.verticalLayout_4.addLayout(self.horizontalLayout_7)
|
||||
self.tableWidget = QtWidgets.QTableWidget(parent=self.apparatResult)
|
||||
self.verticalLayout_7.addLayout(self.horizontalLayout_7)
|
||||
self.tableWidget = QtWidgets.QTableWidget(parent=self.app_results)
|
||||
self.tableWidget.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
|
||||
self.tableWidget.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
|
||||
self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
|
||||
@@ -185,14 +188,18 @@ class Ui_Dialog(object):
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(4, item)
|
||||
self.tableWidget.horizontalHeader().setStretchLastSection(True)
|
||||
self.verticalLayout_4.addWidget(self.tableWidget)
|
||||
self.horizontalLayout.addLayout(self.verticalLayout_4)
|
||||
self.tabWidget_3 = QtWidgets.QTabWidget(parent=self.apparatResult)
|
||||
self.verticalLayout_7.addWidget(self.tableWidget)
|
||||
self.horizontalLayout.addWidget(self.app_results)
|
||||
self.stats = QtWidgets.QWidget(parent=self.apparatResult)
|
||||
self.stats.setObjectName("stats")
|
||||
self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.stats)
|
||||
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
|
||||
self.tabWidget_3 = QtWidgets.QTabWidget(parent=self.stats)
|
||||
self.tabWidget_3.setObjectName("tabWidget_3")
|
||||
self.statistic_table = QtWidgets.QWidget()
|
||||
self.statistic_table.setObjectName("statistic_table")
|
||||
self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.statistic_table)
|
||||
self.verticalLayout_6.setObjectName("verticalLayout_6")
|
||||
self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.statistic_table)
|
||||
self.verticalLayout_4.setObjectName("verticalLayout_4")
|
||||
self.statistics_table = QtWidgets.QTableWidget(parent=self.statistic_table)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
@@ -219,17 +226,16 @@ class Ui_Dialog(object):
|
||||
self.statistics_table.horizontalHeader().setSortIndicatorShown(True)
|
||||
self.statistics_table.horizontalHeader().setStretchLastSection(False)
|
||||
self.statistics_table.verticalHeader().setStretchLastSection(True)
|
||||
self.verticalLayout_6.addWidget(self.statistics_table)
|
||||
self.verticalLayout_4.addWidget(self.statistics_table)
|
||||
self.dataLayout = QtWidgets.QHBoxLayout()
|
||||
self.dataLayout.setObjectName("dataLayout")
|
||||
self.verticalLayout_6.addLayout(self.dataLayout)
|
||||
self.verticalLayout_4.addLayout(self.dataLayout)
|
||||
self.tabWidget_3.addTab(self.statistic_table, "")
|
||||
self.graph_table = QtWidgets.QWidget()
|
||||
self.graph_table.setObjectName("graph_table")
|
||||
self.tabWidget_3.addTab(self.graph_table, "")
|
||||
self.horizontalLayout.addWidget(self.tabWidget_3)
|
||||
self.horizontalLayout.setStretch(0, 55)
|
||||
self.horizontalLayout.setStretch(1, 45)
|
||||
self.horizontalLayout_5.addWidget(self.tabWidget_3)
|
||||
self.horizontalLayout.addWidget(self.stats)
|
||||
self.stackedWidget_4.addWidget(self.apparatResult)
|
||||
self.bookresult = QtWidgets.QWidget()
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
|
||||
@@ -285,8 +291,7 @@ class Ui_Dialog(object):
|
||||
Dialog.setTabOrder(self.box_dauerapp, self.btn_search)
|
||||
Dialog.setTabOrder(self.btn_search, self.btn_del_select_apparats)
|
||||
Dialog.setTabOrder(self.btn_del_select_apparats, self.btn_notify_for_deletion)
|
||||
Dialog.setTabOrder(self.btn_notify_for_deletion, self.tabWidget_3)
|
||||
Dialog.setTabOrder(self.tabWidget_3, self.book_search_result)
|
||||
Dialog.setTabOrder(self.btn_notify_for_deletion, self.book_search_result)
|
||||
Dialog.setTabOrder(self.book_search_result, self.seach_by_signature)
|
||||
Dialog.setTabOrder(self.seach_by_signature, self.search_by_title)
|
||||
Dialog.setTabOrder(self.search_by_title, self.book_search)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
from .blob import create_blob
|
||||
from .icon import Icon
|
||||
from .pickles import dump_pickle, load_pickle
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
def create_blob(file):
|
||||
"""
|
||||
Creates a blob from a file.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import darkdetect
|
||||
from omegaconf import OmegaConf
|
||||
from PyQt6 import QtGui
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import pickle
|
||||
|
||||
|
||||
|
||||
236
src/utils/richtext.py
Normal file
236
src/utils/richtext.py
Normal file
@@ -0,0 +1,236 @@
|
||||
from datetime import datetime
|
||||
from docx import Document
|
||||
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
|
||||
from docx.enum.table import WD_ROW_HEIGHT_RULE
|
||||
from docx.shared import Pt, RGBColor, Cm, Inches
|
||||
from docx.oxml import OxmlElement
|
||||
from docx.oxml.ns import qn
|
||||
from docx2pdf import convert
|
||||
import win32print
|
||||
import win32api
|
||||
import tempfile
|
||||
import os
|
||||
from os.path import basename
|
||||
|
||||
|
||||
class SemesterDocument:
|
||||
def __init__(self, apparats: list[tuple[int, str]], semester: str, filename):
|
||||
assert isinstance(apparats, list), "Apparats must be a list of tuples"
|
||||
assert all(isinstance(apparat, tuple) for apparat in apparats), (
|
||||
"Apparats must be a list of tuples"
|
||||
)
|
||||
assert all(isinstance(apparat[0], int) for apparat in apparats), (
|
||||
"Apparat numbers must be integers"
|
||||
)
|
||||
assert all(isinstance(apparat[1], str) for apparat in apparats), (
|
||||
"Apparat names must be strings"
|
||||
)
|
||||
assert isinstance(semester, str), "Semester must be a string"
|
||||
assert "." not in filename and isinstance(filename, str), (
|
||||
"Filename must be a string and not contain an extension"
|
||||
)
|
||||
self.doc = Document()
|
||||
self.apparats = apparats
|
||||
self.semester = semester
|
||||
self.table_font = "Arial"
|
||||
self.header_font = "Times New Roman"
|
||||
self.header_font_size = Pt(26)
|
||||
self.sub_header_font_size = Pt(18)
|
||||
self.table_font_size = Pt(10)
|
||||
self.color_red = RGBColor(255, 0, 0)
|
||||
self.color_blue = RGBColor(0, 0, 255)
|
||||
self.filename = filename
|
||||
|
||||
def set_table_border(self, table):
|
||||
"""
|
||||
Adds a full border to the table.
|
||||
|
||||
:param table: Table object to which the border will be applied.
|
||||
"""
|
||||
tbl = table._element
|
||||
tbl_pr = tbl.xpath("w:tblPr")[0]
|
||||
tbl_borders = OxmlElement("w:tblBorders")
|
||||
|
||||
# Define border styles
|
||||
for border_name in ["top", "left", "bottom", "right", "insideH", "insideV"]:
|
||||
border = OxmlElement(f"w:{border_name}")
|
||||
border.set(qn("w:val"), "single")
|
||||
border.set(qn("w:sz"), "4") # Thickness of the border
|
||||
border.set(qn("w:space"), "0")
|
||||
border.set(qn("w:color"), "000000") # Black color
|
||||
tbl_borders.append(border)
|
||||
|
||||
tbl_pr.append(tbl_borders)
|
||||
|
||||
def create_sorted_table(self) -> None:
|
||||
# Sort the apparats list by the string in the tuple (index 1)
|
||||
self.apparats.sort(key=lambda x: x[1])
|
||||
# Create a table with rows equal to the length of the apparats list
|
||||
table = self.doc.add_table(rows=len(self.apparats), cols=2)
|
||||
table.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
|
||||
|
||||
# Set column widths by directly modifying the cell properties
|
||||
widths = [Cm(1.19), Cm(10.39)]
|
||||
for col_idx, width in enumerate(widths):
|
||||
for cell in table.columns[col_idx].cells:
|
||||
cell_width_element = cell._element.xpath(".//w:tcPr")[0]
|
||||
tcW = OxmlElement("w:tcW")
|
||||
tcW.set(qn("w:w"), str(int(width.cm * 567))) # Convert cm to twips
|
||||
tcW.set(qn("w:type"), "dxa")
|
||||
cell_width_element.append(tcW)
|
||||
|
||||
# Adjust row heights
|
||||
for row in table.rows:
|
||||
trPr = row._tr.get_or_add_trPr() # Get or add the <w:trPr> element
|
||||
trHeight = OxmlElement("w:trHeight")
|
||||
trHeight.set(
|
||||
qn("w:val"), str(int(Pt(15).pt * 20))
|
||||
) # Convert points to twips
|
||||
trHeight.set(qn("w:hRule"), "exact") # Use "exact" for fixed height
|
||||
trPr.append(trHeight)
|
||||
|
||||
# Fill the table with sorted data
|
||||
for row_idx, (number, name) in enumerate(self.apparats):
|
||||
row = table.rows[row_idx]
|
||||
|
||||
# Set font for the first column (number)
|
||||
cell_number_paragraph = row.cells[0].paragraphs[0]
|
||||
cell_number_run = cell_number_paragraph.add_run(str(number))
|
||||
cell_number_run.font.name = self.table_font
|
||||
cell_number_run.font.size = self.table_font_size
|
||||
cell_number_run.font.bold = True
|
||||
cell_number_run.font.color.rgb = self.color_red
|
||||
cell_number_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
|
||||
|
||||
# Set font for the second column (name)
|
||||
cell_name_paragraph = row.cells[1].paragraphs[0]
|
||||
words = name.split()
|
||||
if words:
|
||||
# Add the first word in bold
|
||||
bold_run = cell_name_paragraph.add_run(words[0])
|
||||
bold_run.font.bold = True
|
||||
bold_run.font.name = self.table_font
|
||||
bold_run.font.size = self.table_font_size
|
||||
|
||||
# Add the rest of the words normally
|
||||
if len(words) > 1:
|
||||
normal_run = cell_name_paragraph.add_run(" " + " ".join(words[1:]))
|
||||
normal_run.font.name = self.table_font
|
||||
normal_run.font.size = self.table_font_size
|
||||
cell_name_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT
|
||||
|
||||
self.set_table_border(table)
|
||||
|
||||
def make_document(self):
|
||||
# Create a new Document
|
||||
section = self.doc.sections[0]
|
||||
section.top_margin = Cm(2.54) # Default 1 inch (can adjust as needed)
|
||||
section.bottom_margin = Cm(1.5) # Set bottom margin to 1.5 cm
|
||||
section.left_margin = Cm(2.54) # Default 1 inch
|
||||
section.right_margin = Cm(2.54) # Default 1 inch
|
||||
|
||||
# Add the current date
|
||||
current_date = datetime.now().strftime("%Y-%m-%d")
|
||||
date_paragraph = self.doc.add_paragraph(current_date)
|
||||
date_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT
|
||||
|
||||
# Add a header
|
||||
semester = f"Semesterapparate {self.semester}"
|
||||
header = self.doc.add_paragraph(semester)
|
||||
header.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
|
||||
header_run = header.runs[0]
|
||||
header_run.font.name = self.header_font
|
||||
header_run.font.size = self.header_font_size
|
||||
header_run.font.bold = True
|
||||
header_run.font.color.rgb = self.color_blue
|
||||
|
||||
sub_header = self.doc.add_paragraph("(Alphabetisch)")
|
||||
sub_header.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
|
||||
sub_header_run = sub_header.runs[0]
|
||||
sub_header_run.font.name = self.header_font
|
||||
sub_header_run.font.size = self.sub_header_font_size
|
||||
sub_header_run.font.color.rgb = self.color_red
|
||||
|
||||
self.doc.add_paragraph("")
|
||||
|
||||
self.create_sorted_table()
|
||||
|
||||
def save_document(self, name):
|
||||
# Save the document
|
||||
self.doc.save(name)
|
||||
print(f"Document saved as {name}")
|
||||
|
||||
def print_document(self):
|
||||
# send document to printer as attachment of email
|
||||
import smtplib
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.application import MIMEApplication
|
||||
from email.mime.text import MIMEText
|
||||
from src import settings as config
|
||||
|
||||
smtp = config.mail.smtp_server
|
||||
port = config.mail.port
|
||||
sender_email = config.mail.sender
|
||||
password = config.mail.password
|
||||
receiver = "mobileprint@ph-freiburg.de"
|
||||
message = MIMEMultipart()
|
||||
message["From"] = sender_email
|
||||
message["To"] = receiver
|
||||
message["cc"] = config.mail.sender
|
||||
message["Subject"] = "."
|
||||
mail_body = "."
|
||||
message.attach(MIMEText(mail_body, "html"))
|
||||
with open(self.filename + ".pdf", "rb") as fil:
|
||||
part = MIMEApplication(fil.read(), Name=basename(self.filename + "pdf"))
|
||||
# After the file is closed
|
||||
part["Content-Disposition"] = 'attachment; filename="%s"' % basename(
|
||||
self.filename + ".pdf"
|
||||
)
|
||||
message.attach(part)
|
||||
mail = message.as_string()
|
||||
with smtplib.SMTP_SSL(smtp, port) as server:
|
||||
server.connect(smtp, port)
|
||||
server.login(config.mail.user_name, password)
|
||||
server.sendmail(sender_email, receiver, mail)
|
||||
server.quit()
|
||||
print("Mail sent")
|
||||
|
||||
def create_pdf(self):
|
||||
# Save the document
|
||||
import comtypes.client
|
||||
|
||||
word = comtypes.client.CreateObject("Word.Application")
|
||||
self.save_document(self.filename + ".docx")
|
||||
docpath = os.path.abspath(self.filename + ".docx")
|
||||
doc = word.Documents.Open(docpath)
|
||||
curdir = os.getcwd()
|
||||
doc.SaveAs(f"{curdir}/{self.filename}.pdf", FileFormat=17)
|
||||
doc.Close()
|
||||
word.Quit()
|
||||
print("PDF saved")
|
||||
|
||||
def cleanup(self):
|
||||
os.remove(f"{self.filename}.docx")
|
||||
os.remove(f"{self.filename}.pdf")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
apparat = [(i, f"Item {i}") for i in range(405, 438)]
|
||||
doc = SemesterDocument(
|
||||
apparat,
|
||||
"WiSe 24/25",
|
||||
"semap",
|
||||
)
|
||||
doc.make_document()
|
||||
doc.create_pdf()
|
||||
# doc.print_document()
|
||||
|
||||
|
||||
# def printers():
|
||||
# printers = win32print.EnumPrinters(
|
||||
# win32print.PRINTER_ENUM_LOCAL | win32print.PRINTER_ENUM_CONNECTIONS
|
||||
# )
|
||||
# for i, printer in enumerate(printers):
|
||||
# print(f"{i}: {printer[2]}")
|
||||
|
||||
# list printers
|
||||
Reference in New Issue
Block a user