update deps, change config to restore changes, color overdue red in main, in loan color based on state

This commit is contained in:
2025-01-13 11:14:27 +01:00
parent 148adb937d
commit daf8d87b9d
10 changed files with 1085 additions and 40 deletions

View File

@@ -148,10 +148,37 @@ class Config:
raise KeyError(f"Option {keys[0]} not found in configuration") raise KeyError(f"Option {keys[0]} not found in configuration")
else: else:
self._config[key] = value self._config[key] = value
def get_changes(self, other):
# compare self to other, return changes
changes = {}
for key in self._config:
if self._config[key] != other[key]:
changes[key] = self._config[key]
return changes
if __name__ == "__main__": if __name__ == "__main__":
cfg = Config("config/settings.yaml") cfg = Config("config/settings.yaml")
#print(cfg.database.path) other = {
cfg.database.path = "nopathhere" "institution_name": "Test",
#print(cfg.database.path) "default_loan_duration": 7,
cfg.save() "inactive_user_deletion": 365,
#cfg.updateValue("database.path", "Test") "database": {
"path": "./database",
"name": "library.db",
"backupLocation": "./backup",
"do_backup": True,
},
"report": {"generate_report": True, "path": "./report", "report_day": 0},
"shortcuts": [
{"name": "Rueckgabemodus", "default": "F5", "current": "F5"},
{"name": "Nutzer", "default": "F6", "current": "F6"},
{"name": "Hilfe", "default": "F1", "current": "F1"},
{"name": "Bericht_erstellen", "default": "F7", "current": "F7"},
{"name": "Ausleihhistorie", "default": "F8", "current": "F8"},
],
"advanced_refresh": False,
"catalogue": True,
"debug": True,
"documentation": True,
}
print(cfg.get_changes(other))

View File

@@ -1,4 +1,4 @@
from src.ui.main_ui import launch from src.ui.main_ui import launch
if __name__ == "__main__": if __name__ == "__main__":
launch("--debug") launch()

View File

@@ -5,11 +5,22 @@ description = "Add your description here"
readme = "README.md" readme = "README.md"
requires-python = ">=3.12" requires-python = ">=3.12"
dependencies = [ dependencies = [
"beautifulsoup4>=4.12.3",
"loguru>=0.7.3", "loguru>=0.7.3",
"mkdocs>=1.6.1",
"mkdocs-material>=9.5.49",
"mkdocs-material-extensions>=1.3.1",
"omegaconf>=2.3.0",
"prettytable>=3.12.0",
"pyqt6>=6.8.0",
"pyramid>=2.0.2",
"python-dotenv>=1.0.1", "python-dotenv>=1.0.1",
"requests>=2.32.3",
] ]
[dependency-groups] [dependency-groups]
dev = [ dev = [
"bump-my-version>=0.29.0",
"icecream>=2.1.4",
"nuitka>=2.5.9", "nuitka>=2.5.9",
] ]

View File

@@ -12,7 +12,7 @@ docport = 6543
config = Config("config/settings.yaml") config = Config("config/settings.yaml")
_config = config _config = Config("config/settings.yaml")._config
# Store original values that might be overridden by CLI # Store original values that might be overridden by CLI
@@ -46,13 +46,6 @@ if changes_made:
config.save() config.save()
def restore_config():
global _config
config._config = _config
config.save()
log.info("Restored configuration")
atexit.register(restore_config)
log = logger log = logger
log.remove() log.remove()
log.add("logs/application.log", rotation="1 week", compression="zip") log.add("logs/application.log", rotation="1 week", compression="zip")
@@ -69,3 +62,13 @@ if config.debug:
log.add( log.add(
sys.stderr, sys.stderr,
) )
def restore_config():
log.debug("Restoring configuration")
print("Changes made: ", changes_made)
if not changes_made:
return
config._config = _config
config.save()
log.info("Restored configuration, changed values: {config.get_changes(_config)}")

View File

@@ -2,3 +2,4 @@ __help__ = "This package contains the logic of the application."
from .database import Database from .database import Database
from .catalogue import Catalogue from .catalogue import Catalogue
from .backup import Backup from .backup import Backup
from .documentation_thread import DocumentationThread

View File

