diff --git a/admin.py b/admin.py
new file mode 100644
index 0000000..077ab47
--- /dev/null
+++ b/admin.py
@@ -0,0 +1,674 @@
+from datetime import datetime
+
+from nicegui import ui, app
+
+from users import *
+from definitions import *
+from calendar import monthrange
+from web_ui import *
+
+import hashlib
+import calendar
+import locale
+
+@ui.page('/admin')
+def page_admin():
+ ui.page_title(f"{app_title} {app_version}")
+ data = load_adminsettings()
+ active_login = cookie_hash(data["admin_user"], data["admin_password"])
+ try:
+ browser_cookie = app.storage.user['secret']
+ except:
+ browser_cookie = ""
+
+ # Adminseite
+ 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=time_overview))):
+
+ with ui.tab_panel(time_overview):
+ ui.markdown("##Übersichten")
+
+ # Tabelle konstruieren
+ with ui.card():
+
+ with ui.row() as timetable_header:
+ year_binder = ValueBinder()
+ month_binder = ValueBinder()
+
+ def update_months():
+ current_user = user(time_user.value)
+ available_months = current_user.get_months(year_binder.value)
+ available_months_dict = { }
+
+ for element in available_months:
+ available_months_dict[element] = calendar.month_name[int(element)]
+
+ select_month.clear()
+ select_month.set_options(available_months_dict)
+ select_month.value = list(available_months)[0]
+
+ def update_user():
+ current_user = user(time_user.value)
+ available_years = current_user.get_years()
+ select_year.clear()
+ select_year.set_options(available_years)
+ select_year.value = list(available_years)[0]
+
+ userlist = list_users()
+ ui.markdown("Benutzer:")
+
+ time_user = ui.select(options=userlist, value=userlist[0], on_change=update_user)
+
+ user_to_select_for_start = userlist[0]
+
+ current_year = datetime.datetime.now().year
+ current_month = datetime.datetime.now().month
+ current_user = user(user_to_select_for_start)
+ 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)]
+
+ if current_month in available_months:
+ set_month = current_month
+ else:
+ set_month = available_months[0]
+
+ if str(current_year) in available_years:
+ set_year = str(current_year)
+ else:
+ set_year = (available_years[0])
+
+ select_month = ui.select(options=available_months_dict, value=set_month).bind_value_to(month_binder, 'value')
+ select_year = ui.select(options=available_years, value=set_year, on_change=update_months).bind_value_to(year_binder, 'value')
+
+
+ month_header = ui.markdown(f"###Buchungen für **{current_user.fullname}** für **{calendar.month_name[int(select_month.value)]} {select_year.value}**")
+
+ # Tabelle aufbauen
+ with ui.card() as calendar_card:
+ def update_month_and_year():
+
+ with ui.grid(columns='auto auto 1fr 1fr 1fr 1fr') as table_grid:
+ ui.markdown("**Datum**")
+ ui.markdown("**Buchungen**")
+ ui.markdown("**Ist**")
+ ui.markdown("**Soll**")
+ ui.markdown("**Saldo**")
+ ui.space()
+
+ current_user = user(time_user.value)
+ timestamps = current_user.get_timestamps(year=select_year.value, month=select_month.value)
+ user_absent = current_user.get_absence(year=select_year.value, month=select_month.value)
+ # Dictionary für sortierte Timestamps
+ timestamps_dict = { }
+ # Dictionary mit zunächst leeren Tageinträgen befüllen
+ for day in range(1, monthrange(int(select_year.value), int(select_month.value))[1] + 1):
+ # Jeder Tag bekommt eine leere Liste
+ timestamps_dict[day] = [ ]
+
+ # Alle Timestamps durchgehen und sie den Dictionaryeinträgen zuordnen:
+ for stamp in timestamps:
+ day_of_month_of_timestamp = int(datetime.datetime.fromtimestamp(int(stamp)).strftime("%-d"))
+ timestamps_dict[day_of_month_of_timestamp].append(int(stamp))
+
+ general_saldo = 0
+
+ for day in list(timestamps_dict):
+ # Datum für Tabelle konstruieren
+ day_in_list = datetime.datetime(int(select_year.value), int(select_month.value), day)
+ ui.markdown(f"{day_in_list.strftime('%a')}., {day}. {calendar.month_name[int(select_month.value)]}")
+
+ # Buchungen
+
+ with ui.row():
+ def delete_absence(day, absence_type):
+ def execute_deletion():
+ current_user.del_absence(select_year.value, select_month.value, day)
+ calendar_card.clear()
+ update_month_and_year()
+ dialog.close()
+ ui.notify("Abwesenheitseintrag gelöscht")
+ with ui.dialog() as dialog, ui.card():
+ ui.markdown(f'''Soll der Eintrag **{absence_type}** für den **{day}. {calendar.month_name[int(select_month.value)]} {select_year.value}** gelöscht werden?
+
+Dies kann nicht rückgägig gemacht werden!''')
+ with ui.grid(columns=3):
+ ui.button("Ja", on_click=execute_deletion)
+ ui.space()
+ ui.button("Nein", on_click=dialog.close)
+ dialog.open()
+
+ try:
+ for i in list(user_absent):
+ if int(i) == day:
+ ui.button(absence_entries[user_absent[i]]["name"], on_click=lambda i=i, day=day: delete_absence(day, absence_entries[user_absent[i]]["name"])).props(f'color={absence_entries[user_absent[i]]["color"]}')
+ except:
+ pass
+
+ day_type = ui.markdown("Kein Arbeitstag")
+ day_type.set_visibility(False)
+
+ # Hier werden nur die Tage mit Timestamps behandelt
+ if len(timestamps_dict[day]) > 0:
+ timestamps_dict[day].sort()
+
+ def edit_entry(t_stamp, day):
+
+ with ui.dialog() as edit_dialog, ui.card():
+ ui.markdown("###Eintrag bearbeiten")
+ timestamp = datetime.datetime.fromtimestamp(int(t_stamp))
+ input_time = ui.time().classes('w-full justify-center')
+
+ input_time.value = timestamp.strftime('%H:%M')
+
+ def save_entry(day):
+ nonlocal t_stamp
+ t_stamp = f"{t_stamp}\n"
+ position = timestamps.index(t_stamp)
+ new_time_stamp = datetime.datetime(int(select_year.value),
+ int(select_month.value), day,
+ int(input_time.value[:2]),
+ int(input_time.value[-2:]))
+ timestamps[position] = str(
+ int(new_time_stamp.timestamp())) + "\n"
+
+ current_user = user(time_user.value)
+ current_user.write_edited_timestamps(timestamps,
+ select_year.value,
+ select_month.value)
+ edit_dialog.close()
+ calendar_card.clear()
+ update_month_and_year()
+ month_header.set_content(
+ f"###Buchungen für {calendar.month_name[int(select_month.value)]} {select_year.value}")
+ ui.notify("Eintrag gespeichert")
+
+ def del_entry():
+ nonlocal t_stamp
+ t_stamp = f"{t_stamp}\n"
+ timestamps.remove(t_stamp)
+ timestamps.sort()
+ current_user = user(time_user.value)
+ current_user.write_edited_timestamps(timestamps,
+ select_year.value,
+ select_month.value)
+ edit_dialog.close()
+ calendar_card.clear()
+ update_month_and_year()
+ month_header.set_content(
+ f"###Buchungen für {calendar.month_name[int(select_month.value)]} {select_year.value}")
+ ui.notify("Eintrag gelöscht")
+
+ with ui.row():
+ ui.button("Speichern",
+ on_click=lambda day=day: save_entry(day))
+ ui.button("Löschen", on_click=del_entry)
+ ui.button("Abbrechen", on_click=edit_dialog.close)
+
+ edit_dialog.open()
+ for i in range(len(timestamps_dict[day])):
+ try:
+ temp_pair = [ timestamps_dict[day][i] , timestamps_dict[day][i+1] ]
+ with ui.card():
+ with ui.row():
+ for j in temp_pair:
+ ui.button(datetime.datetime.fromtimestamp(int(j)).strftime('%H:%M'), on_click=lambda t_stamp=j, day=day: edit_entry(t_stamp, day))
+ except:
+ if len(timestamps_dict[day]) % 2 != 0:
+ with ui.card():
+ 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))
+
+ # Arbeitszeit Ist bestimmen
+ timestamps_of_this_day = []
+
+ # Suche mir alle timestamps für diesen Tag
+ for i in timestamps:
+ actual_timestamp = datetime.datetime.fromtimestamp(int(i))
+ timestamp_day = actual_timestamp.strftime('%-d')
+
+ if int(timestamp_day) == int(day):
+ timestamps_of_this_day.append(i)
+
+ timestamps_of_this_day.sort()
+ time_sum = 0
+ if len(timestamps_of_this_day) > 1:
+
+ if len(timestamps_of_this_day) % 2 == 0:
+ for i in range(0, len(timestamps_of_this_day), 2):
+ time_delta = int(
+ timestamps_of_this_day[i + 1]) - int(
+ timestamps_of_this_day[i])
+ time_sum = time_sum + time_delta
+ else:
+ for i in range(0, len(timestamps_of_this_day) - 1, 2):
+ time_delta = int(
+ timestamps_of_this_day[i + 1]) - int(
+ timestamps_of_this_day[i])
+ time_sum = time_sum + time_delta
+
+ ui.markdown(convert_seconds_to_hours(time_sum))
+ else:
+ ui.markdown("Kein")
+
+ # Arbeitszeitsoll bestimmen
+
+ hours_to_work = int(current_user.get_day_workhours(select_year.value, select_month.value, day))
+ if hours_to_work < 0:
+ ui.space()
+ else:
+ ui.markdown(f"{convert_seconds_to_hours(int(hours_to_work) * 3600)}")
+ if int(hours_to_work) == 0:
+ day_type.content = "**Kein Arbeitstag**"
+ day_type.set_visibility(True)
+
+
+
+ # Saldo für den Tag berechnen
+
+ if time.time() > day_in_list.timestamp():
+
+ time_duty = int(current_user.get_day_workhours(select_year.value, select_month.value, day)) * 3600
+ if time_duty < 0:
+ ui.space()
+ else:
+ saldo = int(time_sum) - int(time_duty)
+ # Nach Abwesenheitseinträgen suchen
+ try:
+ for i in list(user_absent):
+ if int(i) == day and user_absent[i] != "UU":
+ saldo = 0
+ except:
+ pass
+
+ general_saldo = general_saldo + saldo
+ ui.markdown(convert_seconds_to_hours(saldo))
+ else:
+ ui.markdown("-")
+
+ def add_entry(day):
+ with ui.dialog() as add_dialog, ui.card():
+ ui.markdown("###Eintrag hinzufügen")
+ input_time = ui.time().classes('w-full justify-center')
+
+ def add_entry_save():
+ if input_time.value == None:
+ ui.notify("Bitte eine Uhrzeit auswählen.")
+ return
+
+ new_time_stamp = datetime.datetime(int(year_binder.value),
+ int(month_binder.value), day,
+ int(input_time.value[:2]),
+ int(input_time.value[-2:])).timestamp()
+ current_user = user(time_user.value)
+ current_user.timestamp(stamptime=int(new_time_stamp))
+ calendar_card.clear()
+ update_month_and_year()
+ add_dialog.close()
+ ui.notify("Eintrag hinzugefügt")
+ with ui.grid(columns=3):
+ ui.button("Speichern", on_click=add_entry_save)
+ ui.space()
+ ui.button("Abbrechen", on_click=add_dialog.close)
+ add_dialog.open()
+ add_dialog.move(calendar_card)
+
+ def add_absence(absence_type, day):
+ with ui.dialog() as dialog, ui.card():
+ ui.markdown(f'Für welchen Zeitraum soll *{absence_entries[absence_type]["name"]}* eingetragen werden?')
+ absence_dates = ui.date().props('range')
+ if day < 10:
+ day = f"0{str(day)}"
+ else:
+ day = str(day)
+ if int(select_month.value) < 10:
+ month = f"0{select_month.value}"
+ else:
+ month = select_month.value
+ absence_dates.value = f"{select_year.value}-{month}-{day}"
+
+ def add_absence_save():
+ # Bei nur einem Datum, direkt schreiben
+ if isinstance(absence_dates.value, str):
+ absence_date = absence_dates.value.split("-")
+ current_user.update_absence(absence_date[0], absence_date[1], absence_date[2], absence_type)
+ calendar_card.clear()
+ update_month_and_year()
+ # Bei Zeitbereich, aufteilen
+ elif isinstance(absence_dates.value, dict):
+ start_date = absence_dates.value["from"]
+ end_date = absence_dates.value["to"]
+ start_date = start_date.split("-")
+ end_date = end_date.split("-")
+
+ start_year = int(start_date[0])
+ end_year = int(end_date[0])
+ start_month = int(start_date[1])
+ end_month = int(end_date[1])
+ start_day = int(start_date[2])
+ end_day = int(end_date[2])
+
+ start_date = datetime.datetime(start_year, start_month, start_day)
+ end_date = datetime.datetime(end_year, end_month, end_day)
+ actual_date = start_date
+
+ while actual_date <= end_date:
+ current_user.workhours
+ current_user.update_absence(actual_date.year, actual_date.month, actual_date.day, absence_type)
+
+ actual_date = actual_date + datetime.timedelta(days=1)
+ clear_card()
+ ui.notify("Einträge vorgenomomen")
+ dialog.close()
+
+
+ with ui.grid(columns=3):
+ ui.button("Speichern", on_click=add_absence_save)
+ ui.space()
+ ui.button("Abbrechen", on_click=dialog.close)
+
+ dialog.open()
+ dialog.move(calendar_card)
+
+ with ui.button(icon='menu'):
+ with ui.menu() as menu:
+ ui.menu_item("Zeiteintrag hinzufügen", lambda day=day: add_entry(day))
+ 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))
+ if str(day) in list(user_absent):
+ menu_item.disable()
+
+ #ui.button("Eintrag hinzufügen", on_click=lambda day=day: add_entry(day))
+
+ #4x leer und dann Gesamtsaldo
+ for i in range(4):
+ ui.space()
+ ui.markdown(f"{convert_seconds_to_hours(general_saldo)}")
+ for i in range(4):
+ ui.space()
+ ui.markdown("Stunden aus Vormonat")
+ last_months_overtime = current_user.get_last_months_overtime(select_year.value, select_month.value)
+ ui.markdown(f"{convert_seconds_to_hours(last_months_overtime)}")
+ for i in range(4):
+ ui.space()
+ ui.markdown("Gesamtsaldo")
+ ui.markdown(f"**{convert_seconds_to_hours(general_saldo + last_months_overtime)}**")
+ table_grid.move(calendar_card)
+ update_month_and_year()
+
+ def clear_card():
+ calendar_card.clear()
+ update_month_and_year()
+ 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}**")
+
+ button_update = ui.button("Aktualisieren", on_click=clear_card)
+ button_update.move(timetable_header)
+
+
+ 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():
+ 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()
+
+ with ui.column():
+ 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("**Benutzereinstellungen**")
+ with ui.grid(columns=2):
+
+ ui.label("Benutzername:")
+ username_input = ui.input()
+ ui.label("Voller Name:")
+ fullname_input = ui.input()
+ ui.label("Passwort")
+ password_input = ui.input(password=True)
+ 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 = []
+ ui.markdown("**Arbeitszeiten**")
+
+ 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", 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()
+
+ 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:
+ ui.navigate.to("/login")
\ No newline at end of file
diff --git a/definitions.py b/definitions.py
index 7034256..a5c63cf 100644
--- a/definitions.py
+++ b/definitions.py
@@ -18,4 +18,17 @@ photofilename = "photo.jpg"
# Status
status_in = "eingestempelt"
-status_out = "ausgestempelt"
\ No newline at end of file
+status_out = "ausgestempelt"
+
+# Abesenheiten
+
+absence_entries = {"U": { "name": "Urlaub",
+ "color": "green"},
+ "K": { "name": "Krankheit",
+ "color": "red"},
+ "KK": { "name": "Krankheit Kind",
+ "color": "orange"},
+ "UU": { "name": "Urlaub aus Überstunden",
+ "color": "green"},
+ "F": { "name": "Fortbildung",
+ "color": "black"}}
diff --git a/login.py b/login.py
new file mode 100644
index 0000000..9b37f38
--- /dev/null
+++ b/login.py
@@ -0,0 +1,41 @@
+from datetime import datetime
+
+from nicegui import ui, app
+from web_ui import *
+
+from users import *
+from definitions import *
+from calendar import monthrange
+
+import hashlib
+import calendar
+import locale
+
+@ui.page('/login')
+def page_login():
+
+ # Settingsdatei einlesen
+ data = load_adminsettings()
+
+ def login():
+ nonlocal data
+
+ if username.value == data["admin_user"]:
+ if password.value == data["admin_password"]:
+ active_login = cookie_hash(data["admin_user"], data["admin_password"])
+ app.storage.user['secret'] = active_login
+ ui.navigate.to("/admin")
+ else:
+ ui.notify("Login fehlgeschlagen")
+
+ #ui.markdown(f"## {app_title} {app_version}")
+ #ui.markdown("Bitte einloggen")
+
+ pageheader("Bitte einloggen:")
+
+ with ui.grid(columns=2):
+ ui.markdown("Benutzer:")
+ username = ui.input('Benutzername')
+ ui.markdown("Passwort:")
+ password = ui.input('Passwort', password=True)
+ ui.button(text="Login", on_click=lambda: login())
\ No newline at end of file
diff --git a/main.py b/main.py
index e69de29..1af117a 100644
--- a/main.py
+++ b/main.py
@@ -0,0 +1,7 @@
+from web_ui import *
+from admin import *
+from login import *
+from users import *
+from touchscreen import *
+
+ui.run(port=8090, storage_secret="test")
\ No newline at end of file
diff --git a/touchscreen.py b/touchscreen.py
new file mode 100644
index 0000000..87b0f50
--- /dev/null
+++ b/touchscreen.py
@@ -0,0 +1,57 @@
+from datetime import datetime
+
+from nicegui import ui, app
+
+from users import *
+from definitions import *
+from web_ui import *
+from calendar import monthrange
+
+import hashlib
+import calendar
+import locale
+
+@ui.page('/touchscreen')
+def page_touchscreen():
+
+ def button_click(name):
+ nonlocal buttons
+ current_user = user(name)
+ current_user.timestamp()
+ if current_user.stamp_status() == status_in:
+ buttons[name].props('color=green')
+ ui.notify(status_in)
+ else:
+ buttons[name].props('color=red')
+ ui.notify(status_out)
+
+ pageheader("Bitte User auswählen:")
+
+ userlist = list_users()
+ number_of_users = len(userlist)
+ buttons = { }
+
+ if number_of_users > 5:
+ number_of_columns = 5
+ else:
+ number_of_columns = number_of_users
+
+
+ with ui.grid(columns=number_of_columns):
+ for name in userlist:
+ current_user = user(name)
+ current_button = ui.button(on_click=lambda name=name: button_click(name))
+ with current_button:
+ try:
+ with open(current_user.photofile, 'r') as file:
+ pass
+ file.close()
+ ui.image(current_user.photofile)
+ except:
+ pass
+ ui.label(current_user.fullname)
+ if current_user.stamp_status() == status_in:
+ current_button.props('color=green')
+ else:
+ current_button.props('color=red')
+ buttons[name] = current_button
\ No newline at end of file
diff --git a/users.py b/users.py
index 5be1841..855213f 100644
--- a/users.py
+++ b/users.py
@@ -7,6 +7,7 @@ import datetime
import time
import json
import shutil
+import re
from definitions import userfolder, scriptpath, usersettingsfilename, photofilename, status_in, status_out
@@ -32,18 +33,24 @@ class user:
self.username = data["username"]
self.fullname = data["fullname"]
- def get_stamp_file(self):
- year = str(datetime.datetime.now().year)
- month = str(datetime.datetime.now().month)
+ def get_stamp_file(self, time_stamp=None):
+ if time_stamp == None:
+ year = str(datetime.datetime.now().year)
+ month = str(datetime.datetime.now().month)
+ else:
+ year = str(datetime.datetime.fromtimestamp(time_stamp).year)
+ month = str(datetime.datetime.fromtimestamp(time_stamp).month)
completepath = f"{self.userfolder}/{year}-{month}"
return completepath
def timestamp(self, stamptime=-1):
- filename = f"{self.get_stamp_file()}.txt"
+
if stamptime == -1:
stamptime = time.time()
timestamp = int(stamptime)
+ filename = f"{self.get_stamp_file(time_stamp=stamptime)}.txt"
+
try:
# Öffne die Datei im Anhang-Modus ('a')
with open(filename, 'a') as file:
@@ -124,35 +131,78 @@ class user:
def del_user(self):
shutil.rmtree(self.userfolder)
+ def get_starting_day(self):
+ starting_date = list(self.workhours)
+ starting_date.sort()
+ year = str(starting_date[0])[:4]
+ month = str(starting_date[0])[5:7]
+ day = str(starting_date[0])[8:10]
+
+ return (year, month, day)
+
def get_years(self):
- txtfiles = [ ]
+ years = [ ]
+
+ # Aktuelles Jahr bestimmen
+ year_now = int(datetime.datetime.fromtimestamp(time.time()).strftime('%Y'))
+
+ for i in range(int(self.get_starting_day()[0]), year_now + 1):
+ years.append(str(i))
+
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
+ if re.match(r"\d{4}-\d{1,2}\.json", file):
+ year = file.split("-")[0]
+ if year not in years:
+ years.append(year)
+
+ years.sort()
+ print(years)
+ return years
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
+ # Anfangsdatum bestimmen
+ start_year = int(self.get_starting_day()[0])
+ start_month = int(self.get_starting_day()[1])
+ year_now = int(datetime.datetime.now().year)
+ month_now = int(datetime.datetime.now().month)
+
+ if start_year == int(year):
+
+ if start_year == year_now:
+ for i in range(start_month, month_now + 1):
+ available_months.append(i)
+ elif start_year < year_now:
+ for i in range(start_month, 13):
+ available_months.append(i)
+ else:
+ if int(year) == year_now:
+ for i in range(1, month_now + 1):
+ available_months.append(i)
+ elif int(year) < year_now:
+ for i in range(1, 13):
+ available_months.append(i)
+ print(available_months)
+ for file in os.listdir(self.userfolder):
+
+ if re.match(r"\d{4}-\d{1,2}\.json", file):
+ if file.split("-")[0] == str(year):
+ month = int(file.split("-")[1].split(".")[0])
+ if month not in available_months:
+ available_months.append(month)
+ available_months.sort()
+ return(available_months)
def get_timestamps(self, year, month):
- with open(f"{self.userfolder}/{year}-{month}.txt", "r") as file:
- timestamps = file.readlines()
- timestamps.sort()
- return timestamps
+ try:
+ with open(f"{self.userfolder}/{year}-{month}.txt", "r") as file:
+ timestamps = file.readlines()
+ timestamps.sort()
+ return timestamps
+ except:
+ timestamps = [ ]
+ return timestamps
def write_edited_timestamps(self, timestamps, year, month):
with open(f"{self.userfolder}/{year}-{month}.txt", "w") as file:
@@ -161,6 +211,82 @@ class user:
def archive_hours(self, year, month):
pass
+ def get_last_months_overtime(self, year, month):
+ try:
+ if int(month) == 1:
+ year = str(int(year) - 1)
+ month = str(12)
+ else:
+ month = str(int(month) - 1)
+ with open(f"{self.userfolder}/{year}-{month}.json", "r") as json_file:
+ json_data = json.load(json_file)
+
+ if json_data["archived"] == 1:
+ overtime = int(json_data["overtime"])
+ return overtime
+ else:
+ return 0
+ except:
+ return 0
+
+ def get_absence(self, year, month):
+ try:
+ with open(f"{self.userfolder}/{year}-{month}.json", "r") as json_file:
+ json_data = json.load(json_file)
+ absence = json_data["absence"]
+ return absence
+ except:
+ return { }
+
+ def update_absence(self, year, month, day, absence_type):
+ try:
+ with open(f"{self.userfolder}/{int(year)}-{int(month)}.json", "r") as json_file:
+ json_data = json.load(json_file)
+ except:
+ with open(f"{self.userfolder}/{year}-{month}.json", "w") as json_file:
+ json_data = { }
+ json_data["archived"] = 0
+ json_data["overtime"] = 0
+ json_dict = json.dumps(json_data, indent=4)
+ json_file.write(json_dict)
+ try:
+ json_data["absence"][str(int(day))] = absence_type
+ except:
+ json_data.update({ "absence": { str(int(day)): absence_type}})
+ json_dict = json.dumps(json_data, indent=4)
+ print(json_dict)
+ print(f"{self.userfolder}/{year}-{month}.json")
+
+ with open(f"{self.userfolder}/{int(year)}-{int(month)}.json", "w") as json_file:
+ json_file.write(json_dict)
+
+ def del_absence(self, year, month, day):
+ with open(f"{self.userfolder}/{int(year)}-{int(month)}.json", "r") as json_file:
+ json_data = json.load(json_file)
+
+ del json_data["absence"][str(day)]
+ json_dict = json.dumps(json_data, indent=4)
+
+ with open(f"{self.userfolder}/{int(year)}-{int(month)}.json", "w") as json_file:
+ json_file.write(json_dict)
+
+ def get_day_workhours(self, year, month, day):
+ workhour_entries = list(self.workhours)
+ workhour_entries.sort()
+ day_to_check = datetime.datetime(int(year), int(month), int(day))
+
+ for entry in reversed(workhour_entries):
+ entry_split = entry.split("-")
+ entry_dt = datetime.datetime(int(entry_split[0]), int(entry_split[1]), int(entry_split[2]))
+ if entry_dt <= day_to_check:
+ weekday = day_to_check.strftime("%w")
+ if int(weekday) == 0:
+ weekday = str(7)
+ hours_to_work = self.workhours[entry][weekday]
+ else:
+ # Wenn vor Einstellungsdatum -1 ausgeben
+ hours_to_work = -1
+ return hours_to_work
# Benutzer auflisten
def list_users():
diff --git a/users/testuser1/2025-3.json b/users/testuser1/2025-3.json
index 7ac4a6f..8727377 100644
--- a/users/testuser1/2025-3.json
+++ b/users/testuser1/2025-3.json
@@ -1,4 +1,4 @@
{
"archived": 1,
- "total_hours": 28
+ "overtime": 3950
}
\ No newline at end of file
diff --git a/users/testuser1/2025-3.txt b/users/testuser1/2025-3.txt
index f25130e..7350e03 100644
--- a/users/testuser1/2025-3.txt
+++ b/users/testuser1/2025-3.txt
@@ -26,3 +26,5 @@
1745181050
1745240760
1745240762
+1740996000
+1740997800
diff --git a/users/testuser1/2025-4.json b/users/testuser1/2025-4.json
new file mode 100644
index 0000000..7ce53cc
--- /dev/null
+++ b/users/testuser1/2025-4.json
@@ -0,0 +1,9 @@
+{
+ "archived": 0,
+ "overtime": 0,
+ "absence": {
+ "7": "K",
+ "8": "UU",
+ "9": "KK"
+ }
+}
\ No newline at end of file
diff --git a/users/testuser1/2025-4.txt b/users/testuser1/2025-4.txt
index ab032c6..0a59752 100644
--- a/users/testuser1/2025-4.txt
+++ b/users/testuser1/2025-4.txt
@@ -1,13 +1,5 @@
-1743562800
-1743566400
-1743584340
-1743606000
-1743652800
-1743660240
-1743667140
-1743685200
1744889948
-1744889966
+1744890300
1744989797
1744989827
1744989830
@@ -22,15 +14,9 @@
1744991473
1744991477
1744991770
-1744991777
-1745181046
-1745181050
-1745240760
+1745215200
+1745229600
1745390818
1745390894
1745390894
1745391029
-1745391037
-1745391056
-1745391058
-1745391059
diff --git a/users/testuser1/2025-5.json b/users/testuser1/2025-5.json
new file mode 100644
index 0000000..813396e
--- /dev/null
+++ b/users/testuser1/2025-5.json
@@ -0,0 +1,7 @@
+{
+ "archived": 0,
+ "overtime": 0,
+ "absence": {
+ "14": "U"
+ }
+}
\ No newline at end of file
diff --git a/users/testuser1/2026-4.json b/users/testuser1/2026-4.json
new file mode 100644
index 0000000..e24cac5
--- /dev/null
+++ b/users/testuser1/2026-4.json
@@ -0,0 +1,7 @@
+{
+ "archived": 0,
+ "overtime": 0,
+ "absence": {
+ "14": "F"
+ }
+}
\ No newline at end of file
diff --git a/users/testuser1/settings.json b/users/testuser1/settings.json
index ddeac0f..83a6dee 100644
--- a/users/testuser1/settings.json
+++ b/users/testuser1/settings.json
@@ -3,7 +3,7 @@
"fullname": "Pia Paulina",
"password": "123456789",
"workhours": {
- "2024-04-01": {
+ "2025-04-03": {
"1": "4",
"2": "8",
"3": "8",
diff --git a/users/testuser10/2025-4.json b/users/testuser10/2025-4.json
index b7881be..48d10a6 100644
--- a/users/testuser10/2025-4.json
+++ b/users/testuser10/2025-4.json
@@ -1,4 +1,7 @@
{
"archived": 0,
- "total_hours": 0
+ "total_hours": 0,
+ "absence": {
+ "1": "U"
+ }
}
\ No newline at end of file
diff --git a/web_ui.py b/web_ui.py
index 774f892..1420d52 100644
--- a/web_ui.py
+++ b/web_ui.py
@@ -1,4 +1,3 @@
-import datetime
from datetime import datetime
from nicegui import ui, app
@@ -22,7 +21,7 @@ class pageheader:
class ValueBinder:
def __init__(self):
- self.value_to_bind = ""
+ self.value = ""
def cookie_hash(user, password):
return hashlib.sha256(b"{user}{app.storage.user['id']}{password}").hexdigest()
@@ -63,595 +62,6 @@ def convert_seconds_to_hours(seconds):
else:
return(f"{hours}:{minutes}")
-
-@ui.page('/login')
-def page_login():
-
- # Settingsdatei einlesen
- data = load_adminsettings()
-
- def login():
- nonlocal data
-
- if username.value == data["admin_user"]:
- if password.value == data["admin_password"]:
- active_login = cookie_hash(data["admin_user"], data["admin_password"])
- app.storage.user['secret'] = active_login
- ui.navigate.to("/admin")
- else:
- ui.notify("Login fehlgeschlagen")
-
- #ui.markdown(f"## {app_title} {app_version}")
- #ui.markdown("Bitte einloggen")
-
- pageheader("Bitte einloggen:")
-
- with ui.grid(columns=2):
- ui.markdown("Benutzer:")
- username = ui.input('Benutzername')
- ui.markdown("Passwort:")
- password = ui.input('Passwort', password=True)
- ui.button(text="Login", on_click=lambda: login())
-
-
-@ui.page('/admin')
-def page_admin():
- data = load_adminsettings()
- active_login = cookie_hash(data["admin_user"], data["admin_password"])
- try:
- browser_cookie = app.storage.user['secret']
- except:
- browser_cookie = ""
-
- # Adminseite
- 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=time_overview)):
-
- with ui.tab_panel(time_overview):
- ui.markdown("##Übersichten")
-
- # Tabelle konstruieren
- with ui.card():
-
- with ui.row() as timetable_header:
- year_binder = ValueBinder()
- month_binder = ValueBinder()
-
- def update_months():
- try:
- current_user = user(time_user.value)
- available_months = current_user.get_months(year_binder.value_to_bind)
- available_months_dict = {}
- for element in available_months:
- available_months_dict[element] = calendar.month_name[int(element)]
- select_month.clear()
- select_month.set_options(available_months_dict)
- select_month.value = list(available_months)[0]
- except:
- pass
-
- userlist = list_users()
- ui.markdown("Benutzer:")
- time_user = ui.select(options=userlist, on_change=update_months)
-
- time_user.value = userlist[0]
- 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).bind_value(month_binder, 'value_to_bind')
-
- select_year = ui.select(options=available_years, on_change=update_months).bind_value(year_binder, 'value_to_bind')
- try:
- select_year.value = str(current_year)
- except:
- pass
- try:
- select_month.value = str(current_month)
- except:
- select_month.value = str(available_months[0])
-
- month_header = ui.markdown(f"###Buchungen für {calendar.month_name[int(select_month.value)]} {select_year.value}")
-
- # Tabelle aufbauen
- with ui.card() as calendar_card:
- def update_month_and_year():
-
- with ui.grid(columns='auto auto 1fr 1fr 1fr 1fr') as table_grid:
- ui.markdown("**Datum**")
- ui.markdown("**Buchungen**")
- ui.markdown("**Soll**")
- ui.markdown("**Ist**")
- ui.markdown("**Saldo**")
- ui.space()
-
- current_user = user(time_user.value)
- timestamps = current_user.get_timestamps(year=select_year.value, month=select_month.value)
-
- general_saldo = 0
-
- for day in range(1, monthrange(int(select_year.value), int(select_month.value))[1] + 1):
- day_in_list = datetime.datetime(int(select_year.value), int(select_month.value), day)
-
- ui.markdown(f"{day_in_list.strftime('%a')}., {day}. {calendar.month_name[int(select_month.value)]}")
-
- # Buchungen
-
- with ui.row():
- counter = 0
-
- for i in timestamps:
- actual_timestamp = datetime.datetime.fromtimestamp(int(i))
- timestamp_day = actual_timestamp.strftime('%-d')
-
- if int(timestamp_day) == int(day):
- def edit_entry(t_stamp, day):
- with ui.dialog() as edit_dialog, ui.card():
- ui.markdown("###Eintrag bearbeiten")
- timestamp = datetime.datetime.fromtimestamp(int(t_stamp))
- input_time = ui.time().classes('w-full justify-center')
- input_time.value = timestamp.strftime('%H:%M')
-
- def save_entry(day):
-
- position = timestamps.index(t_stamp)
- new_time_stamp = datetime.datetime(int(select_year.value), int(select_month.value), day, int(input_time.value[:2]), int(input_time.value[-2:]))
- timestamps[position] = str(
- int(new_time_stamp.timestamp())) + "\n"
- # print(timestamps)
- current_user = user(time_user.value)
- current_user.write_edited_timestamps(timestamps, select_year.value, select_month.value)
- edit_dialog.close()
- calendar_card.clear()
- update_month_and_year()
- month_header.set_content(f"###Buchungen für {calendar.month_name[int(select_month.value)]} {select_year.value}")
- ui.notify("Eintrag gespeichert")
-
- def del_entry():
- timestamps.remove(t_stamp)
- timestamps.sort()
- current_user = user(time_user.value)
- current_user.write_edited_timestamps(timestamps, select_year.value, select_month.value)
- edit_dialog.close()
- calendar_card.clear()
- update_month_and_year()
- month_header.set_content(f"###Buchungen für {calendar.month_name[int(select_month.value)]} {select_year.value}")
- ui.notify("Eintrag gelöscht")
-
- with ui.row():
- ui.button("Speichern",
- on_click=lambda day=day: save_entry(day))
- ui.button("Löschen", on_click=del_entry)
- ui.button("Abbrechen", on_click=edit_dialog.close)
-
- edit_dialog.open()
- counter += 1
-
- ui.button(actual_timestamp.strftime('%H:%M'), on_click=lambda t_stamp=i, day=day: edit_entry(t_stamp, day))
- if counter % 2 != 0:
- ui.markdown("-")
- else:
- ui.markdown("|")
-
- # Arbeitszeitsoll bestimmen
- workhour_entries = list(current_user.workhours)
- workhour_entries.sort()
-
- found_match = False
- for entry in reversed(workhour_entries):
-
- if datetime.datetime.strptime(entry, '%Y-%m-%d').timestamp() < day_in_list.timestamp() and found_match == False:
-
- if int(day_in_list.strftime('%w')) == 0:
- weekday_index = 7
- else:
- weekday_index = int(day_in_list.strftime('%w'))
- ui.markdown(f"{current_user.workhours[entry][str(weekday_index)]} h")
- found_match = True
-
- # Arbeitszeit Ist bestimmen
- timestamps_of_this_day = [ ]
-
- # Suche mir alle timestamps für diesen Tag
- for i in timestamps:
- actual_timestamp = datetime.datetime.fromtimestamp(int(i))
- timestamp_day = actual_timestamp.strftime('%-d')
-
- if int(timestamp_day) == int(day):
- timestamps_of_this_day.append(i)
-
- timestamps_of_this_day.sort()
- time_sum = 0
- if len(timestamps_of_this_day) > 1:
-
-
- if len(timestamps_of_this_day) % 2 == 0:
- for i in range(0, len(timestamps_of_this_day), 2):
- time_delta = int(timestamps_of_this_day[i+1]) - int(timestamps_of_this_day[i])
- time_sum = time_sum + time_delta
- else:
- for i in range(0, len(timestamps_of_this_day) - 1, 2):
- time_delta = int(timestamps_of_this_day[i+1]) - int(timestamps_of_this_day[i])
- time_sum = time_sum + time_delta
-
- ui.markdown(convert_seconds_to_hours(time_sum))
- else:
- ui.markdown("Kein")
-
- # Plus und Minuszeit für den Tag berechnen
- if time.time() > day_in_list.timestamp():
- time_duty = int(current_user.workhours[entry][str(weekday_index)]) * 3600
-
- saldo = int(time_sum) - int(time_duty)
- general_saldo = general_saldo + saldo
- ui.markdown(convert_seconds_to_hours(saldo))
- else:
- ui.markdown("-")
-
-
- def add_entry(day):
- with ui.dialog() as add_dialog, ui.card():
- ui.markdown("###Eintrag hinzufügen")
- input_time = ui.time().classes('w-full justify-center')
-
- def add_entry_save():
- if input_time.value == None:
- ui.notify("Bitte eine Uhrzeit auswählen.")
- return
-
- new_time_stamp = datetime.datetime(int(select_year.value),
- int(select_month.value), day,
- int(input_time.value[:2]),
- int(input_time.value[-2:])).timestamp()
- current_user = user(time_user.value)
- current_user.timestamp(stamptime=int(new_time_stamp))
- calendar_card.clear()
- update_month_and_year()
- add_dialog.close()
- ui.notify("Eintrag hinzugefügt")
- with ui.grid(columns=3):
- ui.button("Speichern", on_click=add_entry_save)
- ui.space()
- ui.button("Abbrechen", on_click=add_dialog.close)
- add_dialog.open()
- ui.button("Eintrag hinzufügen", on_click=lambda day=day: add_entry(day))
- #4x leer und dann Gesamtsald
- for i in range(4):
- ui.space()
- ui.markdown(f"{convert_seconds_to_hours(general_saldo)}")
- table_grid.move(calendar_card)
- update_month_and_year()
-
- def clear_card():
- calendar_card.clear()
- update_month_and_year()
- month_header.set_content(f"###Buchungen für {calendar.month_name[int(select_month.value)]} {select_year.value}")
-
- button_update = ui.button("Aktualisieren", on_click=clear_card)
- button_update.move(timetable_header)
-
-
- 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():
- 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()
-
- with ui.column():
- 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("**Benutzereinstellungen**")
- with ui.grid(columns=2):
-
- ui.label("Benutzername:")
- username_input = ui.input()
- ui.label("Voller Name:")
- fullname_input = ui.input()
- ui.label("Passwort")
- password_input = ui.input(password=True)
- 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 = []
- ui.markdown("**Arbeitszeiten**")
-
- 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", 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()
-
- 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:
- ui.navigate.to("/login")
-
-@ui.page('/stamping')
-def page_stamping():
- ui.label('Stempelsteite')
-
-@ui.page('/touchscreen')
-def page_touchscreen():
-
- def button_click(name):
- nonlocal buttons
- current_user = user(name)
- current_user.timestamp()
- if current_user.stamp_status() == status_in:
- buttons[name].props('color=green')
- ui.notify(status_in)
- else:
- buttons[name].props('color=red')
- ui.notify(status_out)
-
- pageheader("Bitte User auswählen:")
-
- userlist = list_users()
- number_of_users = len(userlist)
- buttons = { }
-
- if number_of_users > 5:
- number_of_columns = 5
- else:
- number_of_columns = number_of_users
-
-
- with ui.grid(columns=number_of_columns):
- for name in userlist:
- current_user = user(name)
- current_button = ui.button(on_click=lambda name=name: button_click(name))
- with current_button:
- try:
- with open(current_user.photofile, 'r') as file:
- pass
- file.close()
- ui.image(current_user.photofile)
- except:
- pass
- ui.label(current_user.fullname)
- if current_user.stamp_status() == status_in:
- current_button.props('color=green')
- else:
- current_button.props('color=red')
- buttons[name] = current_button
-
-
@ui.page('/userlist')
def page_userlist():
@@ -667,6 +77,4 @@ def page_userlist():
button = ui.button(text=name, on_click=lambda name=name:click_button(name) )
buttons[name] = button
-ui.run(port=8090, storage_secret="test")
-