Add Adminbereich section with overview and user management pages to navigation, other changes

This commit is contained in:
2025-12-01 12:57:15 +01:00
parent c7304b484a
commit dbfcdbd013
27 changed files with 360 additions and 818 deletions

View File

@@ -669,7 +669,7 @@ Nachname, Vorname</string>
</spacer>
</item>
<item>
<widget class="QToolButton" name="copy_qoute">
<widget class="QToolButton" name="copy_quote">
<property name="text">
<string>Kopieren</string>
</property>
@@ -763,7 +763,7 @@ Nachname, Vorname</string>
<tabstop>ilias_filename</tabstop>
<tabstop>copy_filename</tabstop>
<tabstop>copy_ilias_filename</tabstop>
<tabstop>copy_qoute</tabstop>
<tabstop>copy_quote</tabstop>
<tabstop>retryButton</tabstop>
</tabstops>
<resources/>

View File

@@ -18,13 +18,13 @@ class ElsaAddEntry(QtWidgets.QDialog, Ui_Dialog):
self.setupUi(self)
self.setWindowTitle("Eintrag zitieren")
self.buttonBox.button(
QtWidgets.QDialogButtonBox.StandardButton.Ok
QtWidgets.QDialogButtonBox.StandardButton.Ok,
).clicked.connect(self.accept)
self.buttonBox.button(
QtWidgets.QDialogButtonBox.StandardButton.Cancel
QtWidgets.QDialogButtonBox.StandardButton.Cancel,
).clicked.connect(self.close)
self.buttonBox.button(
QtWidgets.QDialogButtonBox.StandardButton.Discard
QtWidgets.QDialogButtonBox.StandardButton.Discard,
).clicked.connect(self.discard)
self.mode = None
self.btn_search.clicked.connect(self.search)
@@ -33,13 +33,13 @@ class ElsaAddEntry(QtWidgets.QDialog, Ui_Dialog):
self.btn_hg.clicked.connect(self.stack)
self.make_quote.clicked.connect(self.display_data)
self.copy_filename.clicked.connect(
lambda: self.copy_to_clipboard(self.filename_edit)
lambda: self.copy_to_clipboard(self.filename_edit),
)
self.copy_ilias_filename.clicked.connect(
lambda: self.copy_to_clipboard(self.ilias_filename)
lambda: self.copy_to_clipboard(self.ilias_filename),
)
self.copy_qoute.clicked.connect(
lambda: self.copy_to_clipboard(self.file_desc_edit)
self.copy_quote.clicked.connect(
lambda: self.copy_to_clipboard(self.file_desc_edit),
)
self.setWindowIcon(Icon("edit").icon)
self.stackedWidget.setEnabled(False)
@@ -61,11 +61,11 @@ class ElsaAddEntry(QtWidgets.QDialog, Ui_Dialog):
def check_pages(self):
if self.source_pages:
if self.book_pages.text() != self.source_pages:
self.make_quote.setEnabled(True)
elif self.hg_pages.text() != self.source_pages:
self.make_quote.setEnabled(True)
elif self.zs_pages.text() != self.source_pages:
if (
self.book_pages.text() != self.source_pages
or self.hg_pages.text() != self.source_pages
or self.zs_pages.text() != self.source_pages
):
self.make_quote.setEnabled(True)
def copy_to_clipboard(self, field):

View File

@@ -1,4 +1,5 @@
# encoding: utf-8
from __future__ import annotations
import atexit
import os
import sys
@@ -6,7 +7,7 @@ import tempfile
import time
import webbrowser
from pathlib import Path
from typing import Any, List, Optional, Tuple, Union
from typing import Any, Optional, Union
from natsort import natsorted
from PySide6 import QtCore, QtGui, QtWidgets
@@ -15,14 +16,13 @@ from PySide6.QtGui import QRegularExpressionValidator
from PySide6.QtMultimedia import QAudioOutput, QMediaPlayer
from src import Icon
from src.database import Database
from src.background import (
AvailChecker,
BookGrabber,
DocumentationThread,
NewEditionCheckerThread,
)
from src.utils.files import recreateFile, delete_temp_contents as tempdelete
from src.core.constants import APP_NRS
from src.core.models import (
Apparat,
ApparatData,
@@ -31,15 +31,15 @@ from src.core.models import (
SemapDocument,
Semester,
)
from src.core.constants import APP_NRS
from src.parsers import (
csv_to_list,
)
from src.database import Database
from src.logic import (
eml_to_semap,
pdf_to_semap,
word_to_semap,
)
from src.parsers import (
csv_to_list,
)
from src.shared.logging import log
from src.ui import Ui_Semesterapparat
from src.ui.dialogs import (
@@ -71,6 +71,8 @@ from src.ui.widgets import (
UpdateSignatures,
UserCreate,
)
from src.utils.files import delete_temp_contents as tempdelete
from src.utils.files import recreateFile
log.success("UI started")
valid_input = (0, 0, 0, 0, 0, 0)
@@ -86,17 +88,17 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
self.MainWindow = MainWindow # type:ignore
# set the window title
MainWindow.setWindowTitle(
f"Semesterapparatsmanagement Semester: {Semester().value}"
f"Semesterapparatsmanagement Semester: {Semester().value}",
) # type:ignore
MainWindow.setWindowIcon(Icon("logo").icon) # type:ignore
self.db = Database()
self.btn_add_document.clicked.connect(self.add_document) # type:ignore
self.check_file.clicked.connect( # type:ignore
self.btn_check_file_threaded
self.btn_check_file_threaded,
) # default: self.add_media_from_file
self.btn_extract_data_from_document.clicked.connect( # type:ignore
self.import_data_from_document
self.import_data_from_document,
)
self.create_new_app.clicked.connect(self.btn_create_new_apparat) # type:ignore
self.btn_apparat_save.clicked.connect(lambda: self.btn_save_apparat(True)) # type:ignore
@@ -109,17 +111,17 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
self.calendarWidget = MessageCalendar(self.calendar_frame)
self.calendarWidget.setGridVisible(True)
self.calendarWidget.setVerticalHeaderFormat(
QtWidgets.QCalendarWidget.VerticalHeaderFormat.NoVerticalHeader
QtWidgets.QCalendarWidget.VerticalHeaderFormat.NoVerticalHeader,
)
self.calendarWidget.setObjectName("MessageCalendar")
self.calendarWidget.clicked.connect(self.open_reminder) # type:ignore
# assign a context menu to the calendar
self.calendarlayout.addWidget(self.calendarWidget)
self.tableWidget_apparat_media.horizontalHeader().setSectionResizeMode( # type:ignore
QtWidgets.QHeaderView.ResizeMode.Stretch
QtWidgets.QHeaderView.ResizeMode.Stretch,
)
self.tableWidget_apparate.horizontalHeader().setSectionResizeMode( # type:ignore
QtWidgets.QHeaderView.ResizeMode.Stretch
QtWidgets.QHeaderView.ResizeMode.Stretch,
)
self.saveandcreate.hide()
@@ -140,29 +142,30 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
self.prof_mail.setValidator(
QRegularExpressionValidator(
QtCore.QRegularExpression(
r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}"
)
)
r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}",
),
),
)
self.prof_tel_nr.setValidator(QtGui.QIntValidator())
self.prof_tel_nr.setValidator(
QtGui.QRegularExpressionValidator(QtCore.QRegularExpression(r"^\d{3,14}"))
QtGui.QRegularExpressionValidator(QtCore.QRegularExpression(r"^\d{3,14}")),
)
# #log.debug(self.prof_tel_nr.maxLength())
self.app_fach.setValidator( # validator to allow typing in the app_fach field
QtGui.QRegularExpressionValidator(
QtCore.QRegularExpression(r"[a-zA-Z0-9\s\W]+")
)
QtCore.QRegularExpression(r"[a-zA-Z0-9\s\W]+"),
),
)
# allow only letters, numbers, whitespaces, symbols for the apparat name
self.app_name.setValidator(
QtGui.QRegularExpressionValidator(
QtCore.QRegularExpression(r"[a-zA-Z0-9\s\W]+")
)
QtCore.QRegularExpression(r"[a-zA-Z0-9\s\W]+"),
),
)
self.tableWidget_apparate.addScrollBarWidget(
QtWidgets.QScrollBar(), QtCore.Qt.AlignmentFlag.AlignRight
QtWidgets.QScrollBar(),
QtCore.Qt.AlignmentFlag.AlignRight,
)
self.tableWidget_apparate.doubleClicked.connect(self.load_app_data) # type:ignore
@@ -229,16 +232,16 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
# Context Menus
self.tableWidget_apparate.setContextMenuPolicy(
QtCore.Qt.ContextMenuPolicy.CustomContextMenu
QtCore.Qt.ContextMenuPolicy.CustomContextMenu,
)
self.tableWidget_apparat_media.setContextMenuPolicy(
QtCore.Qt.ContextMenuPolicy.CustomContextMenu
QtCore.Qt.ContextMenuPolicy.CustomContextMenu,
)
self.tableWidget_apparate.customContextMenuRequested.connect( # type:ignore
self.open_context_menu # type:ignore
self.open_context_menu, # type:ignore
)
self.tableWidget_apparat_media.customContextMenuRequested.connect( # type:ignore
self.media_context_menu # type:ignore
self.media_context_menu, # type:ignore
)
# admin buttons
@@ -252,7 +255,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
self.bookGrabber: list[QThread] = []
self.availChecker = None
self.mail_thread = None
self.autoGrabber = None
self.auto_grabber = None
self.newEditionChecker = NewEditionCheckerThread()
self.elsatab.setLayout(QtWidgets.QVBoxLayout())
@@ -278,7 +281,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
# allow files to be dragged into document_list
self.document_list.setDragDropMode(
QtWidgets.QAbstractItemView.DragDropMode.DropOnly
QtWidgets.QAbstractItemView.DragDropMode.DropOnly,
)
self.document_list.setAcceptDrops(True)
self.document_list.viewport().setAcceptDrops(True)
@@ -295,24 +298,18 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
# Only handle events for document_list and its viewport
if obj in (self.document_list, self.document_list.viewport()):
et = event.type()
if et == QtCore.QEvent.Type.DragEnter:
if et == QtCore.QEvent.Type.DragEnter or et == QtCore.QEvent.Type.DragMove:
if event.mimeData().hasUrls():
event.setDropAction(QtCore.Qt.CopyAction)
event.acceptProposedAction()
else:
event.ignore()
return True
elif et == QtCore.QEvent.Type.DragMove:
if event.mimeData().hasUrls():
event.setDropAction(QtCore.Qt.CopyAction)
event.acceptProposedAction()
else:
event.ignore()
return True
elif et == QtCore.QEvent.Type.Drop:
if et == QtCore.QEvent.Type.Drop:
if not self.app_group_box.isEnabled():
self.confirm_popup(
"Bitte öffnen Sie zuerst einen Apparat!", title="Fehler"
"Bitte öffnen Sie zuerst einen Apparat!",
title="Fehler",
)
return True
if event.mimeData().hasUrls():
@@ -474,15 +471,16 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
elsa_layout.addWidget(ElsaDialog())
# log.debug("added")
pass
def generateSemester(self, today=False):
"""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 Semester()
@@ -492,8 +490,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
semester = "SoSe" if self.sem_sommer.isChecked() else "WiSe"
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: Union[int, str]):
if self.load_app_data(apparat):
@@ -647,7 +644,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
def validate_semester(self):
valid = (self.sem_sommer.isChecked() or self.sem_winter.isChecked()) and len(
self.sem_year.text()
self.sem_year.text(),
) >= 2
if valid or self.check_eternal_app.isChecked():
self.__setValidState(self.valid_check_semester, 1, self._mand, 5)
@@ -749,7 +746,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
def update_document_list(self):
app_id = self.active_apparat
prof_id = self.db.getProfByName(
self.drpdwn_prof_name.currentText().replace(",", "")
self.drpdwn_prof_name.currentText().replace(",", ""),
).id
files = self.db.getFiles(app_id, prof_id)
for file in files:
@@ -827,7 +824,8 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
self.progress_label.setText("Bitte warten...")
if data == []:
self.confirm_popup(
"Bitte mindestens ein Medium hinzufügen!", title="Fehler"
"Bitte mindestens ein Medium hinzufügen!",
title="Fehler",
)
app_nr = self.db.getId(self.app_name.text())
@@ -866,7 +864,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
def check_availability(self):
def _update_progress(current, all_titles):
self.avail_status.setText("{}/{}".format(current, all_titles))
self.avail_status.setText(f"{current}/{all_titles}")
def _hide_progress_label():
self.label_20.hide()
@@ -885,8 +883,9 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
else:
links = [
self.tableWidget_apparat_media.item(
self.tableWidget_apparat_media.currentRow(), 1
).text()
self.tableWidget_apparat_media.currentRow(),
1,
).text(),
]
# get the number of selected rows from the table
items = self.tableWidget_apparat_media.rowCount()
@@ -961,7 +960,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
# # #log.debug(bd, type(bd))
# create a new row below the last one
self.tableWidget_apparat_media.insertRow(
self.tableWidget_apparat_media.rowCount()
self.tableWidget_apparat_media.rowCount(),
)
# #set the data
self.tableWidget_apparat_media.setItem(
@@ -989,10 +988,12 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
label.setTextFormat(QtCore.Qt.TextFormat.RichText)
label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
label.setTextInteractionFlags(
QtCore.Qt.TextInteractionFlag.TextBrowserInteraction
QtCore.Qt.TextInteractionFlag.TextBrowserInteraction,
)
self.tableWidget_apparat_media.setCellWidget(
self.tableWidget_apparat_media.rowCount() - 1, 6, label
self.tableWidget_apparat_media.rowCount() - 1,
6,
label,
)
if availability == 1:
# display green checkmark at column 4 in the row
@@ -1003,7 +1004,8 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
)
# set tooltip
self.tableWidget_apparat_media.item(
self.tableWidget_apparat_media.rowCount() - 1, 4
self.tableWidget_apparat_media.rowCount() - 1,
4,
).setToolTip("Das Medium wurde im Apparat gefunden")
else:
self.tableWidget_apparat_media.setItem(
@@ -1012,21 +1014,21 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
QtWidgets.QTableWidgetItem(""),
)
self.tableWidget_apparat_media.item(
self.tableWidget_apparat_media.rowCount() - 1, 4
self.tableWidget_apparat_media.rowCount() - 1,
4,
).setToolTip("Das Medium wurde nicht im Apparat gefunden")
def open_link(self, item):
def __openLink(link):
if link == "":
return
return None
if "http" not in link:
link = "https://" + link
return link
#
# get the name of the column
columnname = self.tableWidget_apparat_media.horizontalHeaderItem(
item.column()
item.column(),
).text()
if columnname == "Link":
link = __openLink(item.text())
@@ -1086,18 +1088,21 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
_selected_doc_filetype = ""
try:
_selected_doc_name = self.document_list.item(
self.document_list.currentRow(), 0
self.document_list.currentRow(),
0,
).text()
_selected_doc_location = self.document_list.item(
self.document_list.currentRow(), 3
self.document_list.currentRow(),
3,
).text()
_selected_doc_filetype = self.document_list.item(
self.document_list.currentRow(), 1
self.document_list.currentRow(),
1,
).text()
except AttributeError:
self.confirm_popup("Bitte erst ein Dokument auswählen!", title="Fehler")
return
if not _selected_doc_location == "Database":
if _selected_doc_location != "Database":
path = Path(_selected_doc_location)
# path: Path = path.resolve()
# path.
@@ -1110,7 +1115,9 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
os.system(f"open {path}")
else:
recreateFile(
_selected_doc_name, self.active_apparat, filetype=_selected_doc_filetype
_selected_doc_name,
self.active_apparat,
filetype=_selected_doc_filetype,
)
def add_media_from_file(self):
@@ -1138,78 +1145,87 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
# if files are in the table, and are selected, check for books in the file
if self.document_list.rowCount() == 0:
return
else:
# if file is selected, check for books in the file
if self.document_list.currentRow() != -1:
# #log.debug("File selected")
file = self.document_list.item(
self.document_list.currentRow(), 3
).text()
# if file is selected, check for books in the file
if self.document_list.currentRow() != -1:
# #log.debug("File selected")
file = self.document_list.item(
self.document_list.currentRow(),
3,
).text()
file_type = self.document_list.item(
self.document_list.currentRow(), 1
).text()
file_location = self.document_list.item(
self.document_list.currentRow(), 3
).text()
file_name = self.document_list.item(
self.document_list.currentRow(), 0
).text()
if file_location == "Database":
# create a temporaty file to use, delete it after use
temp_file = tempfile.NamedTemporaryFile(
delete=False, suffix="." + file_type
file_type = self.document_list.item(
self.document_list.currentRow(),
1,
).text()
file_location = self.document_list.item(
self.document_list.currentRow(),
3,
).text()
file_name = self.document_list.item(
self.document_list.currentRow(),
0,
).text()
if file_location == "Database":
# create a temporaty file to use, delete it after use
temp_file = tempfile.NamedTemporaryFile(
delete=False,
suffix="." + file_type,
)
temp_file.write(self.db.getBlob(file_name, int(app_id)))
temp_file.close()
file = temp_file.name
if file_type == "pdf":
data = pdf_to_semap(file)
signatures = data.signatures
data = __open_dialog(signatures)
# if no data was returned, return
if data == []:
return
for book in data:
if not isinstance(book, BookData):
continue
self.db.addBookToDatabase(
bookdata=book,
app_id=app_id,
prof_id=prof_id,
)
temp_file.write(self.db.getBlob(file_name, int(app_id)))
temp_file.close()
file = temp_file.name
if file_type == "pdf":
data = pdf_to_semap(file)
signatures = data.signatures
data = __open_dialog(signatures)
# if no data was returned, return
if data == []:
return
for book in data:
if not isinstance(book, BookData):
continue
self.db.addBookToDatabase(
bookdata=book,
app_id=app_id,
prof_id=prof_id,
)
if file_type == "csv":
signatures = csv_to_list(file)
data = __open_dialog(signatures)
# add the data to the database
for book in data:
if not isinstance(book, BookData):
continue
self.db.addBookToDatabase(
bookdata=book, app_id=app_id, prof_id=prof_id
)
if file_type == "docx":
data = word_to_semap(file)
signatures = data.signatures
data = __open_dialog(signatures)
# if no data was returned, return
if data == []:
return
for book in data:
if not isinstance(book, BookData):
continue
self.db.addBookToDatabase(
bookdata=book, app_id=app_id, prof_id=prof_id
)
if file_type == "eml":
data = eml_to_semap(file)
self.update_app_media_list()
# #log.debug(len(signatures))
if file_type == "csv":
signatures = csv_to_list(file)
data = __open_dialog(signatures)
# add the data to the database
for book in data:
if not isinstance(book, BookData):
continue
self.db.addBookToDatabase(
bookdata=book,
app_id=app_id,
prof_id=prof_id,
)
if file_type == "docx":
data = word_to_semap(file)
signatures = data.signatures
data = __open_dialog(signatures)
# if no data was returned, return
if data == []:
return
for book in data:
if not isinstance(book, BookData):
continue
self.db.addBookToDatabase(
bookdata=book,
app_id=app_id,
prof_id=prof_id,
)
if file_type == "eml":
data = eml_to_semap(file)
self.update_app_media_list()
# #log.debug(len(signatures))
def extract_document_data(self) -> Union[list[str], SemapDocument]:
def extract_document_data(self) -> list[str] | SemapDocument:
file_type = self.document_list.item(self.document_list.currentRow(), 1).text()
file_location = self.document_list.item(
self.document_list.currentRow(), 3
self.document_list.currentRow(),
3,
).text()
file_name = self.document_list.item(self.document_list.currentRow(), 0).text()
file = file_location
@@ -1217,10 +1233,12 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
if file_location == "Database":
# create warning, then return
file = self.db.recreateFile(
file_name, self.active_apparat, filetype=file_type
file_name,
self.active_apparat,
filetype=file_type,
)
if file_type == "pdf":
# Todo: implement parser here
# TODO: implement parser here
self.confirm_popup("PDF Dateien werden nicht unterstützt!", title="Fehler")
return [""]
if file_type == "csv":
@@ -1233,8 +1251,14 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
log.debug("Got the data: {}", data)
return data
else:
raise ValueError("Dateityp wird nicht unterstützt")
if file_type == "eml":
data = eml_to_semap(file)
log.info("Converted data from eml file")
log.debug("Got the data: {}", data)
return data
error = "Dateityp wird nicht unterstützt"
raise ValueError(error)
def import_data_from_document(self):
global valid_input
@@ -1254,7 +1278,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
dialog.setModal(True)
layout = QtWidgets.QVBoxLayout()
label = QtWidgets.QLabel(
f"Bitte wählen Sie einen Titel aus:/nDer Titel darf max. {data.title_max_length} Zeichen lang sein."
f"Bitte wählen Sie einen Titel aus:/nDer Titel darf max. {data.title_max_length} Zeichen lang sein.",
)
layout.addWidget(label)
dropdown = QtWidgets.QComboBox()
@@ -1264,7 +1288,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
button_box = QtWidgets.QDialogButtonBox()
button_box.setStandardButtons(
QtWidgets.QDialogButtonBox.StandardButton.Cancel
| QtWidgets.QDialogButtonBox.StandardButton.Ok
| QtWidgets.QDialogButtonBox.StandardButton.Ok,
)
button_box.accepted.connect(dialog.accept)
button_box.rejected.connect(dialog.reject)
@@ -1306,7 +1330,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
# get active app_id and prof_id
self.tableWidget_apparate.setEnabled(False)
self.tableWidget_apparate.setToolTip(
"Bitte warten, bis alle Medien hinzugefügt wurden"
"Bitte warten, bis alle Medien hinzugefügt wurden",
)
app_id = self.active_apparat
log.debug(self.profdata)
@@ -1336,50 +1360,48 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
self.tableWidget_apparate.setEnabled(True)
self.tableWidget_apparate.setToolTip("")
return
# if file is selected, check for books in the file
# #log.debug("File selected")
if prof_id is None:
prof_id = self.db.getProfId(self.profdata)
# log.debug("Prof ID is None", prof_id)
document = None
if c_document is None or not isinstance(c_document, SemapDocument):
document = self.extract_document_data()
if document is None:
log.error("Document is None")
elif isinstance(document, SemapDocument):
signatures = document.signatures
else:
# if file is selected, check for books in the file
# #log.debug("File selected")
signatures = document
if isinstance(signatures, SemapDocument):
signatures = signatures.signatures
auto_grabber = BookGrabber()
auto_grabber.add_values(
mode="ARRAY",
app_id=app_id,
prof_id=int(prof_id),
data=signatures,
any_book=True,
exact=True,
)
self.label_info.show()
self.progress_label.show()
self.line_2.show()
auto_grabber.finished.connect(self.hide_progress_label)
auto_grabber.finished.connect(self.unlock_apparate)
auto_grabber.updateSignal.connect(self.update_progress_label)
if prof_id is None:
prof_id = self.db.getProfId(self.profdata)
# log.debug("Prof ID is None", prof_id)
document = None
if c_document is None or not isinstance(c_document, SemapDocument):
document = self.extract_document_data()
if document is None:
log.error("Document is None")
elif isinstance(document, SemapDocument):
signatures = document.signatures
else:
signatures = document
autoGrabber = BookGrabber()
autoGrabber.add_values(
mode="ARRAY",
app_id=app_id,
prof_id=int(prof_id),
data=signatures,
any_book=True,
exact=True,
)
self.label_info.show()
self.progress_label.show()
self.line_2.show()
# grabber.finished.connect(thread.quit)
# self.autoGrabber.finished.connect(self.autoGrabber.deleteLater)
autoGrabber.finished.connect(self.hide_progress_label)
autoGrabber.finished.connect(self.unlock_apparate)
autoGrabber.updateSignal.connect(self.update_progress_label)
# worker.finished.connect(worker.deleteLater)
autoGrabber.start()
self.bookGrabber.append(autoGrabber)
# refresh book table
# end of thread
# self.autoGrabber.exit()
# self.__clear_fields()
# self.btn_cancel_active_selection()
auto_grabber.start()
self.bookGrabber.append(auto_grabber)
# refresh book table
# end of thread
# self.auto_grabber.exit()
# self.__clear_fields()
# self.btn_cancel_active_selection()
def unlock_apparate(self):
self.tableWidget_apparate.setEnabled(True)
@@ -1442,12 +1464,12 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
self.add_files()
if error is not None:
self.confirm_popup(error.__str__(), title="Fehler")
return
return None
appdata = self.db.getAllAparats()
# merge self.appdata and appdata, remove duplicates
self.apparats = self.__uniques(self.apparats, appdata)
self.apparats = natsorted(self.apparats, key=lambda x: x[4], reverse=True)
self.apparats = natsorted(self.apparats, key=lambda x: x.appnr, reverse=True)
self.update_apparat_list()
@@ -1465,7 +1487,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
self.__clear_fields()
return True
def __uniques(self, list1, list2):
def __uniques(self, list1: list[Apparat], list2: list[Apparat]) -> list[Apparat]:
seen = set()
unique_list = []
for item in list1 + list2:
@@ -1475,7 +1497,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
unique_list.append(item)
return unique_list
def send_mail_preview(self):
def send_mail_preview(self) -> None:
pass
@property
@@ -1491,14 +1513,14 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
"prof_tel": self.prof_tel_nr.text(),
}
def add_files(self):
"""
Add Files to the associated prof in the database
def add_files(self) -> None:
"""Add Files to the associated prof in the database.
Parameters
----------
prof_id : int, optional
The ID associated to the prof, by default None
"""
files: list[dict[str, Any]] = []
for i in range(self.document_list.rowCount()):
@@ -1508,7 +1530,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
"type": self.document_list.item(i, 1).text(),
"date": self.document_list.item(i, 2).text(),
"path": self.document_list.item(i, 3).text(),
}
},
)
self.document_list.item(i, 2).setText("")
@@ -1521,7 +1543,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
"profname": self.drpdwn_prof_name.currentText(),
"prof_mail": self.prof_mail.text(),
"prof_tel": self.prof_tel_nr.text(),
}
},
),
)
@@ -1530,7 +1552,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
for apparat in self.apparats:
self.insert_apparat_into_table(apparat)
log.info("Inserted {} apparats into table".format(len(self.apparats)))
log.info(f"Inserted {len(self.apparats)} apparats into table")
def insert_apparat_into_table(self, apparat: Apparat):
# log.debug(apparat)
@@ -1544,16 +1566,20 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
)
self.tableWidget_apparate.insertRow(0)
self.tableWidget_apparate.setItem(
0, 0, QtWidgets.QTableWidgetItem(str(apparat.appnr))
0,
0,
QtWidgets.QTableWidgetItem(str(apparat.appnr)),
)
self.tableWidget_apparate.setItem(
0, 1, QtWidgets.QTableWidgetItem(str(apparat.name))
0,
1,
QtWidgets.QTableWidgetItem(str(apparat.name)),
)
self.tableWidget_apparate.setItem(
0,
2,
QtWidgets.QTableWidgetItem(
self.db.getProfNameById(apparat.prof_id, add_title=False)
self.db.getProfNameById(apparat.prof_id, add_title=False),
),
)
self.tableWidget_apparate.setItem(
@@ -1562,10 +1588,14 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
QtWidgets.QTableWidgetItem(str(semester)),
)
self.tableWidget_apparate.setItem(
0, 4, QtWidgets.QTableWidgetItem(__dauer_check(apparat))
0,
4,
QtWidgets.QTableWidgetItem(__dauer_check(apparat)),
)
self.tableWidget_apparate.setItem(
0, 5, QtWidgets.QTableWidgetItem(str(apparat.konto))
0,
5,
QtWidgets.QTableWidgetItem(str(apparat.konto)),
)
def open_context_menu(self, position):
@@ -1584,7 +1614,7 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
remind_action,
new_edition_check,
order_newedition_action,
]
],
)
# convert point to row and column
row = self.tableWidget_apparate.rowAt(position.y())
@@ -1599,12 +1629,12 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
remind_action.triggered.connect(self.reminder)
new_edition_check.triggered.connect(lambda: self.check_new_editions())
order_newedition_action.triggered.connect(
lambda: self.order_new_editions(app_id, pid)
lambda: self.order_new_editions(app_id, pid),
)
delete_action.triggered.connect(lambda: self.delete_apparat(pos))
# pass pos to contact_prof
contact_action.triggered.connect(
lambda: self.contact_prof(pid=pid, apparat=app_id)
lambda: self.contact_prof(pid=pid, apparat=app_id),
)
menu.exec(self.tableWidget_apparate.mapToGlobal(position))
@@ -1641,20 +1671,23 @@ class Ui(QtWidgets.QMainWindow, Ui_Semesterapparat):
pick = selector.selection
app_id = self.tableWidget_apparate.item(
self.tableWidget_apparate.currentRow(), 0
self.tableWidget_apparate.currentRow(),
0,
).text()
prof_id: int = self.db.getProfIDByApparat(app_id)
app_name = self.tableWidget_apparate.item(
self.tableWidget_apparate.currentRow(), 1
self.tableWidget_apparate.currentRow(),
1,
).text()
subject = self.tableWidget_apparate.item(
self.tableWidget_apparate.currentRow(), 4
self.tableWidget_apparate.currentRow(),
4,
).text()
if pick == "professor":
books = self.db.getBooksByProfId(prof_id)
app_name = "Sammelmail"
app_id = ", ".join(
[str(app.appnr) for app in self.db.getApparatsByProf(prof_id)]
[str(app.appnr) for app in self.db.getApparatsByProf(prof_id)],
)
else:
apparats_id = self.db.getId(app_name)
@@ -1702,10 +1735,9 @@ WHERE m.id = ?""",
for book in accepted_books:
oldBookId = self.db.getBookIdByPPN(book.old_book.ppn)
apparats_id = self.db.getId(
self.db.getApparatNameByAppNr(book.old_book.library_location)
self.db.getApparatNameByAppNr(book.old_book.library_location),
)
self.db.insertNewEdition(book, oldBookId, apparats_id)
pass
self.mail_thread = Mail_Dialog(
prof_name=self.db.getSpecificProfData(prof_id, ["fullname"]),
@@ -1799,7 +1831,7 @@ WHERE m.id = ?""",
apparat_copy_action,
apparat_move_action,
replace_old_editions,
]
],
)
generalmenu.addActions([edit_action, delete_action, update_data_action]) # type: ignore
# disable apparat_add_action
@@ -1848,7 +1880,7 @@ WHERE m.id = ?""",
] # type: ignore
prof_id = self.db.getProfId(self.profdata) # type: ignore
app_id = self.db.getId(self.app_name.text()) # type: ignore
books: List[Tuple[int, BookData]] = []
books: list[tuple[int, BookData]] = []
for signature in signatures:
book = self.db.getBookBasedOnSignature(
app_id=app_id,
@@ -1894,7 +1926,7 @@ WHERE m.id = ?""",
)
signatures.append(book_id) # type: ignore
result, apparat = self.confirm_action_dialog( # type: ignore
"In welchen Apparat sollen die Medien kopiert werden?"
"In welchen Apparat sollen die Medien kopiert werden?",
)
if result == 1:
for book_id in signatures:
@@ -1914,7 +1946,7 @@ WHERE m.id = ?""",
)
signatures.append(book_id)
result, apparat = self.confirm_action_dialog(
"In welchen Apparat sollen die Medien verschoben werden?"
"In welchen Apparat sollen die Medien verschoben werden?",
)
if result == 1:
for book_id in signatures:
@@ -1957,13 +1989,14 @@ WHERE m.id = ?""",
dialog.setLayout(layout)
return dialog.exec(), self.db.getApparatId(
self.db.getApparatNameByAppNr(drpdwn.currentText())
self.db.getApparatNameByAppNr(drpdwn.currentText()),
)
def add_to_apparat(self):
"""use playwright in background to add medium to apparat"""
"""Use playwright in background to add medium to apparat"""
signature = self.tableWidget_apparat_media.item(
self.tableWidget_apparat_media.currentRow(), 1
self.tableWidget_apparat_media.currentRow(),
1,
).text()
self.db.getBookBasedOnSignature(
self.drpdwn_app_nr.currentText(),
@@ -1974,7 +2007,8 @@ WHERE m.id = ?""",
def edit_medium(self):
book = self.tableWidget_apparat_media.item(
self.tableWidget_apparat_media.currentRow(), 1
self.tableWidget_apparat_media.currentRow(),
1,
).text()
prof_id = self.db.getProfId(self.profdata)
data = self.db.getBookBasedOnSignature(
@@ -2004,7 +2038,6 @@ WHERE m.id = ?""",
self.update_app_media_list()
else:
return
pass
def delete_medium(self):
selected_apparat_id = self.active_apparat
@@ -2013,7 +2046,8 @@ WHERE m.id = ?""",
selected_rows = self.tableWidget_apparat_media.selectionModel().selectedRows()
if len(selected_rows) == 1:
signature = self.tableWidget_apparat_media.item(
self.tableWidget_apparat_media.currentRow(), 1
self.tableWidget_apparat_media.currentRow(),
1,
).text()
book_id = self.db.getBookIdBasedOnSignature(
selected_apparat_id,
@@ -2026,7 +2060,6 @@ WHERE m.id = ?""",
if state == 1:
self.db.deleteBook(book_id)
self.update_app_media_list()
pass
else:
# get all selected rows
ranges = self.tableWidget_apparat_media.selectedRanges()
@@ -2057,12 +2090,15 @@ WHERE m.id = ?""",
# #log.debug(data)
# return data
selected_apparat_id = self.tableWidget_apparate.item(
self.tableWidget_apparate.currentRow(), 0
self.tableWidget_apparate.currentRow(),
0,
).text()
# #log.debug(selected_apparat_id)
self.db.setNewSemesterDate(
selected_apparat_id, data["semester"], dauerapp=data["dauerapp"]
selected_apparat_id,
data["semester"],
dauerapp=data["dauerapp"],
)
# update the table
self.get_apparats()
@@ -2079,9 +2115,7 @@ WHERE m.id = ?""",
app_id="",
):
log.debug(
"Got these values apparat: {}, location: {}, mail: {}, pid: {}, accepted_books: {}, app_id: {}".format(
apparat, location, mail, pid, accepted_books, app_id
)
f"Got these values apparat: {apparat}, location: {location}, mail: {mail}, pid: {pid}, accepted_books: {accepted_books}, app_id: {app_id}",
)
active_apparat_id = (
@@ -2126,7 +2160,8 @@ WHERE m.id = ?""",
if self.active_apparat == "":
if apparat is False:
self.confirm_popup(
"Bitte erst einen Apparat auswählen!", title="Apparat auswählen"
"Bitte erst einen Apparat auswählen!",
title="Apparat auswählen",
)
return
@@ -2134,7 +2169,8 @@ WHERE m.id = ?""",
def delete_apparat(self, position):
selected_apparat_id = self.tableWidget_apparate.item(
self.tableWidget_apparate.currentRow(), 0
self.tableWidget_apparate.currentRow(),
0,
).text()
message = f"Soll der Apparat {selected_apparat_id} wirklich gelöscht werden?"
state = self.confirm_popup(message, title="Löschen?")
@@ -2146,7 +2182,8 @@ WHERE m.id = ?""",
apparat = Apparat(
appnr=int(selected_apparat_id),
name=self.tableWidget_apparate.item(
self.tableWidget_apparate.currentRow(), 1
self.tableWidget_apparate.currentRow(),
1,
).text(),
)
self.db.deleteApparat(apparat=apparat, semester=Semester().value)
@@ -2189,7 +2226,7 @@ def launch_gui():
MainWindow.show()
# atexit.register()
app.aboutToQuit.connect(
aui.validate_thread.quit
aui.validate_thread.quit,
) # if that thread uses an event loop
app.aboutToQuit.connect(aui.docu.terminate) # our new slot
app.aboutToQuit.connect(aui.docu.wait)

View File

@@ -30,38 +30,41 @@ class WelcomeWizard(QtWidgets.QWizard, Ui_Wizard):
# allow user to toggle password visibility
self.settings_mail_password.setContextMenuPolicy(
QtCore.Qt.ContextMenuPolicy.CustomContextMenu
QtCore.Qt.ContextMenuPolicy.CustomContextMenu,
)
self.settings_zotero_api_key.setContextMenuPolicy(
QtCore.Qt.ContextMenuPolicy.CustomContextMenu
QtCore.Qt.ContextMenuPolicy.CustomContextMenu,
)
self.settings_openai_api_key.setContextMenuPolicy(
QtCore.Qt.ContextMenuPolicy.CustomContextMenu
QtCore.Qt.ContextMenuPolicy.CustomContextMenu,
)
self.sam_password.setContextMenuPolicy(
QtCore.Qt.ContextMenuPolicy.CustomContextMenu
QtCore.Qt.ContextMenuPolicy.CustomContextMenu,
)
self.settings_mail_password.customContextMenuRequested.connect(
lambda pos: self.toggle_password_visibility(
pos, self.settings_mail_password
)
pos,
self.settings_mail_password,
),
)
self.settings_zotero_api_key.customContextMenuRequested.connect(
lambda pos: self.toggle_password_visibility(
pos, self.settings_zotero_api_key
)
pos,
self.settings_zotero_api_key,
),
)
self.settings_openai_api_key.customContextMenuRequested.connect(
lambda pos: self.toggle_password_visibility(
pos, self.settings_openai_api_key
)
pos,
self.settings_openai_api_key,
),
)
self.sam_password.customContextMenuRequested.connect(
lambda pos: self.toggle_password_visibility(pos, self.sam_password)
lambda pos: self.toggle_password_visibility(pos, self.sam_password),
)
# if button for next page is clicked, run function to store settings
self.button(QtWidgets.QWizard.WizardButton.NextButton).clicked.connect(
self.store_settings
self.store_settings,
)
self.settings_mail_use_user_name.toggled.connect(self.set_check_text)
# set initial values for checkbox, database
@@ -69,13 +72,13 @@ class WelcomeWizard(QtWidgets.QWizard, Ui_Wizard):
self.settings_database.setText(
str(settings.database.path)
if settings.database.path is not None
else str(appdirs.user_data_dir)
else str(appdirs.user_data_dir),
)
self.settings_temp.setText(
str(settings.database.temp)
if settings.database.temp is not None
else str(appdirs.user_cache_dir)
else str(appdirs.user_cache_dir),
)
self.settings_database_name.setText("semesterapparate.db")
@@ -199,7 +202,7 @@ class WelcomeWizard(QtWidgets.QWizard, Ui_Wizard):
file_dialog.setFileMode(QtWidgets.QFileDialog.FileMode.Directory)
file_dialog.setViewMode(QtWidgets.QFileDialog.ViewMode.List)
file_dialog.setWindowFlags(
file_dialog.windowFlags() | QtCore.Qt.WindowType.WindowStaysOnTopHint
file_dialog.windowFlags() | QtCore.Qt.WindowType.WindowStaysOnTopHint,
)
# set start dir to appdir.user_data_dir
file_dialog.setDirectory(str(appdirs.user_data_dir))
@@ -230,8 +233,6 @@ def launch_wizard():
if not app:
app = QtWidgets.QApplication([])
wizard = WelcomeWizard()
# wizard.setWindowTitle("Welcome to the Semester Apparatus Manager")
# wizard.setWindowIcon(settings.Icon("welcome").icon)
wizard.setWizardStyle(QtWidgets.QWizard.WizardStyle.ModernStyle)
wizard.setStartId(0)
wizard.show()