From 0d867a3f132dc06c22e1c7425c25df38214a79e9 Mon Sep 17 00:00:00 2001 From: Alexander Malzkuhn Date: Tue, 22 Apr 2025 12:10:03 +0200 Subject: [PATCH] Commit nach Git-Recover MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Userfunktionen hinzugefügt Erste Funktionen für Admin-Übersicht --- users.py | 53 +++- users/{testuser => testuser1}/2025-4.txt | 2 + users/{testuser => testuser1}/photo.jpg | Bin users/testuser1/settings.json | 47 +++ users/testuser1/settings.json.bak | 27 ++ users/testuser2/settings.json | 27 -- users/{test => testuser3}/2025-4.txt | 0 users/{test => testuser3}/settings.json | 4 +- users/{testuser2 => testuser5}/2025-4.txt | 0 users/{testuser2 => testuser5}/photo.jpg | Bin users/{testuser => testuser5}/settings.json | 20 +- web_ui.py | 323 +++++++++++++++++--- 12 files changed, 426 insertions(+), 77 deletions(-) rename users/{testuser => testuser1}/2025-4.txt (92%) rename users/{testuser => testuser1}/photo.jpg (100%) create mode 100644 users/testuser1/settings.json create mode 100644 users/testuser1/settings.json.bak delete mode 100644 users/testuser2/settings.json rename users/{test => testuser3}/2025-4.txt (100%) rename users/{test => testuser3}/settings.json (88%) rename users/{testuser2 => testuser5}/2025-4.txt (100%) rename users/{testuser2 => testuser5}/photo.jpg (100%) rename users/{testuser => testuser5}/settings.json (56%) diff --git a/users.py b/users.py index 94d374b..d88c020 100644 --- a/users.py +++ b/users.py @@ -6,6 +6,7 @@ import os import datetime import time import json +import shutil from definitions import userfolder, scriptpath, usersettingsfilename, photofilename, status_in, status_out @@ -21,15 +22,15 @@ class user: try: with open(self.settingsfile) as json_file: data = json.load(json_file) - json_file.close() + except: - pass + print("Fehler beim Erstellen des Datenarrays.") #Hier muss noch Fehlerbehandlungcode hin - self.fullname = data["name"] self.password = data["password"] self.workhours = data["workhours"] self.username = data["username"] + self.fullname = data["fullname"] def get_stamp_file(self): year = str(datetime.datetime.now().year) @@ -86,8 +87,54 @@ class user: else: return -1 + def write_settings(self): + dict = { } + dict["username"] = (self.username) + dict["fullname"] = (self.fullname) + dict["password"] = (self.password) + dict["workhours"] = (self.workhours) + + json_dict = json.dumps(dict, indent=4) + + with open(self.settingsfile, "w") as outputfile: + outputfile.write(json_dict) + + pathcheck = self.userfolder + pathcheck = pathcheck.removeprefix(f"{scriptpath}/{userfolder}/") + + if pathcheck != self.username: + os.rename(self.userfolder, f"{scriptpath}/{userfolder}/{self.username}") + + def del_user(self): + shutil.rmtree(self.userfolder) + + def get_years(self): + txtfiles = [ ] + for file in os.listdir(self.userfolder): + if file.endswith(".txt"): + txtfiles.append(file) + for i in range(len(txtfiles)): + txtfiles[i] = txtfiles[i][:4] + txtfiles = list(set(txtfiles)) + txtfiles.sort() + return txtfiles + + def get_months(self, year): + txtfiles = [ ] + for file in os.listdir(self.userfolder): + if file.endswith(".txt"): + txtfiles.append(file) + txtfiles.sort() + available_months = [ ] + + for entry in txtfiles: + if entry[:4] == str(year): + available_months.append(entry[5:-4]) + return available_months + # Benutzer auflisten def list_users(): users = [d for d in os.listdir(userfolder) if os.path.isdir(os.path.join(userfolder, d))] + users.sort() return users diff --git a/users/testuser/2025-4.txt b/users/testuser1/2025-4.txt similarity index 92% rename from users/testuser/2025-4.txt rename to users/testuser1/2025-4.txt index f4ed5ca..f25130e 100644 --- a/users/testuser/2025-4.txt +++ b/users/testuser1/2025-4.txt @@ -24,3 +24,5 @@ 1744991777 1745181046 1745181050 +1745240760 +1745240762 diff --git a/users/testuser/photo.jpg b/users/testuser1/photo.jpg similarity index 100% rename from users/testuser/photo.jpg rename to users/testuser1/photo.jpg diff --git a/users/testuser1/settings.json b/users/testuser1/settings.json new file mode 100644 index 0000000..90f686a --- /dev/null +++ b/users/testuser1/settings.json @@ -0,0 +1,47 @@ +{ + "username": "testuser1", + "fullname": "Pia Paulina", + "password": "123456789", + "workhours": { + "2024-04-01": { + "1": "8", + "2": "8", + "3": "8", + "4": "4", + "5": "5", + "6": "4", + "7": "0", + "vacation": "35" + }, + "2025-04-23": { + "0": 0, + "1": 0, + "2": 0, + "3": 0, + "4": 0, + "5": 0, + "6": 0, + "vacation": 0 + }, + "2025-05-13": { + "0": 0, + "1": 0, + "2": 0, + "3": 0, + "4": 0, + "5": 0, + "6": 0, + "vacation": 0 + }, + "2025-04-22": { + "0": 0, + "1": 0, + "2": 0, + "3": 0, + "4": 0, + "5": 0, + "6": 0, + "vacation": 0 + } + } +} \ No newline at end of file diff --git a/users/testuser1/settings.json.bak b/users/testuser1/settings.json.bak new file mode 100644 index 0000000..1bf319c --- /dev/null +++ b/users/testuser1/settings.json.bak @@ -0,0 +1,27 @@ +{ + "username": "testuser", + "fullname": "Pia Paulina", + "password": "123456789", + "workhours": { + "2024-04-01": { + "1": "8", + "2": "8", + "3": "8", + "4": "4", + "5": "5", + "6": "4", + "7": "0", + "vacation": "35" + }, + "2024-04-07": { + "1": "8", + "2": "7", + "3": "12", + "4": "0", + "5": "0", + "6": "0", + "7": "0", + "vacation": "28" + } + } +} \ No newline at end of file diff --git a/users/testuser2/settings.json b/users/testuser2/settings.json deleted file mode 100644 index 5aa6347..0000000 --- a/users/testuser2/settings.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "username": "testuser", - "name": "Peter Pan", - "password": "123456789", - "workhours": { - "2024-04-01": { - "0": "0", - "1": "8", - "2": "8", - "3": "8", - "4": "8", - "5": "8", - "6": "0", - "vacation": "30" - }, - "2024-04-07": { - "0": "0", - "1": "6", - "2": "6", - "3": "6", - "4": "8", - "5": "6", - "6": "0", - "vacation": "28" - } - } -} \ No newline at end of file diff --git a/users/test/2025-4.txt b/users/testuser3/2025-4.txt similarity index 100% rename from users/test/2025-4.txt rename to users/testuser3/2025-4.txt diff --git a/users/test/settings.json b/users/testuser3/settings.json similarity index 88% rename from users/test/settings.json rename to users/testuser3/settings.json index 9561df2..47c60e7 100644 --- a/users/test/settings.json +++ b/users/testuser3/settings.json @@ -1,6 +1,6 @@ { - "username": "test", - "name": "Karl Klammer", + "username": "testuser3", + "fullname": "Karl Klammer", "password": "123456789", "workhours": { "2024-04-01": { diff --git a/users/testuser2/2025-4.txt b/users/testuser5/2025-4.txt similarity index 100% rename from users/testuser2/2025-4.txt rename to users/testuser5/2025-4.txt diff --git a/users/testuser2/photo.jpg b/users/testuser5/photo.jpg similarity index 100% rename from users/testuser2/photo.jpg rename to users/testuser5/photo.jpg diff --git a/users/testuser/settings.json b/users/testuser5/settings.json similarity index 56% rename from users/testuser/settings.json rename to users/testuser5/settings.json index 5d8f3ee..1935ee2 100644 --- a/users/testuser/settings.json +++ b/users/testuser5/settings.json @@ -1,9 +1,9 @@ { - "username": "testuser", - "name": "Otto Octavius", + "username": "testuser5", + "fullname": "Peter Pan", "password": "123456789", "workhours": { - "2024-04-01": { + "2025-04-01": { "0": "0", "1": "8", "2": "8", @@ -13,8 +13,8 @@ "6": "0", "vacation": "30" }, - "2024-04-07": { - "0": "0", + "2025-04-07": { + "0": "5", "1": "6", "2": "6", "3": "6", @@ -22,6 +22,16 @@ "5": "6", "6": "0", "vacation": "28" + }, + "2025-03-16": { + "0": 0, + "1": 0, + "2": 0, + "3": 0, + "4": 0, + "5": 0, + "6": 0, + "vacation": 0 } } } \ No newline at end of file diff --git a/web_ui.py b/web_ui.py index 8c06c42..4d8148a 100644 --- a/web_ui.py +++ b/web_ui.py @@ -1,7 +1,14 @@ +import datetime + from nicegui import ui, app + from users import * from definitions import * import hashlib +import calendar +import locale + +locale.setlocale(locale.LC_ALL, '') class pageheader: def __init__(self, heading): @@ -13,7 +20,7 @@ class pageheader: def cookie_hash(user, password): return hashlib.sha256(b"{user}{app.storage.user['id']}{password}").hexdigest() -def adminsettings(): +def load_adminsettings(): # Settingsdatei einlesen try: with open(f"{scriptpath}/{usersettingsfilename}") as json_file: @@ -27,7 +34,7 @@ def adminsettings(): def page_login(): # Settingsdatei einlesen - data = adminsettings() + data = load_adminsettings() def login(): nonlocal data @@ -52,9 +59,11 @@ def page_login(): password = ui.input('Passwort', password=True) ui.button(text="Login", on_click=lambda: login()) + + @ui.page('/admin') def page_admin(): - data = adminsettings() + data = load_adminsettings() active_login = cookie_hash(data["admin_user"], data["admin_password"]) try: browser_cookie = app.storage.user['secret'] @@ -65,42 +74,235 @@ def page_admin(): if browser_cookie == active_login: pageheader("Administration") + def admin_logout(): + app.storage.user['secret'] = "" + ui.navigate.to("/login") + + ui.button("Logout", on_click=admin_logout) + with ui.tabs() as tabs: + + time_overview = ui.tab('Zeitübersichten') admin_user = ui.tab('Admin Benutzer') users = ui.tab('Benutzer') settings = ui.tab('Einstellungen') - with ui.tab_panels(tabs, value=admin_user): + with ui.tab_panels(tabs, value=time_overview): + + with ui.tab_panel(time_overview): + ui.markdown("##Übersichten") + + # Basisstruktur + with ui.card(): + with ui.row(): + def update_user(): + pass + + userlist = list_users() + ui.markdown("Benutzer:") + time_user = ui.select(options=userlist) + time_user.value = userlist[0] + ui.button("Aktualisieren", on_click=update_user) + + # Tabelle konstruieren + with ui.card(): + + with ui.row(): + current_year = datetime.datetime.now().year + current_month = datetime.datetime.now().month + + current_user = user(time_user.value) + available_years = current_user.get_years() + available_months = current_user.get_months(current_year) + + available_months_dict = { } + for element in available_months: + available_months_dict[element] = calendar.month_name[int(element)] + + select_month = ui.select(options=available_months_dict) + try: + select_month.value = str(current_month) + except: + pass + + select_year = ui.select(options=available_years) + try: + select_year.value = str(current_year) + except: + pass + + + ui.markdown(f"###Buchungen für {calendar.month_name[current_month]} {current_year}") + table_string = "| Datum | Buchungen | Soll | Ist | +/- | \n" + table_string += ("| --- | --- | --- | --- | --- |\n") + table_string += "| 01.04.2025 | 8:00 - 12:00 | 8 | 4 | -4 | \n" + ui.markdown(table_string, extras=['tables']) + with ui.tab_panel(admin_user): with ui.grid(columns=2): + def save_admin_settings(): + output_dict = { } + output_dict["admin_user"] = admin_user.value + output_dict["adnin_password"] = admin_password.value + json_dict = json.dumps(output_dict, indent=4) + with open(f"{scriptpath}/{usersettingsfilename}", "w") as outputfile: + outputfile.write(json_dict) + ui.notify("Einstellungen gespeichert") + + ui.label("Benutzername des Adminstrators") admin_user = ui.input() admin_user.value = data["admin_user"] ui.label("Passwort des Adminsistrators") admin_password = ui.input(password=True) admin_password.value = data["admin_password"] + ui.button("Speichern", on_click=save_admin_settings) + with ui.tab_panel(users): ui.markdown("###Benutzerverwaltung") userlist = list_users() + userlist.sort() workhours = [ ] with ui.row(): - def user_selection_changed(value): - current_user = user(value) - username_input.value = current_user.username - fullname_input.value = current_user.fullname - password_input.value = current_user.password - usersettingscard.visible = True + def user_selection_changed(): + try: + if user_selection.value != None: + current_user = user(user_selection.value) + username_input.value = current_user.username + fullname_input.value = current_user.fullname + password_input.value = current_user.password + usersettingscard.visible = True + + workhours_select.clear() + workhour_list = list(current_user.workhours) + workhour_list.sort() + workhours_select.set_options(workhour_list) + workhours_select.value = workhour_list[0] + workinghourscard.visible = True + except: + pass + + # workhours_selection_changed(list(current_user.workhours)[0]) + + def workhours_selection_changed(): + if workhours_select.value != None: + current_user = user(user_selection.value) + selected_workhours = current_user.workhours[workhours_select.value] + + for key, hours in selected_workhours.items(): + try: + days[int(key)-1].value = hours + except: + if key == 0: + days[6].value = hours + elif key == "vacation": + vacation_input.value = hours + + def save_user_settings(): + def save_settings(): + current_user = user(user_selection.value) + current_user.username = username_input.value + current_user.fullname = fullname_input.value + current_user.password = password_input.value + current_user.write_settings() + userlist = list_users() + userlist.sort() + user_selection.clear() + user_selection.set_options(userlist) + user_selection.value = current_user.username + dialog.close() + ui.notify("Einstellungen gespeichert") + + with ui.dialog() as dialog, ui.card(): + if user_selection.value != username_input.value: + ui.markdown("**Benutzername wurde geändert.**") + ui.markdown(f"Benutzerdaten werden in den neuen Ordner {username_input.value}") + ui.markdown("Sollen die Einstellungen gespeichert werden?") + with ui.row(): + ui.button("Speichern", on_click=save_settings) + ui.button("Abbrechen", on_click=dialog.close) + dialog.open() + + def del_user(): + current_user = user(user_selection.value) + + def del_definitely(): + current_user.del_user() + userlist = list_users() + userlist.sort() + user_selection.clear() + user_selection.set_options(userlist) + user_selection.value = userlist[0] + dialog.close() + ui.notify("Benutzer gelöscht") + + with ui.dialog() as dialog, ui.card(): + ui.markdown(f"Soll der Benutzer *{current_user.username}* gelöscht werden?") + ui.markdown("**Dies kann nicht rückgängig gemacht werden?**") + with ui.row(): + ui.button("Löschen", on_click=del_definitely) + ui.button("Abbrechen", on_click=dialog.close) + + dialog.open() + + def save_workhours(): + def save_settings(): + current_user = user(user_selection.value) + construct_dict = { } + for i in range(7): + if i < 7: + construct_dict[i+1] = days[i].value + elif i == 7: + conctruct_dict[0] = days[i].value + + construct_dict["vacation"] = vacation_input.value + current_user.workhours[workhours_select.value] = construct_dict + current_user.write_settings() + dialog.close() + ui.notify("Einstellungen gespeichert") + + with ui.dialog() as dialog, ui.card(): + ui.markdown("Sollen die Änderungen an den Arbeitsstunden und/oder Urlaubstagen gespeichert werden?") + with ui.row(): + ui.button("Speichern", on_click=save_settings) + ui.button("Abrrechen", on_click=dialog.close) + dialog.open() + + def delete_workhour_entry(): + def delete_entry(): + current_user = user(user_selection.value) + del current_user.workhours[workhours_select.value] + current_user.write_settings() + workhour_list = list(current_user.workhours) + workhours_select.clear() + workhours_select.set_options(workhour_list) + workhours_select.set_value(workhour_list[-1]) + + #workhours_selection_changed(current_user.workhours[0]) + dialog.close() + ui.notify("Eintrag gelöscht" + "") + with ui.dialog() as dialog, ui.card(): + current_user = user(user_selection.value) + if len(current_user.workhours) > 1: + ui.markdown(f"Soll der Eintrag *{workhours_select.value}* wirklich gelöscht werden?") + ui.markdown("**Dies kann nicht rückgängig gemacht werden.**") + with ui.row(): + ui.button("Löschen", on_click=delete_entry) + ui.button("Abbrechen", on_click=dialog.close) + else: + ui.markdown("Es gibt nur einen Eintrag. Dieser kann nicht gelöscht werden.") + ui.button("OK", on_click=dialog.close) + dialog.open() - workhours_select.set_options(list(current_user.workhours)) - workhours_select.value = list(current_user.workhours)[0] - workinghourscard.visible = True with ui.column(): - ui.select(options=userlist, with_input=True, on_change=lambda e: user_selection_changed(e.value)) + user_selection = ui.select(options=userlist, with_input=True, on_change=user_selection_changed) + user_selection.value = userlist[0] ui.button("Neu") with ui.column(): with ui.card() as usersettingscard: - ui.markdown("**Benutzereisntellungen**") + ui.markdown("**Benutzereinstellungen**") with ui.grid(columns=2): ui.label("Benutzername:") @@ -109,36 +311,77 @@ def page_admin(): fullname_input = ui.input() ui.label("Passwort") password_input = ui.input(password=True) - with ui.row(): - ui.button("Speichern") - ui.button("Löschen") + with ui.grid(columns=2): + ui.button("Speichern", on_click=save_user_settings) + ui.button("Löschen", on_click=del_user) with ui.card() as workinghourscard: - workhours = [ ] + workhours = [] ui.markdown("**Arbeitszeiten**") - with ui.grid(columns=2): - ui.markdown("gültig ab:") - workhours_select = ui.select(options=workhours) - days = [ ] - weekdays = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"] - counter = 0 - for day in weekdays: - ui.markdown(day) - days.append(ui.input()) - counter = counter + 1 - ui.separator() - with ui.grid(columns=2): - ui.markdown("Urlaubstage") - vacation_input = ui.input() + + with ui.card(): + + def calculate_weekhours(): + sum = 0 + for i in range(7): + try: + sum = float(days[i].value) + sum + except: + pass + workhours_sum.set_content(str(sum)) + + with ui.grid(columns=2): + ui.markdown("gültig ab:") + workhours_select = ui.select(options=workhours, on_change=workhours_selection_changed) + + days = [ ] + weekdays = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"] + counter = 0 + for day in weekdays: + ui.markdown(f"{day}:") + days.append(ui.input(on_change=calculate_weekhours)) + counter = counter + 1 + ui.separator().classes('col-span-full') + ui.markdown("**Summe:**") + workhours_sum = ui.markdown() + + with ui.card(): + with ui.grid(columns=2): + ui.markdown("Urlaubstage") + vacation_input = ui.input() with ui.row(): - ui.button("Speichern") - ui.button("Löschen") - ui.button("Neu") + ui.button("Speichern", on_click=save_workhours) + ui.button("Löschen", on_click=delete_workhour_entry) + def new_workhours_entry(): + current_user = user(user_selection.value) + def add_workhours_entry(): + workhours_dict = { } + for i in range(7): + workhours_dict[i] = 0 + workhours_dict["vacation"] = 0 + current_user.workhours[date_picker.value] = workhours_dict + current_user.write_settings() - # Initial das Benutzerfeld unsichtbar machen - usersettingscard.visible = False - workinghourscard.visible = False + workhours_select.clear() + workhours_list = list(current_user.workhours) + workhours_list.sort() + workhours_select.set_options(workhours_list) + workhours_select.value = date_picker.value + + dialog.close() + ui.notify("Eintrag angelegt") + + with ui.dialog() as dialog, ui.card(): + ui.markdown("Geben Sie das Gültigkeitsdatum an, ab wann die Einträge gültig sein sollen.") + date_picker = ui.date() + + with ui.row(): + ui.button("OK", on_click=add_workhours_entry) + ui.button("Abbrechen", on_click=dialog.close) + dialog.open() + ui.button("Neu", on_click=new_workhours_entry) + user_selection_changed() # Alternativ zur Loginseite navigieren else: @@ -162,7 +405,7 @@ def page_touchscreen(): buttons[name].props('color=red') ui.notify(status_out) - ui.markdown(f"##{app_title} {app_version}") + pageheader("Bitte User auswählen:") userlist = list_users() number_of_users = len(userlist)