@@ -29,7 +29,7 @@ class Database:
os.makedirs(config.database.backupLocation) os.makedirs(config.database.backupLocation)
#if main path does not exist, try to create it. if that fails, use the backuplocation #if main path does not exist, try to create it. if that fails, use the backuplocation
log.debug("Checking Database Path", self.db_path) log.debug("Checking Database Path {}", self.db_path)
self.checkDatabaseStatus() self.checkDatabaseStatus()
def handle_folder_reachability(self, original_path, backup_path): def handle_folder_reachability(self, original_path, backup_path):
@@ -219,14 +219,14 @@ class Database:
for res in result: for res in result:
if res[0] == user_id: if res[0] == user_id:
user = User(userid=res[1], username=res[2], email=res[3], id=res[0]) user = User(userid=res[1], username=res[2], email=res[3], id=res[0])
dbg(f"Returning User {user}") log.debug(f"Returning User {user}")
log.info(f"Returning User {user}") log.info(f"Returning User {user}")
return user return user
else: else:
for res in result: for res in result:
if res[1] == user_id: if res[1] == user_id:
user = User(userid=res[1], username=res[2], email=res[3], id=res[0]) user = User(userid=res[1], username=res[2], email=res[3], id=res[0])
dbg(f"Returning User {user}") log.debug(f"Returning User {user}")
log.info(f"Returning User {user}") log.info(f"Returning User {user}")
return user return user
raise ValueError(f"User {user_id} not found") raise ValueError(f"User {user_id} not found")
@@ -245,7 +245,7 @@ class Database:
return user return user
def updateUser(self, username, user_id, usermail): def updateUser(self, username, user_id, usermail):
log.debug(f"Updating User {userno}, {username}, {usermail}") log.debug(f"Updating User {user_id}, {username}, {usermail}")
conn = self.connect() conn = self.connect()
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute( cursor.execute(
@@ -260,7 +260,7 @@ class Database:
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(query) cursor.execute(query)
conn.commit() conn.commit()
dbg(f"Setting User {userid} to active on {date}") log.debug(f"Setting User {userid} to active on {date}")
def renameInactiveUsers(self): def renameInactiveUsers(self):
lastYear = QtCore.QDate.currentDate().addDays(int(f"-{config.delete_inactive_user_duration}")).toString("yyyy-MM-dd") lastYear = QtCore.QDate.currentDate().addDays(int(f"-{config.delete_inactive_user_duration}")).toString("yyyy-MM-dd")
@@ -294,7 +294,7 @@ class Database:
self.close_connection(conn) self.close_connection(conn)
def getActiveLoans(self, userid): def getActiveLoans(self, userid):
dbg("id", str(userid)) log.debug("id", str(userid))
conn = self.connect() conn = self.connect()
cursor = conn.cursor() cursor = conn.cursor()
try: try:
@@ -404,7 +404,7 @@ class Database:
) )
return res return res
def getAllMedia(self, user_id): def getAllMedia(self, user_id) -> list[Book]:
# get all books that have the user id in the loans table # get all books that have the user id in the loans table
query = f"SELECT * FROM loans WHERE user_id = '{user_id}'" query = f"SELECT * FROM loans WHERE user_id = '{user_id}'"
conn = self.connect() conn = self.connect()
@@ -487,7 +487,7 @@ class Database:
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(query) cursor.execute(query)
result = cursor.fetchone() result = cursor.fetchone()
dbg("Result", response=result) log.debug(f"Result: {result}")
self.close_connection(conn) self.close_connection(conn)
if result is not None: if result is not None:
return result[0] return result[0]

View File

