Merge branch 'read-only' into web_ui

This commit is contained in:
Alexander Malzkuhn 2025-05-14 11:02:38 +02:00
commit 43b4b6bce5
10 changed files with 95 additions and 75 deletions

View File

@ -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
@ -130,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),
@ -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')
@ -304,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
@ -539,13 +549,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 +565,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))
@ -576,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)

18
api.py
View File

@ -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')) + "<br>"
booking_text = booking_text + str(datetime.fromtimestamp(temp_pair[0]).strftime('%H:%M')) + " - " + str(datetime.fromtimestamp(temp_pair[1]).strftime('%H:%M')) + "<br>"
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()

View File

@ -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)

View File

@ -3,6 +3,8 @@ import hashlib
# User bezogene Funktionen
import os
from calendar import monthrange
from stat import S_IREAD, S_IWUSR
import datetime
import time
import json
@ -222,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"
@ -230,11 +251,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:

2
users/testuser1/2025-3.json Normal file → Executable file
View File

@ -1 +1 @@
{"archived": 1, "overtime": -528928}
{"archived": 0, "overtime": -528928}

32
users/testuser1/2025-3.txt Normal file → Executable file
View File

@ -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

View File

@ -1,6 +1,6 @@
{
"archived": 0,
"overtime": 0,
"archived": 1,
"overtime": -877154,
"absence": {
"7": "U",
"8": "K",

View File

@ -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

View File

@ -2,7 +2,6 @@
"archived": 0,
"overtime": 0,
"absence": {
"14": "U",
"2": "SO"
},
"notes": {

View File

@ -6,3 +6,6 @@
1746608922
1746609024
1746609037
1747206908
1747207022
1747813500