update deps, change config to restore changes, color overdue red in main, in loan color based on state
This commit is contained in:
@@ -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))
|
||||||
@@ -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()
|
||||||
|
|||||||
@@ -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",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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)}")
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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]
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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():
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user