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