Merge branch 'api' into web_ui
This commit is contained in:
commit
2d6e64fe0d
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.pyc
|
168
admin.py
168
admin.py
@ -16,19 +16,19 @@ import locale
|
|||||||
def page_admin():
|
def page_admin():
|
||||||
ui.page_title(f"{app_title} {app_version}")
|
ui.page_title(f"{app_title} {app_version}")
|
||||||
data = load_adminsettings()
|
data = load_adminsettings()
|
||||||
active_login = cookie_hash(data["admin_user"], data["admin_password"])
|
|
||||||
try:
|
try:
|
||||||
browser_cookie = app.storage.user['secret']
|
browser_cookie = app.storage.user['admin_authenticated']
|
||||||
except:
|
except:
|
||||||
browser_cookie = ""
|
browser_cookie = False
|
||||||
|
|
||||||
# Adminseite
|
# Adminseite
|
||||||
if browser_cookie == active_login:
|
if browser_cookie:
|
||||||
pageheader("Administration")
|
pageheader("Administration")
|
||||||
|
|
||||||
def admin_logout():
|
def admin_logout():
|
||||||
app.storage.user['secret'] = ""
|
app.storage.user.pop("admin_authenticated", None)
|
||||||
ui.navigate.to("/login")
|
ui.navigate.to("/")
|
||||||
|
|
||||||
ui.button("Logout", on_click=admin_logout)
|
ui.button("Logout", on_click=admin_logout)
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ def page_admin():
|
|||||||
settings = ui.tab('Einstellungen')
|
settings = ui.tab('Einstellungen')
|
||||||
users = ui.tab('Benutzer')
|
users = ui.tab('Benutzer')
|
||||||
|
|
||||||
with ((ui.tab_panels(tabs, value=time_overview))):
|
with (((ui.tab_panels(tabs, value=time_overview)))):
|
||||||
|
|
||||||
with ui.tab_panel(time_overview):
|
with ui.tab_panel(time_overview):
|
||||||
ui.markdown("##Übersichten")
|
ui.markdown("##Übersichten")
|
||||||
@ -106,7 +106,6 @@ def page_admin():
|
|||||||
select_month = ui.select(options=available_months_dict, value=set_month).bind_value_to(month_binder, 'value')
|
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')
|
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}**")
|
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
|
# Tabelle aufbauen
|
||||||
@ -121,6 +120,7 @@ def page_admin():
|
|||||||
ui.markdown("**Saldo**")
|
ui.markdown("**Saldo**")
|
||||||
ui.space()
|
ui.space()
|
||||||
|
|
||||||
|
|
||||||
current_user = user(time_user.value)
|
current_user = user(time_user.value)
|
||||||
timestamps = current_user.get_timestamps(year=select_year.value, month=select_month.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)
|
user_absent = current_user.get_absence(year=select_year.value, month=select_month.value)
|
||||||
@ -141,7 +141,10 @@ def page_admin():
|
|||||||
for day in list(timestamps_dict):
|
for day in list(timestamps_dict):
|
||||||
# Datum für Tabelle konstruieren
|
# Datum für Tabelle konstruieren
|
||||||
day_in_list = datetime.datetime(int(select_year.value), int(select_month.value), day)
|
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)]}")
|
class_content = ""
|
||||||
|
if day_in_list.date() == datetime.datetime.now().date():
|
||||||
|
class_content = 'font-bold text-red-700 uppercase'
|
||||||
|
ui.markdown(f"{day_in_list.strftime('%a')}., {day}. {calendar.month_name[int(select_month.value)]}").classes(class_content)
|
||||||
|
|
||||||
# Buchungen
|
# Buchungen
|
||||||
|
|
||||||
@ -180,7 +183,7 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
def edit_entry(t_stamp, day):
|
def edit_entry(t_stamp, day):
|
||||||
|
|
||||||
with ui.dialog() as edit_dialog, ui.card():
|
with ui.dialog() as edit_dialog, ui.card():
|
||||||
ui.markdown("###Eintrag bearbeiten")
|
ui.markdown("**Eintrag bearbeiten**")
|
||||||
timestamp = datetime.datetime.fromtimestamp(int(t_stamp))
|
timestamp = datetime.datetime.fromtimestamp(int(t_stamp))
|
||||||
input_time = ui.time().props('format24h now-btn').classes('w-full justify-center')
|
input_time = ui.time().props('format24h now-btn').classes('w-full justify-center')
|
||||||
|
|
||||||
@ -244,6 +247,7 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
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))
|
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
|
# Arbeitszeit Ist bestimmen
|
||||||
|
|
||||||
timestamps_of_this_day = []
|
timestamps_of_this_day = []
|
||||||
|
|
||||||
# Suche mir alle timestamps für diesen Tag
|
# Suche mir alle timestamps für diesen Tag
|
||||||
@ -255,6 +259,7 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
timestamps_of_this_day.append(i)
|
timestamps_of_this_day.append(i)
|
||||||
|
|
||||||
timestamps_of_this_day.sort()
|
timestamps_of_this_day.sort()
|
||||||
|
|
||||||
time_sum = 0
|
time_sum = 0
|
||||||
if len(timestamps_of_this_day) > 1:
|
if len(timestamps_of_this_day) > 1:
|
||||||
|
|
||||||
@ -271,7 +276,7 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
timestamps_of_this_day[i])
|
timestamps_of_this_day[i])
|
||||||
time_sum = time_sum + time_delta
|
time_sum = time_sum + time_delta
|
||||||
|
|
||||||
ui.markdown(convert_seconds_to_hours(time_sum))
|
ui.markdown(convert_seconds_to_hours(time_sum)).classes('text-right')
|
||||||
else:
|
else:
|
||||||
ui.markdown("Kein")
|
ui.markdown("Kein")
|
||||||
|
|
||||||
@ -281,12 +286,13 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
if hours_to_work < 0:
|
if hours_to_work < 0:
|
||||||
ui.space()
|
ui.space()
|
||||||
else:
|
else:
|
||||||
ui.markdown(f"{convert_seconds_to_hours(int(hours_to_work) * 3600)}")
|
ui.markdown(f"{convert_seconds_to_hours(int(hours_to_work) * 3600)}").classes('text-right')
|
||||||
if int(hours_to_work) == 0:
|
if int(hours_to_work) == 0:
|
||||||
day_type.content = "**Kein Arbeitstag**"
|
day_type.content = "**Kein Arbeitstag**"
|
||||||
day_type.set_visibility(True)
|
day_type.set_visibility(True)
|
||||||
|
|
||||||
|
if day_in_list.strftime("%Y-%m-%d") in data["holidays"]:
|
||||||
|
day_type.content = f'**{data["holidays"][day_in_list.strftime("%Y-%m-%d")]}**'
|
||||||
|
|
||||||
# Saldo für den Tag berechnen
|
# Saldo für den Tag berechnen
|
||||||
|
|
||||||
@ -306,9 +312,9 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
general_saldo = general_saldo + saldo
|
general_saldo = general_saldo + saldo
|
||||||
ui.markdown(convert_seconds_to_hours(saldo))
|
ui.markdown(convert_seconds_to_hours(saldo)).classes('text-right')
|
||||||
else:
|
else:
|
||||||
ui.markdown("-")
|
ui.markdown("-").classes('text-center')
|
||||||
|
|
||||||
def add_entry(day):
|
def add_entry(day):
|
||||||
with ui.dialog() as add_dialog, ui.card():
|
with ui.dialog() as add_dialog, ui.card():
|
||||||
@ -338,9 +344,15 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
add_dialog.move(calendar_card)
|
add_dialog.move(calendar_card)
|
||||||
|
|
||||||
def add_absence(absence_type, day):
|
def add_absence(absence_type, day):
|
||||||
with ui.dialog() as dialog, ui.card():
|
with ui.dialog() as dialog, ui.card().classes('w-[350px]'):
|
||||||
ui.markdown(f'Für welchen Zeitraum soll *{absence_entries[absence_type]["name"]}* eingetragen werden?')
|
ui.markdown(f'Für welchen Zeitraum soll *{absence_entries[absence_type]["name"]}* eingetragen werden?').classes('w-full')
|
||||||
absence_dates = ui.date().props('range')
|
absence_dates = ui.date().props('range today-btn').classes('w-full justify-center')
|
||||||
|
absence_dates._props['locale'] = {'daysShort': ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'],
|
||||||
|
'months': ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
|
||||||
|
'monthsShort': ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']}
|
||||||
|
absence_dates._props['title'] = absence_entries[absence_type]["name"]
|
||||||
|
absence_dates._props['minimal'] = True
|
||||||
|
|
||||||
if day < 10:
|
if day < 10:
|
||||||
day = f"0{str(day)}"
|
day = f"0{str(day)}"
|
||||||
else:
|
else:
|
||||||
@ -398,7 +410,7 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
dialog.close()
|
dialog.close()
|
||||||
|
|
||||||
|
|
||||||
with ui.grid(columns=3):
|
with ui.grid(columns=3).classes('w-full justify-center'):
|
||||||
ui.button("Speichern", on_click=add_absence_save)
|
ui.button("Speichern", on_click=add_absence_save)
|
||||||
ui.space()
|
ui.space()
|
||||||
ui.button("Abbrechen", on_click=dialog.close)
|
ui.button("Abbrechen", on_click=dialog.close)
|
||||||
@ -418,18 +430,13 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
#ui.button("Eintrag hinzufügen", on_click=lambda day=day: add_entry(day))
|
#ui.button("Eintrag hinzufügen", on_click=lambda day=day: add_entry(day))
|
||||||
|
|
||||||
#4x leer und dann Gesamtsaldo
|
#4x leer und dann Gesamtsaldo
|
||||||
for i in range(4):
|
ui.space().classes('col-span-4')
|
||||||
ui.space()
|
ui.markdown(f"{convert_seconds_to_hours(general_saldo)}").classes('text-right')
|
||||||
ui.markdown(f"{convert_seconds_to_hours(general_saldo)}")
|
ui.markdown("Stunden aus Vormonat").classes('col-span-4 text-right')
|
||||||
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)
|
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)}")
|
ui.markdown(f"{convert_seconds_to_hours(last_months_overtime)}").classes('text-right')
|
||||||
for i in range(4):
|
ui.markdown("Gesamtsaldo").classes('col-span-4 text-right')
|
||||||
ui.space()
|
ui.markdown(f"**<ins>{convert_seconds_to_hours(general_saldo + last_months_overtime)}</ins>**").classes('text-right')
|
||||||
ui.markdown("Gesamtsaldo")
|
|
||||||
ui.markdown(f"**<ins>{convert_seconds_to_hours(general_saldo + last_months_overtime)}</ins>**")
|
|
||||||
table_grid.move(calendar_card)
|
table_grid.move(calendar_card)
|
||||||
update_month_and_year()
|
update_month_and_year()
|
||||||
|
|
||||||
@ -449,15 +456,17 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
def save_admin_settings():
|
def save_admin_settings():
|
||||||
output_dict = { }
|
output_dict = { }
|
||||||
output_dict["admin_user"] = admin_user.value
|
output_dict["admin_user"] = admin_user.value
|
||||||
output_dict["admin_password"] = admin_password.value
|
if admin_password.value != "":
|
||||||
|
output_dict["admin_password"] = hash_password(admin_password.value)
|
||||||
|
else:
|
||||||
|
output_dict["admin_password"] = data["admin_password"]
|
||||||
output_dict["port"] = port.value
|
output_dict["port"] = port.value
|
||||||
output_dict["secret"] = secret
|
output_dict["secret"] = secret
|
||||||
|
output_dict["holidays"] = data["holidays"]
|
||||||
json_dict = json.dumps(output_dict, indent=4)
|
json_dict = json.dumps(output_dict, indent=4)
|
||||||
with open(f"{scriptpath}/{usersettingsfilename}", "w") as outputfile:
|
with open(f"{scriptpath}/{usersettingsfilename}", "w") as outputfile:
|
||||||
outputfile.write(json_dict)
|
outputfile.write(json_dict)
|
||||||
print(old_port)
|
if int(old_port) != int(port.value):
|
||||||
print(int(port.value))
|
|
||||||
if old_port != int(port.value):
|
|
||||||
with ui.dialog() as dialog, ui.card():
|
with ui.dialog() as dialog, ui.card():
|
||||||
ui.markdown("Damit die Porteinstellungen wirksam werden, muss der Server neu gestartet werden.")
|
ui.markdown("Damit die Porteinstellungen wirksam werden, muss der Server neu gestartet werden.")
|
||||||
ui.button("OK", on_click=lambda: dialog.close())
|
ui.button("OK", on_click=lambda: dialog.close())
|
||||||
@ -467,9 +476,8 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
ui.markdown("Benutzername des Adminstrators")
|
ui.markdown("Benutzername des Adminstrators")
|
||||||
admin_user = ui.input()
|
admin_user = ui.input()
|
||||||
admin_user.value = data["admin_user"]
|
admin_user.value = data["admin_user"]
|
||||||
ui.markdown("Passwort des Adminsistrators")
|
ui.markdown("Passwort des Administrators")
|
||||||
admin_password = ui.input(password=True)
|
admin_password = ui.input(password=True)
|
||||||
admin_password.value = data["admin_password"]
|
|
||||||
|
|
||||||
secret = data["secret"]
|
secret = data["secret"]
|
||||||
|
|
||||||
@ -481,6 +489,82 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
port = ui.input()
|
port = ui.input()
|
||||||
old_port = data["port"]
|
old_port = data["port"]
|
||||||
port.value = old_port
|
port.value = old_port
|
||||||
|
|
||||||
|
def holiday_section():
|
||||||
|
with ui.card():
|
||||||
|
ui.markdown('**Feiertage:**')
|
||||||
|
|
||||||
|
def new_holiday_entry():
|
||||||
|
def add_holiday_to_dict():
|
||||||
|
year_from_picker = int(datepicker.value.split("-")[0])
|
||||||
|
month_from_picker = int(datepicker.value.split("-")[1])
|
||||||
|
day_from_picker = int(datepicker.value.split("-")[2])
|
||||||
|
for i in range(0, int(repetition.value)):
|
||||||
|
repetition_date_dt = datetime.datetime(year_from_picker + i, month_from_picker, day_from_picker)
|
||||||
|
date_entry = repetition_date_dt.strftime('%Y-%m-%d')
|
||||||
|
data["holidays"][date_entry] = description.value
|
||||||
|
print(data['holidays'])
|
||||||
|
holiday_buttons_grid.refresh()
|
||||||
|
dialog.close()
|
||||||
|
|
||||||
|
with ui.dialog() as dialog, ui.card():
|
||||||
|
with ui.grid(columns='auto auto'):
|
||||||
|
ui.markdown('Geben Sie den neuen Feiertag ein:').classes('col-span-2')
|
||||||
|
datepicker = ui.date(value=datetime.datetime.now().strftime('%Y-%m-%d')).classes('col-span-2')
|
||||||
|
description = ui.input('Beschreibung').classes('col-span-2')
|
||||||
|
repetition = ui.number('Für Jahre wiederholen', value=1, min=1, precision=0).classes('col-span-2')
|
||||||
|
ui.button("OK", on_click=add_holiday_to_dict)
|
||||||
|
ui.button('Abbrechen', on_click=dialog.close)
|
||||||
|
dialog.open()
|
||||||
|
|
||||||
|
@ui.refreshable
|
||||||
|
def holiday_buttons_grid():
|
||||||
|
|
||||||
|
holidays = list(data["holidays"])
|
||||||
|
holidays.sort()
|
||||||
|
|
||||||
|
year_list = []
|
||||||
|
|
||||||
|
# Jahresliste erzeugen
|
||||||
|
for i in holidays:
|
||||||
|
i_split = i.split("-")
|
||||||
|
year = int(i_split[0])
|
||||||
|
year_list.append(year)
|
||||||
|
|
||||||
|
year_list = list(set(year_list))
|
||||||
|
year_dict = {}
|
||||||
|
|
||||||
|
# Jahresdictionary konstruieren
|
||||||
|
for i in year_list:
|
||||||
|
year_dict[i] = []
|
||||||
|
|
||||||
|
for i in holidays:
|
||||||
|
i_split = i.split("-")
|
||||||
|
year = int(i_split[0])
|
||||||
|
month = int(i_split[1])
|
||||||
|
day = int(i_split[2])
|
||||||
|
date_dt = datetime.datetime(year, month, day)
|
||||||
|
year_dict[year].append(date_dt)
|
||||||
|
|
||||||
|
def del_holiday_entry(entry):
|
||||||
|
del(data['holidays'][entry.strftime('%Y-%m-%d')])
|
||||||
|
holiday_buttons_grid.refresh()
|
||||||
|
|
||||||
|
with ui.grid(columns='auto auto'):
|
||||||
|
ui.space()
|
||||||
|
with ui.row():
|
||||||
|
ui.button("Neuer Eintrag", on_click=new_holiday_entry)
|
||||||
|
|
||||||
|
for year_entry in year_list:
|
||||||
|
ui.markdown(f"{str(year_entry)}:")
|
||||||
|
with ui.row():
|
||||||
|
for entry in year_dict[year_entry]:
|
||||||
|
date_label = entry.strftime("%d.%m.%Y")
|
||||||
|
ui.button(f"{data['holidays'][entry.strftime('%Y-%m-%d')]} ({date_label})", on_click=lambda entry=entry: del_holiday_entry(entry)).classes('bg-blue')
|
||||||
|
holiday_buttons_grid()
|
||||||
|
|
||||||
|
holiday_section()
|
||||||
|
|
||||||
ui.button("Speichern", on_click=save_admin_settings)
|
ui.button("Speichern", on_click=save_admin_settings)
|
||||||
|
|
||||||
with ui.tab_panel(users):
|
with ui.tab_panel(users):
|
||||||
@ -497,7 +581,7 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
current_user = user(user_selection.value)
|
current_user = user(user_selection.value)
|
||||||
username_input.value = current_user.username
|
username_input.value = current_user.username
|
||||||
fullname_input.value = current_user.fullname
|
fullname_input.value = current_user.fullname
|
||||||
password_input.value = current_user.password
|
#password_input.value = current_user.password
|
||||||
usersettingscard.visible = True
|
usersettingscard.visible = True
|
||||||
|
|
||||||
workhours_select.clear()
|
workhours_select.clear()
|
||||||
@ -513,7 +597,6 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
user_photo.set_visibility(os.path.exists(current_user.photofile))
|
user_photo.set_visibility(os.path.exists(current_user.photofile))
|
||||||
delete_button.set_visibility(os.path.exists(current_user.photofile))
|
delete_button.set_visibility(os.path.exists(current_user.photofile))
|
||||||
|
|
||||||
|
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -538,8 +621,9 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
current_user = user(user_selection.value)
|
current_user = user(user_selection.value)
|
||||||
current_user.username = username_input.value
|
current_user.username = username_input.value
|
||||||
current_user.fullname = fullname_input.value
|
current_user.fullname = fullname_input.value
|
||||||
current_user.password = password_input.value
|
current_user.password = hash_password(password_input.value)
|
||||||
current_user.write_settings()
|
current_user.write_settings()
|
||||||
|
password_input.value = ""
|
||||||
userlist = list_users()
|
userlist = list_users()
|
||||||
userlist.sort()
|
userlist.sort()
|
||||||
user_selection.clear()
|
user_selection.clear()
|
||||||
@ -588,7 +672,7 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
if i < 7:
|
if i < 7:
|
||||||
construct_dict[i+1] = days[i].value
|
construct_dict[i+1] = days[i].value
|
||||||
elif i == 7:
|
elif i == 7:
|
||||||
conctruct_dict[0] = days[i].value
|
construct_dict[0] = days[i].value
|
||||||
|
|
||||||
construct_dict["vacation"] = vacation_input.value
|
construct_dict["vacation"] = vacation_input.value
|
||||||
current_user.workhours[workhours_select.value] = construct_dict
|
current_user.workhours[workhours_select.value] = construct_dict
|
||||||
@ -646,6 +730,7 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
fullname_input = ui.input()
|
fullname_input = ui.input()
|
||||||
ui.markdown("Passwort")
|
ui.markdown("Passwort")
|
||||||
password_input = ui.input(password=True)
|
password_input = ui.input(password=True)
|
||||||
|
password_input.value = ""
|
||||||
|
|
||||||
with ui.grid(columns=2):
|
with ui.grid(columns=2):
|
||||||
ui.button("Speichern", on_click=save_user_settings)
|
ui.button("Speichern", on_click=save_user_settings)
|
||||||
@ -745,4 +830,5 @@ Dies kann nicht rückgägig gemacht werden!''')
|
|||||||
|
|
||||||
# Alternativ zur Loginseite navigieren
|
# Alternativ zur Loginseite navigieren
|
||||||
else:
|
else:
|
||||||
ui.navigate.to("/login")
|
login = login_mask()
|
||||||
|
#ui.navigate.to("/login")
|
383
api.py
Normal file
383
api.py
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
import sys
|
||||||
|
from calendar import month_name
|
||||||
|
from logging import exception
|
||||||
|
|
||||||
|
from nicegui import *
|
||||||
|
|
||||||
|
import ui
|
||||||
|
from definitions import *
|
||||||
|
from web_ui import *
|
||||||
|
from users import *
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import calendar
|
||||||
|
|
||||||
|
|
||||||
|
# Überblicksseite zum Ausdrucken oder als PDF speichern
|
||||||
|
@ui.page('/api/month/{username}/{year}-{month}')
|
||||||
|
def page_overview_month(username: str, year: int, month: int):
|
||||||
|
|
||||||
|
try:
|
||||||
|
current_user = user(username)
|
||||||
|
ui.page_title(f"Bericht für {current_user.fullname} für {calendar.month_name[month]} {year}")
|
||||||
|
ui.label(datetime.now().strftime('%d.%m.%Y')).classes('absolute top-5 right-5')
|
||||||
|
ui.space()
|
||||||
|
ui.markdown(f'#Bericht für {current_user.fullname} für {calendar.month_name[month]} {year}')
|
||||||
|
|
||||||
|
pad_x = 4
|
||||||
|
pad_y = 0
|
||||||
|
|
||||||
|
color_weekend = "gray-100"
|
||||||
|
color_holiday = "gray-100"
|
||||||
|
|
||||||
|
def overview_table():
|
||||||
|
# Timestamp in ein Array schreiben
|
||||||
|
timestamps = current_user.get_timestamps(year, month)
|
||||||
|
timestamps.sort()
|
||||||
|
|
||||||
|
# Abwesenheitsdaten in ein Dict schreiben
|
||||||
|
user_absent = current_user.get_absence(year, month)
|
||||||
|
|
||||||
|
# Dictionary für sortierte Timestamps
|
||||||
|
timestamps_dict = { }
|
||||||
|
|
||||||
|
# Dictionary mit zunächst leeren Tageinträgen befüllen
|
||||||
|
for day in range(1, monthrange(year, month)[1] + 1):
|
||||||
|
# Jeder Tag bekommt eine leere Liste
|
||||||
|
timestamps_dict[day] = [ ]
|
||||||
|
|
||||||
|
# Timestamps den Monatstagen zuordnen
|
||||||
|
for stamp in timestamps:
|
||||||
|
day_of_month_of_timestamp = datetime.fromtimestamp(int(stamp)).day
|
||||||
|
timestamps_dict[day_of_month_of_timestamp].append(int(stamp))
|
||||||
|
timestamps_dict[day_of_month_of_timestamp].append(int(stamp))
|
||||||
|
|
||||||
|
general_saldo = 0
|
||||||
|
|
||||||
|
with ui.grid(columns='auto auto 1fr 1fr 1fr').classes(f'gap-0 border px-0 py-0'):
|
||||||
|
ui.markdown("**Datum**").classes(f'border px-{pad_x} py-{pad_y}')
|
||||||
|
ui.markdown("**Buchungen**").classes(f'border px-{pad_x} py-{pad_y}')
|
||||||
|
ui.markdown("**Ist**").classes(f'border px-{pad_x} py-{pad_y}')
|
||||||
|
ui.markdown("**Soll**").classes(f'border px-{pad_x} py-{pad_y}')
|
||||||
|
ui.markdown("**Saldo**").classes(f'border px-{pad_x} py-{pad_y}')
|
||||||
|
|
||||||
|
# Gehe jeden einzelnen Tag des Dictionaries für die Timestamps durch
|
||||||
|
for day in list(timestamps_dict):
|
||||||
|
booking_text = ""
|
||||||
|
color_day = 'inherit'
|
||||||
|
if datetime(year, month, day).strftime('%w') in ["0", "6"]:
|
||||||
|
color_day = color_weekend
|
||||||
|
|
||||||
|
current_day_date = f"{datetime(year, month, day).strftime('%a')}, {day}.{month}.{year}"
|
||||||
|
day_text_element = ui.markdown(current_day_date).classes(f'border px-{pad_x} py-{pad_y} bg-{color_day}')
|
||||||
|
|
||||||
|
|
||||||
|
# Abwesenheitseinträge
|
||||||
|
booking_color = "inherit"
|
||||||
|
booking_text_color = "inherit"
|
||||||
|
try:
|
||||||
|
# Abwesenheitszeiten behandeln
|
||||||
|
for i in list(user_absent):
|
||||||
|
if int(i) == day:
|
||||||
|
booking_text += absence_entries[user_absent[i]]["name"] + "<br>"
|
||||||
|
booking_color = absence_entries[user_absent[i]]["color"]
|
||||||
|
booking_text_color = absence_entries[user_absent[i]]["text-color"]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Buchungen behandeln
|
||||||
|
for i in range(len(timestamps_dict[day])):
|
||||||
|
try:
|
||||||
|
temp_pair = [timestamps_dict[day][i], timestamps_dict[day][i + 1]]
|
||||||
|
booking_text = booking_text + str(datetime.fromtimestamp(temp_pair[0]).strftime('%H:%M')) + "-" + str(datetime.fromtimestamp(temp_pair[1]).strftime('%H:%M')) + "<br>"
|
||||||
|
|
||||||
|
except:
|
||||||
|
if len(timestamps_dict[day]) % 2 != 0:
|
||||||
|
booking_text += datetime.fromtimestamp(int(timestamps_dict[day][i])).strftime('%H:%M')
|
||||||
|
|
||||||
|
booking_text_element = ui.markdown(booking_text).classes(f'border px-{pad_x} py-{pad_y} bg-{booking_color} text-{booking_text_color}')
|
||||||
|
|
||||||
|
# Ist-Zeiten berechnen
|
||||||
|
timestamps_of_this_day = []
|
||||||
|
|
||||||
|
# Suche mir alle timestamps für diesen Tag
|
||||||
|
for i in timestamps:
|
||||||
|
actual_timestamp = 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
|
||||||
|
|
||||||
|
is_time = convert_seconds_to_hours(time_sum) + " h"
|
||||||
|
else:
|
||||||
|
is_time = "Kein"
|
||||||
|
|
||||||
|
ui.markdown(is_time).classes(f'border px-{pad_x} py-{pad_y} text-center')
|
||||||
|
# Sollzeit bestimmen
|
||||||
|
|
||||||
|
hours_to_work = int(current_user.get_day_workhours(year, month, day))
|
||||||
|
|
||||||
|
if hours_to_work < 0:
|
||||||
|
target_time = ""
|
||||||
|
else:
|
||||||
|
target_time = f"{convert_seconds_to_hours(int(hours_to_work) * 3600)} h"
|
||||||
|
if int(hours_to_work) == 0:
|
||||||
|
booking_text = "Kein Arbeitstag"
|
||||||
|
booking_text_element.set_content(booking_text)
|
||||||
|
|
||||||
|
ui.markdown(target_time).classes(f'border px-{pad_x} py-{pad_y} text-center')
|
||||||
|
|
||||||
|
# Saldo für den Tag berechnen
|
||||||
|
day_in_list = datetime(year, month, day)
|
||||||
|
if time.time() > day_in_list.timestamp():
|
||||||
|
|
||||||
|
time_duty = int(current_user.get_day_workhours(year, month, day)) * 3600
|
||||||
|
if time_duty < 0:
|
||||||
|
saldo = 0
|
||||||
|
total = ""
|
||||||
|
booking_text = "Kein Arbeitsverhältnis"
|
||||||
|
booking_text_element.set_content(booking_text)
|
||||||
|
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
|
||||||
|
total = f"{convert_seconds_to_hours(saldo)} h"
|
||||||
|
|
||||||
|
else:
|
||||||
|
total = "-"
|
||||||
|
if total == "-":
|
||||||
|
total_class = 'text-center'
|
||||||
|
else:
|
||||||
|
total_class = 'text-right'
|
||||||
|
ui.markdown(total).classes(total_class).classes(f'border px-{pad_x} py-{pad_y}')
|
||||||
|
|
||||||
|
# Überstundenzusammenfassung
|
||||||
|
ui.markdown("Überstunden aus Vormonat:").classes(f'col-span-4 text-right border px-{pad_x} py-{pad_y}')
|
||||||
|
last_months_overtime = current_user.get_last_months_overtime(year, month)
|
||||||
|
ui.markdown(f"{convert_seconds_to_hours(last_months_overtime)} h").classes(f'text-right border px-{pad_x} py-{pad_y}')
|
||||||
|
ui.markdown("Überstunden diesen Monat:").classes(f'col-span-4 text-right border px-{pad_x} py-{pad_y}')
|
||||||
|
ui.markdown(f"{convert_seconds_to_hours(general_saldo)} h").classes(f'text-right border px-{pad_x} py-{pad_y}')
|
||||||
|
ui.markdown("**Überstunden Gesamt:**").classes(f'col-span-4 text-right border px-{pad_x} py-{pad_y}')
|
||||||
|
global overtime_overall
|
||||||
|
overtime_overall = last_months_overtime + general_saldo
|
||||||
|
ui.markdown(f"**{convert_seconds_to_hours(overtime_overall)} h**").classes(f'text-right border px-{pad_x} py-{pad_y}')
|
||||||
|
|
||||||
|
overview_table()
|
||||||
|
|
||||||
|
def absence_table():
|
||||||
|
absences_this_month = current_user.get_absence(year, month)
|
||||||
|
absence_dict = { }
|
||||||
|
|
||||||
|
for abbr in list(absence_entries):
|
||||||
|
absence_dict[abbr] = 0
|
||||||
|
|
||||||
|
for key, value in absences_this_month.items():
|
||||||
|
if value in list(absence_dict):
|
||||||
|
absence_dict[value] += 1
|
||||||
|
|
||||||
|
total_absence_days = 0
|
||||||
|
for key, value in absence_dict.items():
|
||||||
|
total_absence_days += absence_dict[key]
|
||||||
|
|
||||||
|
if total_absence_days > 0:
|
||||||
|
ui.markdown("###Abwesenheitstage diesen Monat:")
|
||||||
|
|
||||||
|
with ui.grid(columns='auto 20%').classes(f'gap-0 border px-0 py-0'):
|
||||||
|
|
||||||
|
for key,value in absence_dict.items():
|
||||||
|
if value > 0:
|
||||||
|
ui.markdown(absence_entries[key]['name']).classes(f"border px-{pad_x} py-{pad_y}")
|
||||||
|
ui.markdown(str(value)).classes(f'border px-{pad_x} py-{pad_y} text-center')
|
||||||
|
|
||||||
|
absence_table()
|
||||||
|
|
||||||
|
def archive():
|
||||||
|
current_year = datetime.now().year
|
||||||
|
current_month = datetime.now().month
|
||||||
|
archivable = False
|
||||||
|
|
||||||
|
if current_year > year:
|
||||||
|
if current_user.get_archive_status(year, month) == False:
|
||||||
|
archivable = True
|
||||||
|
if current_year == year:
|
||||||
|
if current_month > month:
|
||||||
|
if current_user.get_archive_status(year, month) == False:
|
||||||
|
archivable = True
|
||||||
|
|
||||||
|
def archive_dialog():
|
||||||
|
def do_archiving():
|
||||||
|
global overtime_overall
|
||||||
|
current_user.archive_hours(year, month, overtime_overall)
|
||||||
|
dialog.close()
|
||||||
|
ui.navigate.to(f'/api/month/{username}/{year}-{month}')
|
||||||
|
|
||||||
|
with ui.dialog() as dialog, ui.card():
|
||||||
|
with ui.grid(columns='1fr 1fr'):
|
||||||
|
ui.markdown("Hiermit bestätigen Sie, dass die Zeitbuchungen im Montagsjournal korrekt sind.<br>Sollte dies nicht der Fall sein, wenden Sie sich für eine Korrektur an den Administrator.").classes('col-span-2')
|
||||||
|
ui.button("Archivieren", on_click=do_archiving)
|
||||||
|
ui.button("Abbrechen", on_click=dialog.close)
|
||||||
|
|
||||||
|
dialog.open()
|
||||||
|
|
||||||
|
if archivable == True:
|
||||||
|
ui.button("Archivieren", on_click=archive_dialog)
|
||||||
|
|
||||||
|
archive()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(str(type(e).__name__) + " " + str(e))
|
||||||
|
if type(e) == UnboundLocalError:
|
||||||
|
ui.markdown('#Fehler')
|
||||||
|
ui.markdown('Benutzer existiert nicht')
|
||||||
|
else:
|
||||||
|
ui.markdown('#Fehler')
|
||||||
|
ui.markdown(str(type(e)))
|
||||||
|
ui.markdown(str(e))
|
||||||
|
|
||||||
|
@ui.page('/api/vacation/{username}/{year}')
|
||||||
|
def page_overview_vacation(username: str, year: int):
|
||||||
|
|
||||||
|
if login_is_valid(username):
|
||||||
|
|
||||||
|
try:
|
||||||
|
current_user = user(username)
|
||||||
|
|
||||||
|
month = datetime.now().month
|
||||||
|
day = datetime.now().day
|
||||||
|
|
||||||
|
ui.page_title(f"Urlaubsanspruch für {current_user.fullname} für {year}")
|
||||||
|
ui.label(datetime.now().strftime('%d.%m.%Y')).classes('absolute top-5 right-5')
|
||||||
|
ui.space()
|
||||||
|
ui.markdown(f'#Urlaubsanspruch für {current_user.fullname} für {year}')
|
||||||
|
|
||||||
|
pad_x = 4
|
||||||
|
pad_y = 0
|
||||||
|
|
||||||
|
vacationclaim = int(current_user.get_vacation_claim(year, month, day))
|
||||||
|
if vacationclaim == -1:
|
||||||
|
ui.markdown(f"###Kein Urlaubsanspruch für {year}")
|
||||||
|
else:
|
||||||
|
|
||||||
|
with ui.grid(columns='auto auto').classes(f'gap-0 border px-0 py-0'):
|
||||||
|
ui.markdown(f"Urlaubsanspruch für {year}:").classes(f'border px-{pad_x} py-{pad_y}')
|
||||||
|
ui.markdown(f"{vacationclaim} Tage").classes(f'text-right border px-{pad_x} py-{pad_y}')
|
||||||
|
ui.markdown("Registrierte Urlaubstage").classes(f'border px-{pad_x} py-{pad_y} col-span-2')
|
||||||
|
vacation_counter = 0
|
||||||
|
try:
|
||||||
|
for i in range(1, 13):
|
||||||
|
absence_entries = current_user.get_absence(year, i)
|
||||||
|
for day, absence_type in absence_entries.items():
|
||||||
|
# print(day + "." + str(i) + " " + absence_type)
|
||||||
|
if absence_type == "U":
|
||||||
|
day_in_list = datetime(int(year), int(i), int(day)).strftime("%d.%m.%Y")
|
||||||
|
ui.markdown(day_in_list).classes(f'border px-{pad_x} py-{pad_y}')
|
||||||
|
ui.markdown("-1 Tag").classes(f'border px-{pad_x} py-{pad_y} text-center')
|
||||||
|
vacation_counter += 1
|
||||||
|
except Exception as e:
|
||||||
|
print(str(type(e).__name__) + " " + str(e))
|
||||||
|
ui.markdown("**Resturlaub:**").classes(f'border px-{pad_x} py-{pad_y}')
|
||||||
|
ui.markdown(f'**{str(vacationclaim - vacation_counter)} Tage**').classes(f'border px-{pad_x} py-{pad_y} text-center')
|
||||||
|
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(str(type(e).__name__) + " " + str(e))
|
||||||
|
if type(e) == UnboundLocalError:
|
||||||
|
ui.markdown('#Fehler')
|
||||||
|
ui.markdown('Benutzer existiert nicht')
|
||||||
|
else:
|
||||||
|
ui.markdown('#Fehler')
|
||||||
|
ui.markdown(str(type(e)))
|
||||||
|
ui.markdown(str(e))
|
||||||
|
else:
|
||||||
|
login = login_mask(target=f'/api/vacation/{username}/{year}')
|
||||||
|
|
||||||
|
@ui.page('/api/absence/{username}/{year}')
|
||||||
|
def page_overview_absence(username: str, year: int):
|
||||||
|
|
||||||
|
if login_is_valid(username):
|
||||||
|
current_user = user(username)
|
||||||
|
ui.page_title(f"Abwesenheitsübersicht für {current_user.fullname} für {year}")
|
||||||
|
ui.label(datetime.now().strftime('%d.%m.%Y')).classes('absolute top-5 right-5')
|
||||||
|
ui.space()
|
||||||
|
pageheader(f"Abwesenheitsübersicht für {current_user.fullname} für {year}")
|
||||||
|
|
||||||
|
pad_x = 2
|
||||||
|
pad_y = 0
|
||||||
|
|
||||||
|
def absence_calender():
|
||||||
|
|
||||||
|
column_constructor = 'auto '
|
||||||
|
for j in range(1, 31):
|
||||||
|
column_constructor += "1fr "
|
||||||
|
column_constructor += 'auto'
|
||||||
|
|
||||||
|
with ui.grid(columns=column_constructor).classes(f'gap-0 border px-0 py-0') as calendar_grid:
|
||||||
|
# Erste Zeile
|
||||||
|
ui.space()
|
||||||
|
for i in range(1, 32):
|
||||||
|
ui.markdown(str(i)).classes(f'border px-{pad_x} py-{pad_y} text-center')
|
||||||
|
# Monate durchgehen
|
||||||
|
for month in range(1, 13):
|
||||||
|
for column in range(0, 32):
|
||||||
|
if column == 0:
|
||||||
|
ui.markdown(month_name[month]).classes(f'border px-{pad_x} py-{pad_y} text.center')
|
||||||
|
else:
|
||||||
|
absences = current_user.get_absence(year, month)
|
||||||
|
if str(column) in list(absences):
|
||||||
|
bg_color = absence_entries[absences[str(column)]]['color']
|
||||||
|
text_color = absence_entries[absences[str(column)]]['text-color']
|
||||||
|
ui.markdown(absences[str(column)]).classes(f'border px-{pad_x} py-{pad_y} bg-{bg_color} text-{text_color} text-center')
|
||||||
|
else:
|
||||||
|
if column > monthrange(year, month)[1]:
|
||||||
|
bg_color = 'gray-500'
|
||||||
|
elif int(current_user.get_day_workhours(year, month, column)) == 0:
|
||||||
|
bg_color = 'gray-300'
|
||||||
|
elif int(current_user.get_day_workhours(year, month, column)) == -1:
|
||||||
|
bg_color = 'gray-400'
|
||||||
|
else:
|
||||||
|
bg_color = 'inherit'
|
||||||
|
ui.space().classes(f'border px-{pad_x} py-{pad_y} bg-{bg_color}')
|
||||||
|
|
||||||
|
absence_calender()
|
||||||
|
|
||||||
|
def absence_table():
|
||||||
|
|
||||||
|
with ui.grid(columns='auto auto').classes(f'gap-0 px-0 py-0'):
|
||||||
|
ui.markdown('**Summen**').classes('col-span-2 px-2')
|
||||||
|
for type in list(absence_entries):
|
||||||
|
number_of_days = 0
|
||||||
|
ui.markdown(absence_entries[type]["name"]).classes(f'border px-{pad_x} py-{pad_y}')
|
||||||
|
for month in range(1, 13):
|
||||||
|
absences_of_month = current_user.get_absence(year, month)
|
||||||
|
for i in list(absences_of_month):
|
||||||
|
if absences_of_month[i] == type:
|
||||||
|
number_of_days += 1
|
||||||
|
ui.markdown(str(number_of_days)).classes(f'border px-{pad_x} py-{pad_y} text-center')
|
||||||
|
absence_table()
|
||||||
|
|
||||||
|
else:
|
||||||
|
login = login_mask(target=f'/api/absence/{username}/{year}')
|
@ -23,14 +23,21 @@ status_out = "ausgestempelt"
|
|||||||
# Abesenheiten
|
# Abesenheiten
|
||||||
|
|
||||||
absence_entries = {"U": { "name": "Urlaub",
|
absence_entries = {"U": { "name": "Urlaub",
|
||||||
"color": "green"},
|
"color": "green",
|
||||||
|
"text-color": "black"},
|
||||||
"K": { "name": "Krankheit",
|
"K": { "name": "Krankheit",
|
||||||
"color": "red"},
|
"color": "red",
|
||||||
|
"text-color": "white"},
|
||||||
"KK": { "name": "Krankheit Kind",
|
"KK": { "name": "Krankheit Kind",
|
||||||
"color": "orange"},
|
"color": "orange",
|
||||||
|
"text-color": "black"},
|
||||||
"UU": { "name": "Urlaub aus Überstunden",
|
"UU": { "name": "Urlaub aus Überstunden",
|
||||||
"color": "green"},
|
"color": "green",
|
||||||
|
"text-color": "black"},
|
||||||
"F": { "name": "Fortbildung",
|
"F": { "name": "Fortbildung",
|
||||||
"color": "black"},
|
"color": "black",
|
||||||
|
"text-color": "white"},
|
||||||
"EZ": { "name": "Elternzeit",
|
"EZ": { "name": "Elternzeit",
|
||||||
"color": "purple"}}
|
"color": "purple",
|
||||||
|
"text-color": "white"}
|
||||||
|
}
|
||||||
|
126
homepage.py
Normal file
126
homepage.py
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
# Zeiterfassung
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from nicegui import ui, app
|
||||||
|
|
||||||
|
from users import *
|
||||||
|
from definitions import *
|
||||||
|
from calendar import monthrange, month_name
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import calendar
|
||||||
|
import locale
|
||||||
|
|
||||||
|
from web_ui import *
|
||||||
|
|
||||||
|
@ui.page('/')
|
||||||
|
def homepage():
|
||||||
|
if login_is_valid():
|
||||||
|
|
||||||
|
ui.page_title("Zeiterfassung")
|
||||||
|
current_user = user(app.storage.user["active_user"])
|
||||||
|
pageheader(f"Willkommen, {current_user.fullname}")
|
||||||
|
|
||||||
|
today = datetime.datetime.now()
|
||||||
|
|
||||||
|
@ui.refreshable
|
||||||
|
def stamp_interface():
|
||||||
|
|
||||||
|
time_so_far = current_user.get_worked_time(today.year, today.month, today.day)[0]
|
||||||
|
|
||||||
|
def stamp_and_refresh():
|
||||||
|
current_user.timestamp()
|
||||||
|
stamp_interface.refresh()
|
||||||
|
|
||||||
|
with ui.grid(columns='20% auto 20%').classes('w-full justify-center'):
|
||||||
|
ui.space()
|
||||||
|
with ui.grid(columns='1fr 1fr'):
|
||||||
|
if current_user.stamp_status() == status_in:
|
||||||
|
bg_color = 'green'
|
||||||
|
else:
|
||||||
|
bg_color = 'red'
|
||||||
|
working_hours = ui.markdown(convert_seconds_to_hours(time_so_far)).classes(f'col-span-2 rounded-3xl text-center text-white text-bold text-2xl border-4 border-gray-600 bg-{bg_color}')
|
||||||
|
in_button = ui.button("Einstempeln", on_click=stamp_and_refresh).classes('bg-green')
|
||||||
|
out_button = ui.button("Ausstempeln", on_click=stamp_and_refresh).classes('bg-red')
|
||||||
|
|
||||||
|
def update_timer():
|
||||||
|
time_in_total = time_so_far + int((datetime.datetime.now().timestamp() - current_user.get_worked_time(today.year, today.month, today.day)[1]))
|
||||||
|
print(time_in_total)
|
||||||
|
working_hours.set_content(convert_seconds_to_hours(time_in_total))
|
||||||
|
|
||||||
|
working_timer = ui.timer(1.0, update_timer)
|
||||||
|
working_timer.active = False
|
||||||
|
|
||||||
|
if current_user.stamp_status() == status_in:
|
||||||
|
in_button.set_enabled(False)
|
||||||
|
out_button.set_enabled(True)
|
||||||
|
working_timer.active = True
|
||||||
|
|
||||||
|
else:
|
||||||
|
in_button.set_enabled(True)
|
||||||
|
out_button.set_enabled(False)
|
||||||
|
working_timer.active = False
|
||||||
|
|
||||||
|
stamp_interface()
|
||||||
|
|
||||||
|
available_years = current_user.get_years()
|
||||||
|
|
||||||
|
|
||||||
|
available_months = [ ]
|
||||||
|
binder_month_button = ValueBinder()
|
||||||
|
binder_month_button.value = False
|
||||||
|
|
||||||
|
binder_available_years = ValueBinder()
|
||||||
|
|
||||||
|
binder_vacation = ValueBinder
|
||||||
|
binder_vacation.value = False
|
||||||
|
|
||||||
|
binder_absence = ValueBinder
|
||||||
|
binder_absence.value = False
|
||||||
|
|
||||||
|
def enable_month():
|
||||||
|
binder_month_button.value = True
|
||||||
|
|
||||||
|
def update_month():
|
||||||
|
month_dict = { }
|
||||||
|
for i in current_user.get_months(month_year_select.value):
|
||||||
|
month_dict[i] = month_name[i]
|
||||||
|
|
||||||
|
month_month_select.set_options(month_dict)
|
||||||
|
month_month_select.enable()
|
||||||
|
|
||||||
|
ui.separator()
|
||||||
|
|
||||||
|
with ui.grid(columns='1fr auto 1fr').classes('w-full justify-center'):
|
||||||
|
ui.space()
|
||||||
|
|
||||||
|
def activate_vacation():
|
||||||
|
binder_vacation.value = True
|
||||||
|
|
||||||
|
with ui.grid(columns='1fr 1fr'):
|
||||||
|
|
||||||
|
ui.markdown("**Monatsübersicht:**").classes('col-span-2')
|
||||||
|
|
||||||
|
month_year_select = ui.select(list(reversed(available_years)), label="Jahr", on_change=update_month).bind_value_to(binder_available_years, 'value')
|
||||||
|
month_month_select = ui.select(available_months, label="Monat", on_change=enable_month)
|
||||||
|
month_month_select.disable()
|
||||||
|
|
||||||
|
ui.space()
|
||||||
|
month_button = ui.button("Anzeigen", on_click=lambda: ui.navigate.to(f"/api/month/{current_user.username}/{month_year_select.value}-{month_month_select.value}", new_tab=True)).bind_enabled_from(binder_month_button, 'value')
|
||||||
|
ui.markdown("**Urlaubsanspruch**").classes('col-span-2')
|
||||||
|
vacation_select = ui.select(list(reversed(available_years)), on_change=activate_vacation)
|
||||||
|
vacation_button = ui.button("Anzeigen", on_click=lambda: ui.navigate.to(f"/api/vacation/{current_user.username}/{vacation_select.value}", new_tab=True)).bind_enabled_from(binder_vacation, 'value')
|
||||||
|
ui.markdown("**Fehlzeitenübersicht**").classes('col-span-2')
|
||||||
|
absences_select = ui.select(list(reversed(available_years)))
|
||||||
|
absences_button = ui.button("Anzeigen").bind_enabled_from(binder_absence, 'value')
|
||||||
|
ui.separator().classes('col-span-2')
|
||||||
|
|
||||||
|
def logout():
|
||||||
|
app.storage.user.pop("active_user", None)
|
||||||
|
ui.navigate.to("/")
|
||||||
|
|
||||||
|
ui.button("Logout", on_click=logout).classes('col-span-2')
|
||||||
|
ui.space()
|
||||||
|
|
||||||
|
else:
|
||||||
|
login_mask()
|
6
login.py
6
login.py
@ -21,9 +21,9 @@ def page_login():
|
|||||||
nonlocal data
|
nonlocal data
|
||||||
|
|
||||||
if username.value == data["admin_user"]:
|
if username.value == data["admin_user"]:
|
||||||
if password.value == data["admin_password"]:
|
print(f"Input Hash: {hash_password(password.value)} gespeichert: {data['admin_password']}")
|
||||||
active_login = cookie_hash(data["admin_user"], data["admin_password"])
|
if hash_password(password.value) == data["admin_password"]:
|
||||||
app.storage.user['secret'] = active_login
|
app.storage.user['authenticated'] = True
|
||||||
ui.navigate.to("/admin")
|
ui.navigate.to("/admin")
|
||||||
else:
|
else:
|
||||||
ui.notify("Login fehlgeschlagen")
|
ui.notify("Login fehlgeschlagen")
|
||||||
|
9
main.py
9
main.py
@ -6,10 +6,11 @@ from login import *
|
|||||||
from users import *
|
from users import *
|
||||||
from touchscreen import *
|
from touchscreen import *
|
||||||
from definitions import *
|
from definitions import *
|
||||||
|
from api import *
|
||||||
|
from homepage import *
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
# Einstellungen einlesen
|
# Einstellungen einlesen
|
||||||
@ -19,7 +20,9 @@ def main():
|
|||||||
port = int(data["port"])
|
port = int(data["port"])
|
||||||
secret = data["secret"]
|
secret = data["secret"]
|
||||||
|
|
||||||
ui.run(port=port, storage_secret=secret)
|
homepage()
|
||||||
|
|
||||||
|
ui.run(port=port, storage_secret=secret, language='de-DE')
|
||||||
|
|
||||||
if __name__ in ("__main__", "__mp_main__"):
|
if __name__ in ("__main__", "__mp_main__"):
|
||||||
main()
|
main()
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
from nicegui import ui
|
from nicegui import ui
|
||||||
|
|
||||||
ui.time().props('now-btn format24h')
|
test = ('Eintrag 1')
|
||||||
|
|
||||||
ui.run(port=9000)
|
ui.markdown(test)
|
||||||
|
ui.markdown('Nächstes Element')
|
||||||
|
|
||||||
|
ui.run(language="de-DE", port=9000)
|
@ -1,6 +1,12 @@
|
|||||||
{
|
{
|
||||||
"admin_user": "admin",
|
"admin_user": "admin",
|
||||||
"admin_password": "123456",
|
"admin_password": "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92",
|
||||||
"port": "8090",
|
"port": "8090",
|
||||||
"secret": "ftgzuhjikg,mt5jn46uzer8sfi9okrmtzjhndfierko5zltjhdgise"
|
"secret": "ftgzuhjikg,mt5jn46uzer8sfi9okrmtzjhndfierko5zltjhdgise",
|
||||||
|
"holidays": {
|
||||||
|
"2024-01-01": "Tag der Arbeit",
|
||||||
|
"2024-12-25": "1. Weihnachtsfeiertag",
|
||||||
|
"2025-01-01": "Neujahr",
|
||||||
|
"2025-05-01": "Tag der Arbeit"
|
||||||
|
}
|
||||||
}
|
}
|
113
users.py
113
users.py
@ -83,9 +83,14 @@ class user:
|
|||||||
with open(f"{self.get_stamp_file()}.txt", 'r') as file:
|
with open(f"{self.get_stamp_file()}.txt", 'r') as file:
|
||||||
# Zähle die Zeilen
|
# Zähle die Zeilen
|
||||||
lines = file.readlines()
|
lines = file.readlines()
|
||||||
file.close()
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print(f"Die Datei {filename} wurde nicht gefunden.")
|
print(f"Die Datei {self.get_stamp_file()} wurde nicht gefunden.")
|
||||||
|
print("Lege die Datei an.")
|
||||||
|
with open(f'{self.get_stamp_file()}.txt', 'w') as file:
|
||||||
|
file.write("")
|
||||||
|
with open(f"{self.get_stamp_file()}.txt", 'r') as file:
|
||||||
|
# Zähle die Zeilen
|
||||||
|
lines = file.readlines()
|
||||||
if len(lines)== 0:
|
if len(lines)== 0:
|
||||||
print(f"Keine Einträge")
|
print(f"Keine Einträge")
|
||||||
elif len(lines) % 2 == 0:
|
elif len(lines) % 2 == 0:
|
||||||
@ -156,7 +161,6 @@ class user:
|
|||||||
years.append(year)
|
years.append(year)
|
||||||
|
|
||||||
years.sort()
|
years.sort()
|
||||||
print(years)
|
|
||||||
return years
|
return years
|
||||||
|
|
||||||
def get_months(self, year):
|
def get_months(self, year):
|
||||||
@ -183,7 +187,7 @@ class user:
|
|||||||
elif int(year) < year_now:
|
elif int(year) < year_now:
|
||||||
for i in range(1, 13):
|
for i in range(1, 13):
|
||||||
available_months.append(i)
|
available_months.append(i)
|
||||||
print(available_months)
|
|
||||||
for file in os.listdir(self.userfolder):
|
for file in os.listdir(self.userfolder):
|
||||||
|
|
||||||
if re.match(r"\d{4}-\d{1,2}\.json", file):
|
if re.match(r"\d{4}-\d{1,2}\.json", file):
|
||||||
@ -208,8 +212,26 @@ class user:
|
|||||||
with open(f"{self.userfolder}/{year}-{month}.txt", "w") as file:
|
with open(f"{self.userfolder}/{year}-{month}.txt", "w") as file:
|
||||||
file.write(''.join(timestamps))
|
file.write(''.join(timestamps))
|
||||||
|
|
||||||
def archive_hours(self, year, month):
|
def get_archive_status(self, year, month):
|
||||||
pass
|
try:
|
||||||
|
with open(f"{self.userfolder}/{year}-{month}.json", 'r') as json_file:
|
||||||
|
data = json.load(json_file)
|
||||||
|
return (data["archived"])
|
||||||
|
except:
|
||||||
|
return(-1)
|
||||||
|
|
||||||
|
def archive_hours(self, year, month, overtime: int):
|
||||||
|
|
||||||
|
filename = f"{self.userfolder}/{year}-{month}.json"
|
||||||
|
with open(filename, 'r') as json_file:
|
||||||
|
data = json.load(json_file)
|
||||||
|
data["archived"] = 1
|
||||||
|
data["overtime"] = overtime
|
||||||
|
|
||||||
|
json_dict = json.dumps(data)
|
||||||
|
|
||||||
|
with open(filename, "w") as outputfile:
|
||||||
|
outputfile.write(json_dict)
|
||||||
|
|
||||||
def get_last_months_overtime(self, year, month):
|
def get_last_months_overtime(self, year, month):
|
||||||
try:
|
try:
|
||||||
@ -254,8 +276,6 @@ class user:
|
|||||||
except:
|
except:
|
||||||
json_data.update({ "absence": { str(int(day)): absence_type}})
|
json_data.update({ "absence": { str(int(day)): absence_type}})
|
||||||
json_dict = json.dumps(json_data, indent=4)
|
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:
|
with open(f"{self.userfolder}/{int(year)}-{int(month)}.json", "w") as json_file:
|
||||||
json_file.write(json_dict)
|
json_file.write(json_dict)
|
||||||
@ -275,25 +295,102 @@ class user:
|
|||||||
workhour_entries.sort()
|
workhour_entries.sort()
|
||||||
day_to_check = datetime.datetime(int(year), int(month), int(day))
|
day_to_check = datetime.datetime(int(year), int(month), int(day))
|
||||||
|
|
||||||
|
# Fertage prüfen
|
||||||
|
settings = load_adminsettings()
|
||||||
|
holidays = list(settings["holidays"])
|
||||||
|
|
||||||
|
today_dt = datetime.datetime(int(year), int(month), int(day))
|
||||||
|
check_date_list = [ ]
|
||||||
|
for i in holidays:
|
||||||
|
i_split = i.split("-")
|
||||||
|
check_year = int(i_split[0])
|
||||||
|
check_month = int(i_split[1])
|
||||||
|
check_day = int(i_split[2])
|
||||||
|
check_dt = datetime.datetime(check_year, check_month, check_day)
|
||||||
|
check_date_list.append(check_dt)
|
||||||
|
if today_dt in check_date_list:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# Wochenarbeitszeit durchsuchen
|
||||||
for entry in reversed(workhour_entries):
|
for entry in reversed(workhour_entries):
|
||||||
|
|
||||||
entry_split = entry.split("-")
|
entry_split = entry.split("-")
|
||||||
entry_dt = datetime.datetime(int(entry_split[0]), int(entry_split[1]), int(entry_split[2]))
|
entry_dt = datetime.datetime(int(entry_split[0]), int(entry_split[1]), int(entry_split[2]))
|
||||||
|
|
||||||
if entry_dt <= day_to_check:
|
if entry_dt <= day_to_check:
|
||||||
weekday = day_to_check.strftime("%w")
|
weekday = day_to_check.strftime("%w")
|
||||||
if int(weekday) == 0:
|
if int(weekday) == 0:
|
||||||
weekday = str(7)
|
weekday = str(7)
|
||||||
hours_to_work = self.workhours[entry][weekday]
|
hours_to_work = self.workhours[entry][weekday]
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
# Wenn vor Einstellungsdatum -1 ausgeben
|
# Wenn vor Einstellungsdatum -1 ausgeben
|
||||||
hours_to_work = -1
|
hours_to_work = -1
|
||||||
return hours_to_work
|
return hours_to_work
|
||||||
|
|
||||||
|
def get_vacation_claim(self, year, month, day):
|
||||||
|
workhour_entries = list(self.workhours)
|
||||||
|
workhour_entries.sort()
|
||||||
|
day_to_check = datetime.datetime(int(year), int(month), int(day))
|
||||||
|
|
||||||
|
claim = -1
|
||||||
|
|
||||||
|
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:
|
||||||
|
claim = self.workhours[entry]["vacation"]
|
||||||
|
break
|
||||||
|
|
||||||
|
return claim
|
||||||
|
|
||||||
def delete_photo(self):
|
def delete_photo(self):
|
||||||
os.remove(self.photofile)
|
os.remove(self.photofile)
|
||||||
|
|
||||||
|
def get_worked_time(self, year, month, day):
|
||||||
|
timestamps = self.get_timestamps(year, month)
|
||||||
|
check_day_dt = datetime.datetime(year, month, day)
|
||||||
|
todays_timestamps = [ ]
|
||||||
|
|
||||||
|
for i in timestamps:
|
||||||
|
i_dt = datetime.datetime.fromtimestamp(int(i))
|
||||||
|
if i_dt.date() == check_day_dt.date():
|
||||||
|
todays_timestamps.append(int(i))
|
||||||
|
|
||||||
|
todays_timestamps.sort()
|
||||||
|
if len(todays_timestamps) % 2 == 0:
|
||||||
|
workrange = len(todays_timestamps)
|
||||||
|
in_time_stamp = -1
|
||||||
|
else:
|
||||||
|
workrange = len(todays_timestamps) - 1
|
||||||
|
in_time_stamp = int(todays_timestamps[-1])
|
||||||
|
total_time = 0
|
||||||
|
|
||||||
|
for i in range(0, workrange, 2):
|
||||||
|
time_worked = todays_timestamps[i + 1] - todays_timestamps[i]
|
||||||
|
total_time += time_worked
|
||||||
|
|
||||||
|
print(total_time)
|
||||||
|
print(in_time_stamp)
|
||||||
|
|
||||||
|
return([total_time, in_time_stamp])
|
||||||
|
|
||||||
# Benutzer auflisten
|
# Benutzer auflisten
|
||||||
def list_users():
|
def list_users():
|
||||||
users = [d for d in os.listdir(userfolder) if os.path.isdir(os.path.join(userfolder, d))]
|
users = [d for d in os.listdir(userfolder) if os.path.isdir(os.path.join(userfolder, d))]
|
||||||
users.sort()
|
users.sort()
|
||||||
return users
|
return users
|
||||||
|
|
||||||
|
# Admineinstellungen auslesen
|
||||||
|
def load_adminsettings():
|
||||||
|
# Settingsdatei einlesen
|
||||||
|
try:
|
||||||
|
with open(f"{scriptpath}/{usersettingsfilename}") as json_file:
|
||||||
|
data = json.load(json_file)
|
||||||
|
json_file.close()
|
||||||
|
return(data)
|
||||||
|
except:
|
||||||
|
return(-1)
|
||||||
|
|
||||||
|
@ -7,29 +7,21 @@
|
|||||||
"3": "EZ",
|
"3": "EZ",
|
||||||
"4": "EZ",
|
"4": "EZ",
|
||||||
"5": "EZ",
|
"5": "EZ",
|
||||||
"6": "EZ",
|
|
||||||
"7": "EZ",
|
|
||||||
"8": "EZ",
|
"8": "EZ",
|
||||||
"9": "EZ",
|
"9": "EZ",
|
||||||
"10": "EZ",
|
"10": "EZ",
|
||||||
"11": "EZ",
|
"11": "EZ",
|
||||||
"12": "EZ",
|
"12": "EZ",
|
||||||
"13": "EZ",
|
|
||||||
"14": "EZ",
|
|
||||||
"15": "EZ",
|
"15": "EZ",
|
||||||
"16": "EZ",
|
"16": "EZ",
|
||||||
"17": "EZ",
|
"17": "EZ",
|
||||||
"18": "EZ",
|
"18": "EZ",
|
||||||
"19": "EZ",
|
"19": "EZ",
|
||||||
"20": "EZ",
|
|
||||||
"21": "EZ",
|
|
||||||
"22": "EZ",
|
"22": "EZ",
|
||||||
"23": "EZ",
|
"23": "EZ",
|
||||||
"24": "EZ",
|
"24": "EZ",
|
||||||
"25": "EZ",
|
"25": "EZ",
|
||||||
"26": "EZ",
|
"26": "EZ",
|
||||||
"27": "EZ",
|
|
||||||
"28": "EZ",
|
|
||||||
"29": "EZ",
|
"29": "EZ",
|
||||||
"30": "EZ",
|
"30": "EZ",
|
||||||
"31": "EZ"
|
"31": "EZ"
|
||||||
|
@ -1,4 +1 @@
|
|||||||
{
|
{"archived": 1, "overtime": -528928}
|
||||||
"archived": 1,
|
|
||||||
"overtime": 3950
|
|
||||||
}
|
|
@ -3,8 +3,10 @@
|
|||||||
"overtime": 0,
|
"overtime": 0,
|
||||||
"absence": {
|
"absence": {
|
||||||
"7": "U",
|
"7": "U",
|
||||||
"8": "U",
|
"8": "K",
|
||||||
"9": "U",
|
"9": "KK",
|
||||||
"10": "U"
|
"10": "UU",
|
||||||
|
"11": "F",
|
||||||
|
"14": "EZ"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -20,3 +20,15 @@
|
|||||||
1745390894
|
1745390894
|
||||||
1745390894
|
1745390894
|
||||||
1745391029
|
1745391029
|
||||||
|
1746006467
|
||||||
|
1746006593
|
||||||
|
1746006933
|
||||||
|
1746006937
|
||||||
|
1746007004
|
||||||
|
1746007012
|
||||||
|
1746007119
|
||||||
|
1746007383
|
||||||
|
1746010855
|
||||||
|
1746010861
|
||||||
|
1746011089
|
||||||
|
1746011092
|
||||||
|
0
users/testuser1/2025-5.txt
Normal file
0
users/testuser1/2025-5.txt
Normal file
@ -1,27 +1,17 @@
|
|||||||
{
|
{
|
||||||
"username": "testuser1",
|
"username": "testuser1",
|
||||||
"fullname": "Pia Paulina",
|
"fullname": "Pia Paulina",
|
||||||
"password": "123456789",
|
"password": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
|
||||||
"workhours": {
|
"workhours": {
|
||||||
"2025-04-03": {
|
"2025-05-13": {
|
||||||
"1": "4",
|
"1": "4",
|
||||||
"2": "8",
|
"2": "5",
|
||||||
"3": "8",
|
"3": "6",
|
||||||
"4": "8",
|
"4": "7",
|
||||||
"5": "8",
|
"5": "8",
|
||||||
"6": "0",
|
"6": "0",
|
||||||
"7": "0",
|
"7": "0",
|
||||||
"vacation": "35"
|
"vacation": "30"
|
||||||
},
|
|
||||||
"2025-05-13": {
|
|
||||||
"1": "0",
|
|
||||||
"2": "0",
|
|
||||||
"3": "0",
|
|
||||||
"4": "0",
|
|
||||||
"5": "0",
|
|
||||||
"6": "0",
|
|
||||||
"7": "0",
|
|
||||||
"vacation": "0"
|
|
||||||
},
|
},
|
||||||
"2025-04-22": {
|
"2025-04-22": {
|
||||||
"1": "1",
|
"1": "1",
|
||||||
@ -31,7 +21,17 @@
|
|||||||
"5": "5",
|
"5": "5",
|
||||||
"6": "6",
|
"6": "6",
|
||||||
"7": "7",
|
"7": "7",
|
||||||
"vacation": "0"
|
"vacation": "30"
|
||||||
|
},
|
||||||
|
"2025-03-01": {
|
||||||
|
"1": "4",
|
||||||
|
"2": "8",
|
||||||
|
"3": "8",
|
||||||
|
"4": "8",
|
||||||
|
"5": "8",
|
||||||
|
"6": 0,
|
||||||
|
"7": 0,
|
||||||
|
"vacation": "30"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
84
web_ui.py
84
web_ui.py
@ -26,15 +26,52 @@ class ValueBinder:
|
|||||||
def cookie_hash(user, password):
|
def cookie_hash(user, password):
|
||||||
return hashlib.sha256(b"{user}{app.storage.user['id']}{password}").hexdigest()
|
return hashlib.sha256(b"{user}{app.storage.user['id']}{password}").hexdigest()
|
||||||
|
|
||||||
def load_adminsettings():
|
def hash_password(password):
|
||||||
# Settingsdatei einlesen
|
return hashlib.sha256(bytes(password, 'utf-8')).hexdigest()
|
||||||
try:
|
|
||||||
with open(f"{scriptpath}/{usersettingsfilename}") as json_file:
|
class login_mask:
|
||||||
data = json.load(json_file)
|
def __init__(self, target="/"):
|
||||||
json_file.close()
|
data = load_adminsettings()
|
||||||
return(data)
|
self.target = target
|
||||||
except:
|
|
||||||
return(-1)
|
def login():
|
||||||
|
nonlocal data
|
||||||
|
|
||||||
|
if username.value == data["admin_user"]:
|
||||||
|
if hash_password(password.value) == data["admin_password"]:
|
||||||
|
app.storage.user['admin_authenticated'] = True
|
||||||
|
ui.navigate.to("/admin")
|
||||||
|
else:
|
||||||
|
ui.notify("Login fehlgeschlagen")
|
||||||
|
else:
|
||||||
|
userlist = list_users()
|
||||||
|
|
||||||
|
if username.value in userlist:
|
||||||
|
current_user = user(username.value)
|
||||||
|
|
||||||
|
if hash_password(password.value) == current_user.password:
|
||||||
|
app.storage.user['active_user'] = current_user.username
|
||||||
|
ui.navigate.to(self.target)
|
||||||
|
else:
|
||||||
|
ui.notify("Login fehlgeschlagen")
|
||||||
|
else:
|
||||||
|
ui.notify("Login fehlgeschlagen")
|
||||||
|
|
||||||
|
# ui.markdown(f"## {app_title} {app_version}")
|
||||||
|
# ui.markdown("Bitte einloggen")
|
||||||
|
|
||||||
|
pageheader("Bitte einloggen:")
|
||||||
|
|
||||||
|
with ui.grid(columns='20% auto 20%').classes('w-full justify-center'):
|
||||||
|
|
||||||
|
ui.space()
|
||||||
|
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.space()
|
||||||
|
|
||||||
def convert_seconds_to_hours(seconds):
|
def convert_seconds_to_hours(seconds):
|
||||||
if seconds < 0:
|
if seconds < 0:
|
||||||
@ -62,19 +99,20 @@ def convert_seconds_to_hours(seconds):
|
|||||||
else:
|
else:
|
||||||
return(f"{hours}:{minutes}")
|
return(f"{hours}:{minutes}")
|
||||||
|
|
||||||
@ui.page('/userlist')
|
def login_is_valid(user = -1):
|
||||||
def page_userlist():
|
|
||||||
|
|
||||||
def click_button(button):
|
|
||||||
ui.notify(button)
|
|
||||||
|
|
||||||
ui.markdown(f"#{app_title} {app_version}")
|
|
||||||
|
|
||||||
userlist = list_users()
|
|
||||||
buttons = { }
|
|
||||||
|
|
||||||
for name in userlist:
|
|
||||||
button = ui.button(text=name, on_click=lambda name=name:click_button(name) )
|
|
||||||
buttons[name] = button
|
|
||||||
|
|
||||||
|
if user == -1:
|
||||||
|
try:
|
||||||
|
app.storage.user['active_user']
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
if app.storage.user['active_user'] == user:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user