diff --git a/.gitignore b/.gitignore
index 187bb2d..000c5cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,8 @@ Testplan.md
.venv
users/
backup/
+settings/
Archiv/
Docker/
-docker-work/
\ No newline at end of file
+docker-work/
+Wiki/
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index ff4197a..d892ad0 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,14 +1,13 @@
-FROM debian:latest
+FROM python:latest
RUN apt update && apt upgrade -y
-RUN apt install python3 python3-pip python3.11-venv locales -y
+RUN apt install locales -y
RUN mkdir /app
RUN mkdir /.venv
RUN mkdir /backup
RUN mkdir /settings
-RUN python3 -m venv /.venv
-RUN /.venv/bin/pip install nicegui
-RUN /.venv/bin/pip install segno
-RUN /.venv/bin/pip install python-dateutil
+RUN pip install nicegui
+RUN pip install segno
+RUN pip install python-dateutil
RUN sed -i '/de_DE.UTF-8/s/^# //g' /etc/locale.gen && \
locale-gen
@@ -19,4 +18,4 @@ ENV LC_ALL de_DE.UTF-8
COPY main.py /app/main.py
COPY lib /app/lib/
EXPOSE 8090
-ENTRYPOINT ["/.venv/bin/python", "/app/main.py"]
+ENTRYPOINT ["python", "/app/main.py"]
diff --git a/create_docker.py b/create_docker.py
index e7e6170..d3266a9 100644
--- a/create_docker.py
+++ b/create_docker.py
@@ -5,13 +5,13 @@ import os
server = 'gitea.am-td.de'
server_user = 'alexander'
-if os.getuid() == 0:
- subprocess.run(["docker", "build", "--force-rm", "-t", f"{server}/{server_user}/{app_title.lower()}:{app_version}", "."])
- if input("docker-compose erstellen j=JA ") == "j":
- userfolder = input("Pfad für Benutzerdaten /users:")
- backupfolder = input("Pfad für Backupdaten /backup:")
- settingsfolder = input("Pfad für Einstellungen /settings:")
- docker_compose_content = f'''
+#if os.getuid() == 0:
+subprocess.run(["docker", "build", "--force-rm", "-t", f"{server}/{server_user}/{app_title.lower()}:{app_version}", "."])
+if input("docker-compose erstellen j=JA ") == "j":
+ userfolder = input("Pfad für Benutzerdaten /users:")
+ backupfolder = input("Pfad für Backupdaten /backup:")
+ settingsfolder = input("Pfad für Einstellungen /settings:")
+ docker_compose_content = f'''
services:
zeiterfassung:
image: {server}/{server_user}/{app_title.lower()}:{app_version.lower()}
@@ -25,7 +25,7 @@ services:
- {backupfolder}:/backup
- {settingsfolder}:/settings'''
- with open('docker-compose.yml', 'w') as docker_compose:
- docker_compose.write(docker_compose_content)
-else:
- print("Es werden Root-Rechte benötigt.")
+ with open('docker-compose.yml', 'w') as docker_compose:
+ docker_compose.write(docker_compose_content)
+#else:
+# print("Es werden Root-Rechte benötigt.")
diff --git a/docker-compose.yml b/docker-compose.yml
index 589fadc..dc3a301 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,13 +1,14 @@
services:
zeiterfassung:
- image: gitea.am-td.de/alexander/zeiterfassung:beta-2025.0.1
+ image: gitea.am-td.de/alexander/zeiterfassung:beta-2025.0.2
restart: always
ports:
- 8090:8090
environment:
- PYTHONUNBUFFERED=1
volumes:
- - ./docker-work/users:/users
- - ./docker-work/backup:/backup
- - ./docker-work/settings:/settings
\ No newline at end of file
+ - ./users:/users
+ - ./backup:/backup
+ - ./settings:/settings
+ - /etc/localtime:/etc/localtime:ro
diff --git a/lib/admin.py b/lib/admin.py
index bd27e74..4804882 100644
--- a/lib/admin.py
+++ b/lib/admin.py
@@ -4,6 +4,7 @@ import dateutil.easter
from dateutil.easter import *
from nicegui import ui, app, events
+from nicegui.functions.navigate import navigate
from nicegui.html import button
from nicegui.events import KeyEventArguments
@@ -44,6 +45,10 @@ def page_admin():
updates_available = ValueBinder()
updates_available.value = False
+ delete_binder = ValueBinder()
+ delete_binder.value = True
+ delete_info = ValueBinder()
+ delete_info.value = False
enabled_because_not_docker = ValueBinder
if is_docker():
@@ -65,6 +70,13 @@ def page_admin():
def update_userlist():
nonlocal userlist
userlist = list_users()
+ # Benutzerliste um No Time Users bereinigen
+ users_to_remove = [ ]
+ for entry in userlist:
+ if entry in get_no_time_users_list():
+ users_to_remove.append(entry)
+ for i in users_to_remove:
+ userlist.remove(i)
update_userlist()
@@ -759,17 +771,27 @@ def page_admin():
with ui.tab_panel(settings):
with ui.grid(columns='auto auto'):
with ui.card():
- ui.label("Administrationsbenutzer:").classes('text-bold')
- with ui.grid(columns=2).classes('items-baseline'):
-
- ui.label("Benutzername des Adminstrators:")
- admin_user = ui.input().tooltip("Geben Sie hier den Benutzernamen für den Adminstationsnutzer ein")
- admin_user.value = data["admin_user"]
- ui.label("Passwort des Administrators:")
- admin_password = ui.input(password=True).tooltip("Geben Sie hier das Passwort für den Administationsnutzer ein. Merken Sie sich dieses Passwort gut. Es kann nicht über das Webinterface zurückgesetzt werden.")
+ ui.label("Benutzereinstellungen:").classes('text-bold')
+ with ui.grid(columns=2).classes('items-center'):
+ ui.label("Benutzer mit Administrationsrechten:")
+ user_switch_list = []
+ with ui.grid(columns=2).classes('gap-y-0'):
+ for i in list_users():
+ user_switch_list.append(ui.switch(i))
+ for i in user_switch_list:
+ if i.text in get_admin_list():
+ i.value = True
secret = data["secret"]
-
+ ui.separator().classes('col-span-2')
+ ui.label("Benutzer ohne Zeiterfassung:")
+ no_time_user_switch_list = [ ]
+ with ui.grid(columns=2).classes('gap-y-0'):
+ for i in list_users():
+ no_time_user_switch_list.append(ui.switch(i))
+ for item in no_time_user_switch_list:
+ if item.text in get_no_time_users_list():
+ item.value = True
with ui.card():
ui.label("Systemeinstellungen:").classes('text-bold')
with ui.grid(columns=2).classes('items-baseline'):
@@ -1045,31 +1067,56 @@ def page_admin():
holiday_section()
def save_admin_settings():
- write_adminsetting("admin_user", admin_user.value)
- if admin_password.value != "":
- write_adminsetting("admin_password", hash_password(admin_password.value))
- else:
- write_adminsetting("admin_password", data["admin_password"])
- write_adminsetting("port", port.value)
- write_adminsetting("secret", secret)
- write_adminsetting("touchscreen", touchscreen_switch.value)
- write_adminsetting("times_on_touchscreen", timestamp_switch.value)
- write_adminsetting("photos_on_touchscreen", photo_switch.value)
- write_adminsetting("picture_height", picture_height_input.value)
- write_adminsetting("button_height", button_height_input.value)
- write_adminsetting("user_notes", notes_switch.value)
- write_adminsetting("holidays", data["holidays"])
- write_adminsetting("vacation_application", va_switch.value)
-
- if int(old_port) != int(port.value):
+ admin_users = { }
+ admin_counter = -1
+ for i in user_switch_list:
+ if i.value == True:
+ admin_counter += 1
+ admin_users[str(admin_counter)] = i.text
+ if len(admin_users) == 0:
with ui.dialog() as dialog, ui.card():
- ui.label(
- "Damit die Porteinstellungen wirksam werden, muss der Server neu gestartet werden.")
- ui.button("OK", on_click=lambda: dialog.close())
+ ui.label("Es wurde kein Administrationsbenutzer ausgewählt. Mindestens ein Benutzer muss Administrationsrechte haben.")
+ ui.button("OK", on_click=dialog.close)
dialog.open()
- ui.notify("Einstellungen gespeichert")
- reset_visibility.value = False
- timetable.refresh()
+ else:
+
+ no_time_users = { }
+ no_time_users_counter = -1
+ for i in no_time_user_switch_list:
+ if i.value == True:
+ no_time_users_counter += 1
+ no_time_users[str(no_time_users_counter)] = i.text
+
+ old_no_time_users_list = get_no_time_users_list()
+
+ write_adminsetting("admin_user", admin_users)
+ write_adminsetting("no_time_users", no_time_users)
+ write_adminsetting("port", port.value)
+ write_adminsetting("secret", secret)
+ write_adminsetting("touchscreen", touchscreen_switch.value)
+ write_adminsetting("times_on_touchscreen", timestamp_switch.value)
+ write_adminsetting("photos_on_touchscreen", photo_switch.value)
+ write_adminsetting("picture_height", picture_height_input.value)
+ write_adminsetting("button_height", button_height_input.value)
+ write_adminsetting("user_notes", notes_switch.value)
+ write_adminsetting("holidays", data["holidays"])
+ write_adminsetting("vacation_application", va_switch.value)
+
+ if int(old_port) != int(port.value):
+ with ui.dialog() as dialog, ui.card():
+ ui.label(
+ "Damit die Porteinstellungen wirksam werden, muss der Server neu gestartet werden.")
+ ui.button("OK", on_click=lambda: dialog.close())
+ dialog.open()
+ ui.notify("Einstellungen gespeichert")
+ reset_visibility.value = False
+ timetable.refresh()
+
+ if not set(old_no_time_users_list) == set(get_no_time_users_list()):
+ with ui.dialog() as infobox, ui.card():
+ ui.label("Benutzer ohne Zeiterfassung wurden geändert. Die Seite wird neu geladen.")
+ ui.button("OK", on_click=ui.navigate.reload)
+ infobox.open()
with ui.button("Speichern", on_click=save_admin_settings):
with ui.tooltip():
@@ -1080,7 +1127,6 @@ def page_admin():
workhours = [ ]
with ui.row():
-
def user_selection_changed():
try:
if user_selection.value != None:
@@ -1089,7 +1135,12 @@ def page_admin():
fullname_input.value = current_user.fullname
#password_input.value = current_user.password
usersettingscard.visible = True
-
+ if current_user.username in get_admin_list():
+ delete_info.value = True
+ delete_binder.value = False
+ else:
+ delete_info.value = False
+ delete_binder.value = True
api_key_input.value = current_user.api_key
api_link_column.clear()
@@ -1162,7 +1213,7 @@ def page_admin():
ui.label("Benutzername wurde geändert.").classes('text-bold')
ui.label(f"Benutzerdaten werden in den neuen Ordner {username_input.value} verschoben.")
ui.label("Sollen die Einstellungen gespeichert werden?")
- with ui.row():
+ with ui.row().classes('w-full justify-center'):
ui.button("Speichern", on_click=save_settings)
ui.button("Abbrechen", on_click=dialog.close)
dialog.open()
@@ -1215,9 +1266,9 @@ def page_admin():
with ui.dialog() as dialog, ui.card():
ui.label("Sollen die Änderungen an den Arbeitsstunden und/oder Urlaubstagen gespeichert werden?")
- with ui.row():
+ with ui.row().classes('justify-center w-full'):
ui.button("Speichern", on_click=save_settings)
- ui.button("Abrrechen", on_click=dialog.close)
+ ui.button("Abbrechen", on_click=dialog.close)
dialog.open()
def delete_workhour_entry():
@@ -1321,16 +1372,18 @@ def page_admin():
ui.button("Neu", on_click=new_api_key).tooltip("Neuen API-Schlüssel erzeugen. Wird erst beim Klick auf Speichern übernommen und entsprechende Links und QR-Codes aktualisiert")
ui.label('Aufruf zum Stempeln:')
global api_link_column
- with ui.column().classes('gap-0') as api_link_column:
- global stamp_link
- stamp_link = [ ]
- for i in app.urls:
- stamp_link.append(ui.link(f'{i}/api/stamp/"API-Schüssel"'))
-
+ with ui.expansion("").classes('w-full'):
+ with ui.column().classes('gap-0') as api_link_column:
+ global stamp_link
+ stamp_link = [ ]
+ for i in app.urls:
+ stamp_link.append(ui.link(f'{i}/api/stamp/"API-Schüssel"'))
+ ui.label("Administratoren können nicht gelöscht werden. Um das Konto zu löschen, müssen Sie ihm zuerst die Administrationsrechte entziehen.").bind_visibility_from(delete_info, 'value').classes('font-bold text-red')
with ui.grid(columns=2):
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).bind_enabled_from(delete_binder, 'value')
+
usersettings_card()
diff --git a/lib/definitions.py b/lib/definitions.py
index f8a4747..31ab1ee 100644
--- a/lib/definitions.py
+++ b/lib/definitions.py
@@ -6,7 +6,7 @@ from pathlib import Path
import hashlib
app_title = "Zeiterfassung"
-app_version = "beta-2025.0.1"
+app_version = "beta-2025.0.2"
# Standardpfade
@@ -36,8 +36,9 @@ status_out = "ausgestempelt"
# Standardadmin Settings:
-standard_adminsettings = { "admin_user": "admin",
- "admin_password": "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918",
+standard_adminsettings = { "admin_user": {
+ 0: "admin"},
+ "no_time_users": { },
"port": "8090",
"secret": "ftgzuhjikg,mt5jn46uzer8sfi9okrmtzjhndfierko5zltjhdgise",
"times_on_touchscreen": True,
@@ -55,9 +56,9 @@ standard_adminsettings = { "admin_user": "admin",
# Standard User Settings:
standard_usersettings = {
- "username": "default",
- "fullname": "Standardbenutzer",
- "password": "37a8eec1ce19687d132fe29051dca629d164e2c4958ba141d5f4133a33f0688f",
+ "username": "admin",
+ "fullname": "Administrator",
+ "password": "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918",
"api_key": "1234567890",
"workhours": { }
}
diff --git a/lib/login.py b/lib/login.py
deleted file mode 100644
index 25520ae..0000000
--- a/lib/login.py
+++ /dev/null
@@ -1,41 +0,0 @@
-from datetime import datetime
-
-from nicegui import ui, app
-from lib.web_ui import *
-
-from lib.users import *
-from lib.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"]:
- print(f"Input Hash: {hash_password(password.value)} gespeichert: {data['admin_password']}")
- if hash_password(password.value) == data["admin_password"]:
- app.storage.user['authenticated'] = True
- 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/lib/touchscreen.py b/lib/touchscreen.py
index 9557552..a06beca 100644
--- a/lib/touchscreen.py
+++ b/lib/touchscreen.py
@@ -41,15 +41,15 @@ def page_touchscreen():
def set_columns(width):
nonlocal number_of_columns
if width > 1400:
- number_of_columns = 6
- elif width > 1200:
number_of_columns = 5
- elif width > 900:
+ elif width > 1200:
number_of_columns = 4
- elif width > 750:
+ elif width > 900:
number_of_columns = 3
- else:
+ elif width > 750:
number_of_columns = 2
+ else:
+ number_of_columns = 1
user_buttons.refresh()
ui.on('resize', lambda e: set_columns(e.args['width']))
@@ -71,76 +71,77 @@ def page_touchscreen():
''')
- with ui.grid(columns=number_of_columns).classes('w-full center'):
+ with ui.grid(columns=number_of_columns).classes('w-full'):
for name in userlist:
current_user = user(name)
- current_button = ui.button(on_click=lambda name=name: button_click(name)).classes(f'w-md h-full min-h-[{admin_settings["button_height"]}px]')
+ if not current_user.username in get_no_time_users_list():
+ current_button = ui.button(on_click=lambda name=name: button_click(name)).classes(f'h-full min-h-[{admin_settings["button_height"]}px]')
- with current_button:
- with ui.grid(columns='1fr 1fr').classes('w-full h-full py-5 items-start'):
+ with current_button:
+ with ui.grid(columns='1fr 1fr').classes('w-full h-full py-5 items-start'):
- if admin_settings["photos_on_touchscreen"]:
- image_size = int(admin_settings["picture_height"])
- try:
- with open(current_user.photofile, 'r') as file:
- pass
- ui.image(current_user.photofile).classes(f'max-h-[{image_size}px]').props('fit=scale-down')
- except:
- no_photo_svg = f'''
-
- '''
- ui.html(no_photo_svg)
- with ui.column().classes('' if admin_settings["photos_on_touchscreen"] else 'col-span-2'):
- ui.label(current_user.fullname).classes('text-left text-xl text.bold')
- if admin_settings["times_on_touchscreen"]:
- todays_timestamps = current_user.get_day_timestamps()
- # Wenn wir Einträge haben
- if len(todays_timestamps) > 0 and admin_settings["times_on_touchscreen"]:
- table_string = ""
- for i in range(0, len(todays_timestamps), 2):
- try:
- table_string += f"{datetime.datetime.fromtimestamp(todays_timestamps[i]).strftime('%H:%M')} - {datetime.datetime.fromtimestamp(todays_timestamps[i+1]).strftime('%H:%M')}"
- except IndexError:
- table_string += f"{datetime.datetime.fromtimestamp(todays_timestamps[i]).strftime('%H:%M')} -"
- if i < len(todays_timestamps) - 2:
- table_string += "\n"
- ui.label(table_string).style('white-space: pre-wrap').classes('text-left')
- if current_user.stamp_status() == status_in:
- current_button.props('color=green')
- else:
- current_button.props('color=red')
- buttons[name] = current_button
+ if admin_settings["photos_on_touchscreen"]:
+ image_size = int(admin_settings["picture_height"])
+ try:
+ with open(current_user.photofile, 'r') as file:
+ pass
+ ui.image(current_user.photofile).classes(f'max-h-[{image_size}px]').props('fit=scale-down')
+ except:
+ no_photo_svg = f'''
+
+ '''
+ ui.html(no_photo_svg, sanitize=False)
+ with ui.column().classes('' if admin_settings["photos_on_touchscreen"] else 'col-span-2'):
+ ui.label(current_user.fullname).classes('text-left text-xl text.bold')
+ if admin_settings["times_on_touchscreen"]:
+ todays_timestamps = current_user.get_day_timestamps()
+ # Wenn wir Einträge haben
+ if len(todays_timestamps) > 0 and admin_settings["times_on_touchscreen"]:
+ table_string = ""
+ for i in range(0, len(todays_timestamps), 2):
+ try:
+ table_string += f"{datetime.datetime.fromtimestamp(todays_timestamps[i]).strftime('%H:%M')} - {datetime.datetime.fromtimestamp(todays_timestamps[i+1]).strftime('%H:%M')}"
+ except IndexError:
+ table_string += f"{datetime.datetime.fromtimestamp(todays_timestamps[i]).strftime('%H:%M')} -"
+ if i < len(todays_timestamps) - 2:
+ table_string += "\n"
+ ui.label(table_string).style('white-space: pre-wrap').classes('text-left')
+ if current_user.stamp_status() == status_in:
+ current_button.props('color=green')
+ else:
+ current_button.props('color=red')
+ buttons[name] = current_button
user_buttons()
else:
diff --git a/lib/users.py b/lib/users.py
index eb5c00a..345b440 100644
--- a/lib/users.py
+++ b/lib/users.py
@@ -578,3 +578,13 @@ def write_adminsetting(key: str, value):
except KeyError:
print(f"Kein Einstellungsschlüssel {key} vorhanden.")
+def get_admin_list():
+ adnin_settings = load_adminsettings()
+ admin_list = load_adminsettings()["admin_user"]
+ return admin_list.values()
+
+def get_no_time_users_list():
+ adnin_settings = load_adminsettings()
+ admin_list = load_adminsettings()["no_time_users"]
+ return admin_list.values()
+
diff --git a/lib/web_ui.py b/lib/web_ui.py
index 919eb4f..d14864a 100644
--- a/lib/web_ui.py
+++ b/lib/web_ui.py
@@ -38,10 +38,26 @@ class login_mask:
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")
+ if username.value in get_admin_list():
+ current_user = user(username.value)
+ if hash_password(password.value) == current_user.password:
+ if not username.value in get_no_time_users_list():
+ with ui.dialog() as forward_dialog, ui.card():
+ ui.label("Wollen Sie den Administrationsbereich oder den Datenbereich aufrufen?")
+ def admin_area():
+ app.storage.user['admin_authenticated'] = True
+ ui.navigate.to('/admin')
+ def time_area():
+ app.storage.user['active_user'] = current_user.username
+ ui.navigate.to(self.target)
+ with ui.grid(columns=2).classes('justify-center w-full'):
+ ui.button("Administrationsbereich", on_click=admin_area)
+ ui.button("Datenbereich", on_click=time_area)
+
+ forward_dialog.open()
+ else:
+ app.storage.user['admin_authenticated'] = True
+ ui.navigate.to("/admin")
else:
ui.notify("Login fehlgeschlagen")
else:
diff --git a/main.py b/main.py
index 6566a6c..2e524e8 100644
--- a/main.py
+++ b/main.py
@@ -4,7 +4,6 @@ import os.path
from lib.web_ui import *
from lib.admin import *
-from lib.login import *
from lib.users import *
from lib.touchscreen import *
from lib.definitions import *
@@ -33,7 +32,7 @@ def main():
list_users()
- homepage()
+ #homepage()
def startup_message():
@@ -54,7 +53,7 @@ def main():
ui.toggle.default_props('rounded')
ui.row.default_classes('items-baseline')
- ui.run(favicon='⏲', port=port, storage_secret=secret, language='de-DE', show_welcome_message=False)
+ ui.run(root=homepage, favicon='⏲', port=port, storage_secret=secret, language='de-DE', show_welcome_message=False)
if __name__ in ("__main__", "__mp_main__"):
parser = argparse.ArgumentParser(description=f'{app_title} {app_version}')
@@ -85,11 +84,34 @@ if __name__ in ("__main__", "__mp_main__"):
print("Sollen diese Einstellungen übernommen werden? j=Ja")
question = input()
if question == "j":
- admin_settings["admin_user"] = admin_user
- admin_settings["admin_password"] = hash_password(admin_password)
- json_dict = json.dumps(admin_settings, indent=4)
- with open(os.path.join(scriptpath, usersettingsfilename), "w") as outputfile:
- outputfile.write(json_dict)
+ if not os.path.exists(userfolder):
+ os.makedirs(userfolder)
+ print("Kein Ordner mit Benutzerdaten gefunden. Lege ihn an.")
+ if not os.path.exists(os.path.join(userfolder, admin_user)):
+ print("Benutzer existiert noch nicht. Lege ihn an.")
+ os.makedirs(os.path.join(userfolder, admin_user))
+ start_date_dt = datetime.datetime.now()
+ start_date = start_date_dt.strftime("%Y-%m-%d")
+ settings_to_write = standard_usersettings
+ settings_to_write["workhours"][start_date] = {}
+ settings_to_write["fullname"] = "Administrator"
+ settings_to_write["username"] = admin_user
+ # API-Key erzeugen
+ string_to_hash = f'{admin_user}_{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):
+ settings_to_write["workhours"][start_date][str(i)] = 0
+ settings_to_write["workhours"][start_date]["vacation"] = 0
+ with open(f"{userfolder}/{admin_user}/{usersettingsfilename}", 'w') as json_file:
+ json_dict = json.dumps(standard_usersettings, indent=4)
+ json_file.write(json_dict)
+ current_user = user(admin_user)
+ current_user.password = hash_password(admin_password)
+ current_user.write_settings()
+ admin_users_list = load_adminsettings()["admin_user"]
+ admin_users_list[str(len(admin_users_list))] = admin_user
+ write_adminsetting("admin_user", admin_users_list)
print("Daten geschrieben")
quit()
else:
diff --git a/settings.json b/settings.json
new file mode 100644
index 0000000..9ac6bba
--- /dev/null
+++ b/settings.json
@@ -0,0 +1,20 @@
+{
+ "admin_user": {
+ "0": "admin"
+ },
+ "no_time_users": {
+ "0": "admin"
+ },
+ "port": "8090",
+ "secret": "ftgzuhjikg,mt5jn46uzer8sfi9okrmtzjhndfierko5zltjhdgise",
+ "times_on_touchscreen": true,
+ "photos_on_touchscreen": true,
+ "touchscreen": true,
+ "picture_height": 200,
+ "button_height": "300",
+ "user_notes": true,
+ "vacation_application": true,
+ "backup_folder": "/home/alexander/Dokumente/Python/Zeiterfassung/backup",
+ "backup_api_key": "6fed93dc4a35308b2c073a8a6f3284afe1fb9946",
+ "holidays": {}
+}
\ No newline at end of file