Merge branch 'api-stamping' into web_ui

This commit is contained in:
Alexander Malzkuhn 2025-05-07 11:50:49 +02:00
commit d740b8e2b6
9 changed files with 74 additions and 10 deletions

View File

@ -280,7 +280,7 @@ def page_admin():
ui.button("Abbrechen", on_click=edit_dialog.close) ui.button("Abbrechen", on_click=edit_dialog.close)
edit_dialog.open() edit_dialog.open()
for i in range(len(timestamps_dict[day])): for i in range(0, len(timestamps_dict[day]), 2):
try: try:
temp_pair = [ timestamps_dict[day][i] , timestamps_dict[day][i+1] ] temp_pair = [ timestamps_dict[day][i] , timestamps_dict[day][i+1] ]
with ui.card().classes('bg-inherit'): with ui.card().classes('bg-inherit'):
@ -289,7 +289,7 @@ def page_admin():
timestamp_button = ui.button(datetime.datetime.fromtimestamp(int(j)).strftime('%H:%M'), on_click=lambda t_stamp=j, day=day: edit_entry(t_stamp, day)) timestamp_button = ui.button(datetime.datetime.fromtimestamp(int(j)).strftime('%H:%M'), on_click=lambda t_stamp=j, day=day: edit_entry(t_stamp, day))
if archive_status: if archive_status:
timestamp_button.disable() timestamp_button.disable()
except: except Exception as e:
if len(timestamps_dict[day]) % 2 != 0: if len(timestamps_dict[day]) % 2 != 0:
with ui.card().classes('bg-inherit'): with ui.card().classes('bg-inherit'):
timestamp_button = ui.button(datetime.datetime.fromtimestamp(int(timestamps_dict[day][i])).strftime('%H:%M'), on_click=lambda t_stamp=timestamps_dict[day][i], day=day: edit_entry(t_stamp, day)) timestamp_button = ui.button(datetime.datetime.fromtimestamp(int(timestamps_dict[day][i])).strftime('%H:%M'), on_click=lambda t_stamp=timestamps_dict[day][i], day=day: edit_entry(t_stamp, day))
@ -754,6 +754,14 @@ def page_admin():
#password_input.value = current_user.password #password_input.value = current_user.password
usersettingscard.visible = True usersettingscard.visible = True
api_key_input.value = current_user.api_key
api_link_column.clear()
for i in app.urls:
link = ui.link(f'{i}/api/stamp/"API-Schlüssel"', f'{i}/api/stamp/{api_key_input.value}')
link.tooltip("ACHTUNG: Klick auf den Link löst Stempelaktion aus!")
link.move(api_link_column)
workhours_select.clear() workhours_select.clear()
workhour_list = list(current_user.workhours) workhour_list = list(current_user.workhours)
workhour_list.sort() workhour_list.sort()
@ -792,6 +800,7 @@ def page_admin():
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 = hash_password(password_input.value) current_user.password = hash_password(password_input.value)
current_user.api_key = api_key_input.value
current_user.write_settings() current_user.write_settings()
password_input.value = "" password_input.value = ""
userlist = list_users() userlist = list_users()
@ -920,7 +929,7 @@ def page_admin():
with ui.column(): with ui.column():
with ui.card() as usersettingscard: with ui.card() as usersettingscard:
ui.markdown("**Benutzereinstellungen**") ui.markdown("**Benutzereinstellungen**")
with ui.grid(columns=2): with ui.grid(columns="auto 1fr") as usersettingsgrid:
ui.markdown("Benutzername:") ui.markdown("Benutzername:")
username_input = ui.input() username_input = ui.input()
@ -929,9 +938,20 @@ def page_admin():
ui.markdown("Passwort") ui.markdown("Passwort")
password_input = ui.input(password=True) password_input = ui.input(password=True)
password_input.value = "" password_input.value = ""
ui.markdown("API-Schlüssel:")
with ui.row():
api_key_input = ui.input().props('size=37')
def new_api_key():
api_key_input.value = hashlib.shake_256(bytes(f'{username_input.value}_{datetime.datetime.now().timestamp()}', 'utf-8')).hexdigest(20)
ui.button("Neu", on_click=new_api_key)
ui.markdown('Aufruf zum Stempeln:')
with ui.column().classes('gap-0') as api_link_column:
stamp_link = [ ]
for i in app.urls:
stamp_link.append(ui.link(f'{i}/api/stamp/"API-Schüssel"'))
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).tooltip("Klicken Sie hier um die Änderungen zu speichern.")
ui.button("Löschen", on_click=del_user) ui.button("Löschen", on_click=del_user)
with ui.card() as photocard: with ui.card() as photocard:

31
api.py
View File