@@ -2,8 +2,10 @@ import sys
import atexit import atexit
import datetime import datetime
import webbrowser import webbrowser
from src import config, __email__, docport, log from PyQt6 import QtCore, QtWidgets
from src.logic import Database, Catalogue, Backup from omegaconf import OmegaConf
from src import config, __email__, docport, log, restore_config
from src.logic import Database, Catalogue, Backup, DocumentationThread
from src.utils import stringToDate, Icon from src.utils import stringToDate, Icon
from src.utils.createReport import generate_report from src.utils.createReport import generate_report
from src.schemas import Book from src.schemas import Book
@@ -16,9 +18,7 @@ from .settings import Settings
from .newBook import NewBook from .newBook import NewBook
from .loans import LoanWindow from .loans import LoanWindow
from .reportUi import ReportUi from .reportUi import ReportUi
from PyQt6 import QtCore, QtWidgets
from omegaconf import OmegaConf
from src.logic.documentation_thread import DocumentationThread
backup = Backup() backup = Backup()
cat = Catalogue() cat = Catalogue()
@@ -327,6 +327,12 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
retdate = self.db.selectClosestReturnDate(self.activeUser.id) retdate = self.db.selectClosestReturnDate(self.activeUser.id)
if retdate: if retdate:
date = stringToDate(retdate).toString("dd.MM.yyyy") date = stringToDate(retdate).toString("dd.MM.yyyy")
today = QtCore.QDate.currentDate().toString("yyyy-MM-dd")
# if retdate is in past, set nextReturnDate color to red
if retdate < today:
self.nextReturnDate.setStyleSheet("color: red")
else:
self.nextReturnDate.setStyleSheet("color: black")
self.nextReturnDate.setText(date) self.nextReturnDate.setText(date)
self.nextReturnDate.show() self.nextReturnDate.show()
self.label_7.show() self.label_7.show()
@@ -516,13 +522,16 @@ class MainUI(QtWidgets.QMainWindow, Ui_MainWindow):
dialog.setText(message) dialog.setText(message)
dialog.exec() dialog.exec()
def exit_handler(): def exit_handler():
log.info("Exiting, creating backup") log.info(
"Exiting, creating backup, renaming inactive users, creating report if day matches"
)
restore_config()
app = QtWidgets.QApplication(sys.argv) app = QtWidgets.QApplication(sys.argv)
#print(backup.backup) #print(backup.backup)
# generate report if monday # generate report if monday
if datetime.datetime.now().weekday() == config.report.report_day: if datetime.datetime.now().weekday() == config.report.report_day:
log.info("Generating Report")
generate_report() generate_report()
log.info("Generated Report")
Database().renameInactiveUsers() Database().renameInactiveUsers()
if config.database.do_backup: if config.database.do_backup:
state = backup.createBackup() state = backup.createBackup()
@@ -550,11 +559,35 @@ def exit_handler():
dialog.setWindowTitle("Backup nicht möglich") dialog.setWindowTitle("Backup nicht möglich")
dialog.setText("Backup konnte nicht erstellt werden\nGrund: {}".format(reason)) dialog.setText("Backup konnte nicht erstellt werden\nGrund: {}".format(reason))
dialog.exec() dialog.exec()
log.info("Exiting")
sys.exit()
def launch(*argv): def launch(*argv):
options = sys.argv options = sys.argv
if argv: if argv:
options += [arg for arg in argv] options += [arg for arg in argv]
options = [arg for arg in options if arg.startswith("--")] options += [arg for arg in options if arg.startswith("--")]
# add options to sys.argv
# print(options)
# print("Launching Main UI")
QtCore.QLocale().setDefault(
QtCore.QLocale(QtCore.QLocale.Language.German, QtCore.QLocale.Country.Germany)
)
SYSTEM_LANGUAGE = QtCore.QLocale().system().name()
# Load base QT translations from the normal place
app = QtWidgets.QApplication([])
main_ui = MainUI()
# translate ui to system language
if SYSTEM_LANGUAGE:
translator = QtCore.QTranslator()
# do not use ascii encoding
translator.load(f"qt_{SYSTEM_LANGUAGE}", "translations")
translator.load("app.qm", "translations")
app.installTranslator(translator)
atexit.register(exit_handler)
sys.exit(app.exec())
# sys.exit(app.exec())
#print("Launching Main UI") #print("Launching Main UI")
#print(options) #print(options)
QtCore.QLocale().setDefault(QtCore.QLocale(QtCore.QLocale.Language.German, QtCore.QLocale.Country.Germany)) QtCore.QLocale().setDefault(QtCore.QLocale(QtCore.QLocale.Language.German, QtCore.QLocale.Country.Germany))

View File

@@ -2,9 +2,10 @@ from .sources.Ui_main_userData import Ui_MainWindow
from PyQt6 import QtCore, QtGui, QtWidgets from PyQt6 import QtCore, QtGui, QtWidgets
from src import log from src import log
from src.logic import Database from src.logic import Database
from src.schemas import User from src.schemas import User, Book
from .extendLoan import ExtendLoan from .extendLoan import ExtendLoan
from src.utils import stringToDate, Icon from src.utils import stringToDate, Icon
import datetime
TABLETOFIELDTRANSLATE = { TABLETOFIELDTRANSLATE = {
"Titel": "title", "Titel": "title",
@@ -65,6 +66,18 @@ class UserUI(QtWidgets.QMainWindow, Ui_MainWindow):
self.show() self.show()
def check_book(self, book: Book):
today = QtCore.QDate.currentDate().toString("yyyy-MM-dd")
returnDate = stringToDate(book.loan_to).toString("yyyy-MM-dd")
returned = book.returned
if returned == 1:
return "returned"
else:
if returnDate < today:
return "overdue"
else:
return "ok"
def userDelete(self): def userDelete(self):
self.db.deleteUser(self.user_id) self.db.deleteUser(self.user_id)
dialog = QtWidgets.QMessageBox() dialog = QtWidgets.QMessageBox()
@@ -212,6 +225,22 @@ class UserUI(QtWidgets.QMainWindow, Ui_MainWindow):
else stringToDate(book.returned_date).toString("dd.MM.yyyy") else stringToDate(book.returned_date).toString("dd.MM.yyyy")
), ),
) )
match self.check_book(book):
case "overdue":
for i in range(6):
self.UserMediaTable.item(0, i).setBackground(
QtGui.QColor(255, 0, 0, 100)
)
case "ok":
for i in range(6):
self.UserMediaTable.item(0, i).setBackground(
QtGui.QColor(105, 255, 51, 100)
)
case "returned":
for i in range(6):
self.UserMediaTable.item(0, i).setBackground(
QtGui.QColor(102, 153, 153, 100)
)
def launch(): def launch():

View File

@@ -49,11 +49,6 @@ def generate_report():
loan_action_date, loan_action_date,
] ]
) )
# #print(table)
# # wruitng the table to a file
# with open("report.txt", "w", encoding="utf-8") as f:
# f.write(str(table))
tsv_table = table.get_csv_string().replace(",", "\t") tsv_table = table.get_csv_string().replace(",", "\t")
# write the file # write the file
with open(report_path, "w", encoding="utf-8") as f: with open(report_path, "w", encoding="utf-8") as f:

950
uv.lock generated

File diff suppressed because it is too large Load Diff