From ac3c16633c5ab64f85a839874ba6a3cae73b552d Mon Sep 17 00:00:00 2001 From: Alexander Malzkuhn Date: Tue, 13 May 2025 14:21:36 +0200 Subject: [PATCH 1/3] Archivierte Dateien werden schreibgesperrt --- users.py | 8 ++++++-- users/testuser1/2025-4.json | 13 +------------ 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/users.py b/users.py index fe9fce5..b57f2a9 100644 --- a/users.py +++ b/users.py @@ -3,6 +3,7 @@ import hashlib # User bezogene Funktionen import os +from stat import S_IREAD, S_IWUSR import datetime import time import json @@ -230,11 +231,14 @@ class user: data["archived"] = 1 data["overtime"] = overtime - json_dict = json.dumps(data) + json_dict = json.dumps(data, indent=4) with open(filename, "w") as outputfile: outputfile.write(json_dict) - + # Dateien auf readonly setzen + os.chmod(filename, S_IREAD) + filename_txt = f"{self.userfolder}/{year}-{month}.txt" + os.chmod(filename_txt, S_IREAD) def get_last_months_overtime(self, year, month): try: if int(month) == 1: diff --git a/users/testuser1/2025-4.json b/users/testuser1/2025-4.json index 1346aed..a4558cf 100644 --- a/users/testuser1/2025-4.json +++ b/users/testuser1/2025-4.json @@ -1,12 +1 @@ -{ - "archived": 0, - "overtime": 0, - "absence": { - "7": "U", - "8": "K", - "9": "KK", - "10": "UU", - "11": "F", - "14": "EZ" - } -} \ No newline at end of file +{"archived": 1, "overtime": -860821, "absence": {"7": "U", "8": "K", "9": "KK", "10": "UU", "11": "F", "14": "EZ"}} \ No newline at end of file From 4b1a222132dce57ecea4e8f0b207b39bf1f4d65f Mon Sep 17 00:00:00 2001 From: Alexander Malzkuhn Date: Wed, 14 May 2025 08:45:39 +0200 Subject: [PATCH 2/3] Schreibschutz kann von Admin aufgehoben werden --- admin.py | 16 +++++++++++++--- playgound.py | 13 ++++++++++++- users/testuser1/2025-4.json | 2 +- users/testuser1/2025-4.txt | 0 4 files changed, 26 insertions(+), 5 deletions(-) mode change 100644 => 100755 users/testuser1/2025-4.json mode change 100644 => 100755 users/testuser1/2025-4.txt diff --git a/admin.py b/admin.py index 8853de8..c7723b1 100644 --- a/admin.py +++ b/admin.py @@ -11,6 +11,8 @@ from calendar import monthrange from web_ui import * import os.path +import os +from stat import S_IREAD, S_IRWXU import hashlib import calendar import locale @@ -140,7 +142,11 @@ def page_admin(): def revoke_archive_status(): def revoke_status(): - filename = f"{current_user.userfolder}/{int(select_year.value)}-{int(select_month.value)}.json" + filestring = f"{current_user.userfolder}/{int(select_year.value)}-{int(select_month.value)}" + filename = f"{filestring}.txt" + os.chmod(filename, S_IRWXU) + filename = f"{filestring}.json" + os.chmod(filename, S_IRWXU) with open(filename, 'r') as json_file: data = json.load(json_file) data["archived"] = 0 @@ -160,7 +166,7 @@ def page_admin(): dialog.open() if archive_status == True: - with ui.row().classes('text-right col-span-6 justify-center'): + with ui.row().classes('text-right col-span-7 justify-center'): ui.button("Archiviert", on_click=revoke_archive_status).classes('bg-transparent text-black') ui.separator() calendar_card.classes('bg-yellow') @@ -539,13 +545,15 @@ Dies kann nicht rückgängig gemacht werden!''') dialog.open() dialog.move(calendar_card) - with ui.button(icon='menu'): + with ui.button(icon='menu') as menu_button: with ui.menu() as menu: menu_item = ui.menu_item("Zeiteintrag hinzufügen", lambda day=day: add_entry(day)) if archive_status: menu_item.disable() ui.separator() menu_item = ui.menu_item("Notizen bearbeiten", lambda day=day: edit_notes(day)) + if archive_status: + menu_item.disable() ui.separator() for i in list(absence_entries): menu_item = ui.menu_item(f"{absence_entries[i]['name']} eintragen", lambda absence_type=i, day=day: add_absence(absence_type, day)) @@ -553,6 +561,8 @@ Dies kann nicht rückgängig gemacht werden!''') menu_item.disable() if str(day) in list(user_absent): menu_item.disable() + if archive_status: + menu_button.disable() #ui.button("Eintrag hinzufügen", on_click=lambda day=day: add_entry(day)) diff --git a/playgound.py b/playgound.py index 1800280..8d8184f 100644 --- a/playgound.py +++ b/playgound.py @@ -1,6 +1,17 @@ -from nicegui import ui +import json +import urllib.request + +from nicegui import ui, app + + import segno +@app.get("/data") +async def deliver_data(): + with open("settings.json") as json_file: + data = json.load(json_file) + return data + string = "" for i in range(1000): string += str(i) diff --git a/users/testuser1/2025-4.json b/users/testuser1/2025-4.json old mode 100644 new mode 100755 index a4558cf..1883f9d --- a/users/testuser1/2025-4.json +++ b/users/testuser1/2025-4.json @@ -1 +1 @@ -{"archived": 1, "overtime": -860821, "absence": {"7": "U", "8": "K", "9": "KK", "10": "UU", "11": "F", "14": "EZ"}} \ No newline at end of file +{"archived": 0, "overtime": -860821, "absence": {"7": "U", "8": "K", "9": "KK", "10": "UU", "11": "F", "14": "EZ"}} \ No newline at end of file diff --git a/users/testuser1/2025-4.txt b/users/testuser1/2025-4.txt old mode 100644 new mode 100755 From 3209d0d91f1bcb052e7d171476c58dff39ede057 Mon Sep 17 00:00:00 2001 From: Alexander Malzkuhn Date: Wed, 14 May 2025 10:50:39 +0200 Subject: [PATCH 3/3] =?UTF-8?q?Zus=C3=A4tzliche=20=C3=9Cberpr=C3=BCfung=20?= =?UTF-8?q?ob=20Archivierung=20sinnvoll=20mit=20zustzlichen=20Hinweisen.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin.py | 37 +++++++++++++++++++++---------------- api.py | 18 ++++++++++++++---- users.py | 20 ++++++++++++++++++++ users/testuser1/2025-3.json | 2 +- users/testuser1/2025-3.txt | 32 +++----------------------------- users/testuser1/2025-4.json | 13 ++++++++++++- users/testuser1/2025-4.txt | 16 ---------------- users/testuser1/2025-5.json | 1 - users/testuser1/2025-5.txt | 3 +++ 9 files changed, 74 insertions(+), 68 deletions(-) mode change 100644 => 100755 users/testuser1/2025-3.json mode change 100644 => 100755 users/testuser1/2025-3.txt mode change 100755 => 100644 users/testuser1/2025-4.json mode change 100755 => 100644 users/testuser1/2025-4.txt diff --git a/admin.py b/admin.py index c7723b1..dd07a58 100644 --- a/admin.py +++ b/admin.py @@ -132,7 +132,7 @@ def page_admin(): def update_month_and_year(): current_user = user(time_user.value) # Archivstatus - + days_with_errors = current_user.archiving_validity_check(int(select_year.value), int(select_month.value)) with ui.grid(columns='auto auto auto 1fr 1fr 1fr 1fr') as table_grid: if int(select_month.value) > 1: archive_status = current_user.get_archive_status(int(select_year.value), @@ -310,22 +310,26 @@ Dies kann nicht rückgängig gemacht werden!''') timestamp_button = ui.button(datetime.datetime.fromtimestamp(int(timestamps_dict[day][i])).strftime('%H:%M'), on_click=lambda t_stamp=timestamps_dict[day][i], day=day: edit_entry(t_stamp, day)) if archive_status: timestamp_button.disable() + with ui.row(): + # Fehlerhinweis + if day in days_with_errors: + ui.icon('warning', color='red').tooltip("Keine Schlussbuchung").classes('text-2xl') - # Notizen anzeigen - days_notes = current_user.get_day_notes(select_year.value, select_month.value, day) - if days_notes != { }: - with ui.icon('o_description').classes('text-2xl'): - with ui.tooltip(): - with ui.grid(columns='auto auto'): - for username, text in days_notes.items(): - admins_name = load_adminsettings()["admin_user"] - if username == admins_name: - ui.markdown('Administrator:') - else: - ui.markdown(current_user.fullname) - ui.markdown(text) - else: - ui.space() + # Notizen anzeigen + days_notes = current_user.get_day_notes(select_year.value, select_month.value, day) + if days_notes != { }: + with ui.icon('o_description').classes('text-2xl'): + with ui.tooltip(): + with ui.grid(columns='auto auto'): + for username, text in days_notes.items(): + admins_name = load_adminsettings()["admin_user"] + if username == admins_name: + ui.markdown('Administrator:') + else: + ui.markdown(current_user.fullname) + ui.markdown(text) + else: + ui.space() # Arbeitszeit Ist bestimmen @@ -586,6 +590,7 @@ Dies kann nicht rückgängig gemacht werden!''') current_user = user(time_user.value) month_header.set_content(f"###Buchungen für **{current_user.fullname}** für **{calendar.month_name[int(select_month.value)]} {select_year.value}**") + month_header.set_content(f"###Buchungen für **{current_user.fullname}** für **{calendar.month_name[int(select_month.value)]} {select_year.value}**") timetable() button_update = ui.button("Aktualisieren", on_click=timetable.refresh) button_update.move(timetable_header) diff --git a/api.py b/api.py index b636999..508c091 100644 --- a/api.py +++ b/api.py @@ -21,6 +21,7 @@ def page_overview_month(username: str, year: int, month: int): try: current_user = user(username) + days_with_errors = current_user.archiving_validity_check(year, month) ui.page_title(f"Bericht für {current_user.fullname} für {calendar.month_name[month]} {year}") if current_user.get_archive_status(year, month): with ui.column().classes('w-full items-end gap-0'): @@ -80,7 +81,8 @@ def page_overview_month(username: str, year: int, month: int): color_day = color_weekend current_day_date = f"{datetime(year, month, day).strftime('%a')}, {day}.{month}.{year}" - day_text_element = ui.markdown(current_day_date).classes(f'border px-{pad_x} py-{pad_y} bg-{color_day}') + with ui.link_target(day): + ui.markdown(current_day_date).classes(f'border px-{pad_x} py-{pad_y} bg-{color_day}') # Abwesenheitseinträge @@ -100,11 +102,11 @@ def page_overview_month(username: str, year: int, month: int): for i in range(0, len(timestamps_dict[day]), 2): try: temp_pair = [timestamps_dict[day][i], timestamps_dict[day][i + 1]] - booking_text = booking_text + str(datetime.fromtimestamp(temp_pair[0]).strftime('%H:%M')) + "-" + str(datetime.fromtimestamp(temp_pair[1]).strftime('%H:%M')) + "
" + booking_text = booking_text + str(datetime.fromtimestamp(temp_pair[0]).strftime('%H:%M')) + " - " + str(datetime.fromtimestamp(temp_pair[1]).strftime('%H:%M')) + "
" except: if len(timestamps_dict[day]) % 2 != 0: - booking_text += datetime.fromtimestamp(int(timestamps_dict[day][i])).strftime('%H:%M') + booking_text += datetime.fromtimestamp(int(timestamps_dict[day][i])).strftime('%H:%M') + " - ***Buchung fehlt!***" booking_text_element = ui.markdown(booking_text).classes(f'border px-{pad_x} py-{pad_y} bg-{booking_color} text-{booking_text_color}') @@ -258,7 +260,15 @@ def page_overview_month(username: str, year: int, month: int): dialog.open() if archivable == True: - ui.button("Archivieren", on_click=archive_dialog) + if len(days_with_errors) > 0: + ui.label("Es gibt Inkonsistenzen in den Buchungen. Folgende Tage müssen überprüft werden:") + with ui.grid(columns=len(days_with_errors)): + for i in days_with_errors: + ui.link(f"{i}.", f'#{i}') + + archive_button = ui.button("Archivieren", on_click=archive_dialog) + if len(days_with_errors) > 0: + archive_button.disable() archive() diff --git a/users.py b/users.py index b57f2a9..9d9f2ff 100644 --- a/users.py +++ b/users.py @@ -3,6 +3,7 @@ import hashlib # User bezogene Funktionen import os +from calendar import monthrange from stat import S_IREAD, S_IWUSR import datetime import time @@ -223,6 +224,25 @@ class user: except: return -1 + def archiving_validity_check(self, year: int, month: int): + timestampfilename = f"{self.userfolder}/{year}-{month}.txt" + try: + with open(timestampfilename) as timestampfile: + timestamps = timestampfile.readlines() + timestamps.sort() + days_with_errors = [ ] + for day in range(1, monthrange(year, month)[1] + 1): + day_dt = datetime.datetime(year, month, day) + timestamps_of_this_day = [ ] + for i in timestamps: + i_dt = datetime.datetime.fromtimestamp(int(i)) + if day_dt.year == i_dt.year and day_dt.month == i_dt.month and day_dt.day == i_dt.day: + timestamps_of_this_day.append(i) + if len(timestamps_of_this_day) % 2 != 0: + days_with_errors.append(day) + return days_with_errors + except: + return [ ] def archive_hours(self, year, month, overtime: int): filename = f"{self.userfolder}/{year}-{month}.json" diff --git a/users/testuser1/2025-3.json b/users/testuser1/2025-3.json old mode 100644 new mode 100755 index 27c5b37..d438ef3 --- a/users/testuser1/2025-3.json +++ b/users/testuser1/2025-3.json @@ -1 +1 @@ -{"archived": 1, "overtime": -528928} \ No newline at end of file +{"archived": 0, "overtime": -528928} \ No newline at end of file diff --git a/users/testuser1/2025-3.txt b/users/testuser1/2025-3.txt old mode 100644 new mode 100755 index 7350e03..da7ed21 --- a/users/testuser1/2025-3.txt +++ b/users/testuser1/2025-3.txt @@ -1,30 +1,4 @@ -1743965819 -1743965909 -1743966022 -1743966045 -1743966047 -1743966049 -1743967346 -1744889948 -1744889966 -1744989797 -1744989827 -1744989830 -1744989883 -1744989909 -1744989914 -1744989916 -1744991169 -1744991171 -1744991288 -1744991291 -1744991473 -1744991477 -1744991770 -1744991777 -1745181046 -1745181050 -1745240760 -1745240762 1740996000 -1740997800 +1742460540 +1741038540 +1742464500 diff --git a/users/testuser1/2025-4.json b/users/testuser1/2025-4.json old mode 100755 new mode 100644 index 1883f9d..48da952 --- a/users/testuser1/2025-4.json +++ b/users/testuser1/2025-4.json @@ -1 +1,12 @@ -{"archived": 0, "overtime": -860821, "absence": {"7": "U", "8": "K", "9": "KK", "10": "UU", "11": "F", "14": "EZ"}} \ No newline at end of file +{ + "archived": 1, + "overtime": -877154, + "absence": { + "7": "U", + "8": "K", + "9": "KK", + "10": "UU", + "11": "F", + "14": "EZ" + } +} \ No newline at end of file diff --git a/users/testuser1/2025-4.txt b/users/testuser1/2025-4.txt old mode 100755 new mode 100644 index ad67cca..bd42eec --- a/users/testuser1/2025-4.txt +++ b/users/testuser1/2025-4.txt @@ -1,21 +1,5 @@ 1744889948 1744890300 -1744989797 -1744989827 -1744989830 -1744989883 -1744989909 -1744989914 -1744989916 -1744991169 -1744991171 -1744991288 -1744991291 -1744991473 -1744991477 -1744991770 -1745215200 -1745229600 1745390818 1745390894 1745390894 diff --git a/users/testuser1/2025-5.json b/users/testuser1/2025-5.json index d3b1f01..7ec0e06 100644 --- a/users/testuser1/2025-5.json +++ b/users/testuser1/2025-5.json @@ -2,7 +2,6 @@ "archived": 0, "overtime": 0, "absence": { - "14": "U", "2": "SO" }, "notes": { diff --git a/users/testuser1/2025-5.txt b/users/testuser1/2025-5.txt index 5098bdd..58cd3a9 100644 --- a/users/testuser1/2025-5.txt +++ b/users/testuser1/2025-5.txt @@ -6,3 +6,6 @@ 1746608922 1746609024 1746609037 +1747206908 +1747207022 +1747813500