From 9cc08e2d91537e61daf25bb097a71988862a18c5 Mon Sep 17 00:00:00 2001 From: WorldTeacher Date: Mon, 14 Apr 2025 11:07:06 +0200 Subject: [PATCH 1/3] start work on readme file --- README.md | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 27a67a7..fc6e6f7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,27 @@ -# Semesterapparate +# SemesterapparatsManager -this repo will be used to create a GUI application to manage the semesterapparate of the PH Freiburg. \ No newline at end of file +SemesterapparatsManager is a graphical tool for managing semester apparatuses in the University of Education Freiburg. It allows the users to manage the semester apparatuses in a user-friendly way. It's functions include management of physical and digital semester apparatuses, as well as creating the citations for the digital files of the digital semester apparatuses. For that it uses Zotero, an open source reference management software. The semester apparatuses are stored in a SQLite database, which is created and managed by the SemesterapparatsManager. The SemesterapparatsManager is written in Python and uses the PyQt6 library for the graphical user interface + + +## Features +- Manage physical semester apparatuses + - Add semester apparatuses + - Edit semester apparatuses + - Delete semester apparatuses + - Extend semester apparatuses + - Notify professors about semester apparatuses creation or deletion + - Add messages to all semester apparatuses, or an individual semester apparatus +- Manage digital semester apparatuses + - Use text parsing to extract information from the submitted form and create the scans + - if a book is used multiple parts of a book are used, it can be split into the parts + - Create the matching citations for the files +- Statistics and Search + - Search semester apparatuses by various criteria + - Show statistics about the semester apparatuses creation and deletion +- Edit user data + + +## Images + +![Main Window](docs/images/mainUI.png) +![Statistics](docs/images/statistics.png) \ No newline at end of file -- 2.49.1 From f0148d8855f5f32d8aefddfc15819e86e1a00d81 Mon Sep 17 00:00:00 2001 From: WorldTeacher Date: Mon, 14 Apr 2025 11:07:48 +0200 Subject: [PATCH 2/3] add image, rework SemesterDocument --- docs/images/statistics.png | Bin 0 -> 30670 bytes src/utils/richtext.py | 82 +++++++++++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 18 deletions(-) create mode 100644 docs/images/statistics.png diff --git a/docs/images/statistics.png b/docs/images/statistics.png new file mode 100644 index 0000000000000000000000000000000000000000..55dea3fb91830b9cbfa09cc424a44523e53cd010 GIT binary patch literal 30670 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 literal 0 HcmV?d00001 diff --git a/src/utils/richtext.py b/src/utils/richtext.py index 9ceb250..8da249d 100644 --- a/src/utils/richtext.py +++ b/src/utils/richtext.py @@ -6,22 +6,57 @@ from docx.oxml import OxmlElement from docx.oxml.ns import qn import os from os.path import basename +from loguru import logger as log +import sys + + +logger = log +logger.remove() +logger.add("logs/application.log", rotation="1 week", enqueue=True) +log.add( + f"logs/{datetime.now().strftime('%Y-%m-%d')}.log", + rotation="1 day", + compression="zip", +) + +# logger.add(sys.stderr, format="{time} {level} {message}", level="INFO") +logger.add(sys.stdout) + + +class SemesterError(Exception): + """Custom exception for semester-related errors.""" + + def __init__(self, message): + super().__init__(message) + logger.error(message) + + def __str__(self): + return f"SemesterError: {self.args[0]}" 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), ( + def __init__( + self, + apparats: list[tuple[int, str]], + semester: str, + filename, + config, + full: bool = False, + ): + assert isinstance(apparats, list), SemesterError( "Apparats must be a list of tuples" ) - assert all(isinstance(apparat[0], int) for apparat in apparats), ( + assert all(isinstance(apparat, tuple) for apparat in apparats), SemesterError( + "Apparats must be a list of tuples" + ) + assert all(isinstance(apparat[0], int) for apparat in apparats), SemesterError( "Apparat numbers must be integers" ) - assert all(isinstance(apparat[1], str) for apparat in apparats), ( + assert all(isinstance(apparat[1], str) for apparat in apparats), SemesterError( "Apparat names must be strings" ) - assert isinstance(semester, str), "Semester must be a string" - assert "." not in filename and isinstance(filename, str), ( + assert isinstance(semester, str), SemesterError("Semester must be a string") + assert "." not in filename and isinstance(filename, str), SemesterError( "Filename must be a string and not contain an extension" ) self.doc = Document() @@ -35,7 +70,17 @@ class SemesterDocument: self.color_red = RGBColor(255, 0, 0) self.color_blue = RGBColor(0, 0, 255) self.filename = filename - + self.settings = config + if full: + logger.info("Full document generation") + self.make_document() + logger.info("Document created") + self.create_pdf() + logger.info("PDF created") + self.print_document() + logger.info("Document printed") + self.cleanup() + logger.info("Cleanup done") def set_table_border(self, table): """ Adds a full border to the table. @@ -161,8 +206,8 @@ class SemesterDocument: from email.mime.multipart import MIMEMultipart from email.mime.application import MIMEApplication from email.mime.text import MIMEText - from src import settings as config + config = self.settings smtp = config.mail.smtp_server port = config.mail.port sender_email = config.mail.sender @@ -202,7 +247,7 @@ class SemesterDocument: doc.SaveAs(f"{curdir}/{self.filename}.pdf", FileFormat=17) doc.Close() word.Quit() - print("PDF saved") + logger.debug("PDF saved") def cleanup(self): os.remove(f"{self.filename}.docx") @@ -210,14 +255,15 @@ class SemesterDocument: 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() + pass + # 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() -- 2.49.1 From da0e9e072505f959a6e865752824ab5d45ce035c Mon Sep 17 00:00:00 2001 From: WorldTeacher Date: Mon, 14 Apr 2025 11:08:15 +0200 Subject: [PATCH 3/3] fix bug in document creation --- src/ui/userInterface.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/ui/userInterface.py b/src/ui/userInterface.py index 9cbddfc..68b61d3 100644 --- a/src/ui/userInterface.py +++ b/src/ui/userInterface.py @@ -12,7 +12,7 @@ from PyQt6 import QtCore, QtGui, QtWidgets from PyQt6.QtCore import QThread from PyQt6.QtGui import QRegularExpressionValidator -from src import Icon, logger +from src import Icon, logger, settings from src.backend import Database, BookGrabber, AvailChecker, DocumentationThread from src.backend.semester import Semester from src.backend.create_file import recreateFile @@ -241,7 +241,8 @@ class Ui(Ui_Semesterapparat): "Mit dem Klick auf Okay wird eine Übersicht aller aktiven Semesterapparate erstellt und an den FollowME Drucker gesendet. Es kann bis zu 10 Minuten dauern, bis das document im Drucker angezeigt wird", "document erstellen?", ) - if result == QtWidgets.QDialog.DialogCode.Accepted: + logger.debug(f"Result: {result}") + if result == 1: # print("Creating document") apparats = self.apparats apps = [] @@ -250,15 +251,19 @@ class Ui(Ui_Semesterapparat): data = (apparat[4], f"{prof.lastname} ({apparat[1]})") apps.append(data) # print(apps) + logger.info("Using apparats: {}", apps) doc = SemesterDocument( - semester=Semester(), + semester=Semester().value, filename="Semesterapparate", apparats=apps, + full=True, + config=settings, ) - doc.make_document() - doc.create_pdf() - doc.print_document() - doc.cleanup() + # doc.make_document() + # doc.create_pdf() + # doc.print_document() + # doc.cleanup() + # logger.info("Document created and sent to printer") # kill thread after execution done -- 2.49.1