@ -97,7 +97,7 @@ def page_overview_month(username: str, year: int, month: int):
pass pass
# Buchungen behandeln # Buchungen behandeln
for i in range(len(timestamps_dict[day])): for i in range(0, len(timestamps_dict[day]), 2):
try: try:
temp_pair = [timestamps_dict[day][i], timestamps_dict[day][i + 1]] temp_pair = [timestamps_dict[day][i], timestamps_dict[day][i + 1]]
booking_text = booking_text + str(datetime.fromtimestamp(temp_pair[0]).strftime('%H:%M')) + "-" + str(datetime.fromtimestamp(temp_pair[1]).strftime('%H:%M')) + "<br>" booking_text = booking_text + str(datetime.fromtimestamp(temp_pair[0]).strftime('%H:%M')) + "-" + str(datetime.fromtimestamp(temp_pair[1]).strftime('%H:%M')) + "<br>"
@ -395,3 +395,32 @@ def page_overview_absence(username: str, year: int):
else: else:
login = login_mask(target=f'/api/absence/{username}/{year}') login = login_mask(target=f'/api/absence/{username}/{year}')
@ui.page('/api/stamp/{api_key}')
def page_api_stamp(api_key: str):
userlist = list_users()
user_dict = { }
# Dictionary mit Usernamen befüllen
for i in userlist:
user_dict[i] = ""
for entry in list(user_dict):
try:
temp_user = user(entry)
user_dict[entry] = temp_user.api_key
except:
pass
found_key = False
ui.page_title(f'{app_title} {app_version}')
for user_key, api_value in user_dict.items():
if api_key == api_value:
current_user = user(user_key)
current_user.timestamp()
found_key = True
ui.label(f'Zeitstempel {datetime.now().strftime("%H:%M")} für {current_user.fullname} eingetragen')
break
if found_key == False:
ui.label("Keinen passenden Benutzer gefunden")

View File

@ -35,6 +35,7 @@ standard_usersettings = {
"username": "default", "username": "default",
"fullname": "Standardbenutzer", "fullname": "Standardbenutzer",
"password": "37a8eec1ce19687d132fe29051dca629d164e2c4958ba141d5f4133a33f0688f", "password": "37a8eec1ce19687d132fe29051dca629d164e2c4958ba141d5f4133a33f0688f",
"api_key": "1234567890",
"workhours": { } "workhours": { }
} }

View File

@ -15,9 +15,9 @@ from web_ui import *
@ui.page('/') @ui.page('/')
def homepage(): def homepage():
ui.page_title(f'{app_title} {app_version}')
if login_is_valid(): if login_is_valid():
ui.page_title("Zeiterfassung")
try: try:
current_user = user(app.storage.user["active_user"]) current_user = user(app.storage.user["active_user"])
except: except:
@ -49,7 +49,6 @@ def homepage():
def update_timer(): 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])) 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_hours.set_content(convert_seconds_to_hours(time_in_total))
working_timer = ui.timer(1.0, update_timer) working_timer = ui.timer(1.0, update_timer)

View File

@ -1,5 +1,5 @@
# Zeiterfassung # Zeiterfassung
import hashlib
# User bezogene Funktionen # User bezogene Funktionen
import os import os
@ -32,6 +32,7 @@ class user:
self.workhours = data["workhours"] self.workhours = data["workhours"]
self.username = data["username"] self.username = data["username"]
self.fullname = data["fullname"] self.fullname = data["fullname"]
self.api_key = data["api_key"]
def get_stamp_file(self, time_stamp=None): def get_stamp_file(self, time_stamp=None):
if time_stamp == None: if time_stamp == None:
@ -121,6 +122,7 @@ class user:
dict["fullname"] = self.fullname dict["fullname"] = self.fullname
dict["password"] = self.password dict["password"] = self.password
dict["workhours"] = self.workhours dict["workhours"] = self.workhours
dict["api_key"] = self.api_key
json_dict = json.dumps(dict, indent=4) json_dict = json.dumps(dict, indent=4)
@ -405,6 +407,10 @@ def new_user(username: str):
settings_to_write["workhours"][start_date] = { } settings_to_write["workhours"][start_date] = { }
settings_to_write["fullname"] = username settings_to_write["fullname"] = username
settings_to_write["username"] = username settings_to_write["username"] = username
# API-Key erzeugen
string_to_hash = f'{username}_{datetime.datetime.now().timestamp()}'
hash_string = hashlib.shake_256(bytes(string_to_hash, 'utf-8')).hexdigest(20)
settings_to_write["api_key"] = hash_string
for i in range(1, 8): for i in range(1, 8):
settings_to_write["workhours"][start_date][str(i)] = 0 settings_to_write["workhours"][start_date][str(i)] = 0
settings_to_write["workhours"][start_date]["vacation"] = 0 settings_to_write["workhours"][start_date]["vacation"] = 0

View File

@ -1,2 +1,8 @@
1746385124 1746385124
1746388680 1746388680
1746607385
1746607536
1746607833
1746608922
1746609024
1746609037

View File

@ -33,5 +33,6 @@
"7": 0, "7": 0,
"vacation": "30" "vacation": "30"
} }
} },
"api_key": "de4403f629a30450b2df1aa619a1c06112035499"
} }

View File

@ -2,6 +2,7 @@
"username": "testuser10", "username": "testuser10",
"fullname": "Diego Dieci", "fullname": "Diego Dieci",
"password": "123456789", "password": "123456789",
"api_key": "807518cd5bd85c1e4855d340f9b77b23eac21b7f",
"workhours": { "workhours": {
"2024-04-01": { "2024-04-01": {
"1": "1", "1": "1",

View File

@ -2,6 +2,7 @@
"username": "testuser3", "username": "testuser3",
"fullname": "Karl Klammer", "fullname": "Karl Klammer",
"password": "123456789", "password": "123456789",
"api_key": "0219f98ec471ea4e2ac6bd6c14b96051aae5209b",
"workhours": { "workhours": {
"2024-04-01": { "2024-04-01": {
"1": "4", "1": "4",