Merge branch 'read-only' into web_ui
This commit is contained in:
commit
43b4b6bce5
53
admin.py
53
admin.py
@ -11,6 +11,8 @@ from calendar import monthrange
|
|||||||
from web_ui import *
|
from web_ui import *
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
import os
|
||||||
|
from stat import S_IREAD, S_IRWXU
|
||||||
import hashlib
|
import hashlib
|
||||||
import calendar
|
import calendar
|
||||||
import locale
|
import locale
|
||||||
@ -130,7 +132,7 @@ def page_admin():
|
|||||||
def update_month_and_year():
|
def update_month_and_year():
|
||||||
current_user = user(time_user.value)
|
current_user = user(time_user.value)
|
||||||
# Archivstatus
|
# Archivstatus
|
||||||
|
days_with_errors = current_user.archiving_validity_check(int(select_year.value), int(select_month.value))
|
||||||
with ui.grid(columns='auto auto auto 1fr 1fr 1fr 1fr') as table_grid:
|
with ui.grid(columns='auto auto auto 1fr 1fr 1fr 1fr') as table_grid:
|
||||||
if int(select_month.value) > 1:
|
if int(select_month.value) > 1:
|
||||||
archive_status = current_user.get_archive_status(int(select_year.value),
|
archive_status = current_user.get_archive_status(int(select_year.value),
|
||||||
@ -140,7 +142,11 @@ def page_admin():
|
|||||||
|
|
||||||
def revoke_archive_status():
|
def revoke_archive_status():
|
||||||
def revoke_status():
|
def revoke_status():
|
||||||
filename = f"{current_user.userfolder}/{int(select_year.value)}-{int(select_month.value)}.json"
|
filestring = f"{current_user.userfolder}/{int(select_year.value)}-{int(select_month.value)}"
|
||||||
|
filename = f"{filestring}.txt"
|
||||||
|
os.chmod(filename, S_IRWXU)
|
||||||
|
filename = f"{filestring}.json"
|
||||||
|
os.chmod(filename, S_IRWXU)
|
||||||
with open(filename, 'r') as json_file:
|
with open(filename, 'r') as json_file:
|
||||||
data = json.load(json_file)
|
data = json.load(json_file)
|
||||||
data["archived"] = 0
|
data["archived"] = 0
|
||||||
@ -160,7 +166,7 @@ def page_admin():
|
|||||||
dialog.open()
|
dialog.open()
|
||||||
|
|
||||||
if archive_status == True:
|
if archive_status == True:
|
||||||
with ui.row().classes('text-right col-span-6 justify-center'):
|
with ui.row().classes('text-right col-span-7 justify-center'):
|
||||||
ui.button("Archiviert", on_click=revoke_archive_status).classes('bg-transparent text-black')
|
ui.button("Archiviert", on_click=revoke_archive_status).classes('bg-transparent text-black')
|
||||||
ui.separator()
|
ui.separator()
|
||||||
calendar_card.classes('bg-yellow')
|
calendar_card.classes('bg-yellow')
|
||||||
@ -304,22 +310,26 @@ Dies kann nicht rückgängig gemacht werden!''')
|
|||||||
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))
|
||||||
if archive_status:
|
if archive_status:
|
||||||
timestamp_button.disable()
|
timestamp_button.disable()
|
||||||
|
with ui.row():
|
||||||
|
# Fehlerhinweis
|
||||||
|
if day in days_with_errors:
|
||||||
|
ui.icon('warning', color='red').tooltip("Keine Schlussbuchung").classes('text-2xl')
|
||||||
|
|
||||||
# Notizen anzeigen
|
# Notizen anzeigen
|
||||||
days_notes = current_user.get_day_notes(select_year.value, select_month.value, day)
|
days_notes = current_user.get_day_notes(select_year.value, select_month.value, day)
|
||||||
if days_notes != { }:
|
if days_notes != { }:
|
||||||
with ui.icon('o_description').classes('text-2xl'):
|
with ui.icon('o_description').classes('text-2xl'):
|
||||||
with ui.tooltip():
|
with ui.tooltip():
|
||||||
with ui.grid(columns='auto auto'):
|
with ui.grid(columns='auto auto'):
|
||||||
for username, text in days_notes.items():
|
for username, text in days_notes.items():
|
||||||
admins_name = load_adminsettings()["admin_user"]
|
admins_name = load_adminsettings()["admin_user"]
|
||||||
if username == admins_name:
|
if username == admins_name:
|
||||||
ui.markdown('Administrator:')
|
ui.markdown('Administrator:')
|
||||||
else:
|
else:
|
||||||
ui.markdown(current_user.fullname)
|
ui.markdown(current_user.fullname)
|
||||||
ui.markdown(text)
|
ui.markdown(text)
|
||||||
else:
|
else:
|
||||||
ui.space()
|
ui.space()
|
||||||
|
|
||||||
# Arbeitszeit Ist bestimmen
|
# Arbeitszeit Ist bestimmen
|
||||||
|
|
||||||
@ -539,13 +549,15 @@ Dies kann nicht rückgängig gemacht werden!''')
|
|||||||
dialog.open()
|
dialog.open()
|
||||||
dialog.move(calendar_card)
|
dialog.move(calendar_card)
|
||||||
|
|
||||||
with ui.button(icon='menu'):
|
with ui.button(icon='menu') as menu_button:
|
||||||
with ui.menu() as menu:
|
with ui.menu() as menu:
|
||||||
menu_item = ui.menu_item("Zeiteintrag hinzufügen", lambda day=day: add_entry(day))
|
menu_item = ui.menu_item("Zeiteintrag hinzufügen", lambda day=day: add_entry(day))
|
||||||
if archive_status:
|
if archive_status:
|
||||||
menu_item.disable()
|
menu_item.disable()
|
||||||
ui.separator()
|
ui.separator()
|
||||||
menu_item = ui.menu_item("Notizen bearbeiten", lambda day=day: edit_notes(day))
|
menu_item = ui.menu_item("Notizen bearbeiten", lambda day=day: edit_notes(day))
|
||||||
|
if archive_status:
|
||||||
|
menu_item.disable()
|
||||||
ui.separator()
|
ui.separator()
|
||||||
for i in list(absence_entries):
|
for i in list(absence_entries):
|
||||||
menu_item = ui.menu_item(f"{absence_entries[i]['name']} eintragen", lambda absence_type=i, day=day: add_absence(absence_type, day))
|
menu_item = ui.menu_item(f"{absence_entries[i]['name']} eintragen", lambda absence_type=i, day=day: add_absence(absence_type, day))
|
||||||
@ -553,6 +565,8 @@ Dies kann nicht rückgängig gemacht werden!''')
|
|||||||
menu_item.disable()
|
menu_item.disable()
|
||||||
if str(day) in list(user_absent):
|
if str(day) in list(user_absent):
|
||||||
menu_item.disable()
|
menu_item.disable()
|
||||||
|
if archive_status:
|
||||||
|
menu_button.disable()
|
||||||
|
|
||||||
#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))
|
||||||
|
|
||||||
@ -576,6 +590,7 @@ Dies kann nicht rückgängig gemacht werden!''')
|
|||||||
current_user = user(time_user.value)
|
current_user = user(time_user.value)
|
||||||
month_header.set_content(f"###Buchungen für **{current_user.fullname}** für **{calendar.month_name[int(select_month.value)]} {select_year.value}**")
|
month_header.set_content(f"###Buchungen für **{current_user.fullname}** für **{calendar.month_name[int(select_month.value)]} {select_year.value}**")
|
||||||
|
|
||||||
|
month_header.set_content(f"###Buchungen für **{current_user.fullname}** für **{calendar.month_name[int(select_month.value)]} {select_year.value}**")
|
||||||
timetable()
|
timetable()
|
||||||
button_update = ui.button("Aktualisieren", on_click=timetable.refresh)
|
button_update = ui.button("Aktualisieren", on_click=timetable.refresh)
|
||||||
button_update.move(timetable_header)
|
button_update.move(timetable_header)
|
||||||
|
18
api.py
18
api.py
@ -21,6 +21,7 @@ def page_overview_month(username: str, year: int, month: int):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
current_user = user(username)
|
current_user = user(username)
|
||||||
|
days_with_errors = current_user.archiving_validity_check(year, month)
|
||||||
ui.page_title(f"Bericht für {current_user.fullname} für {calendar.month_name[month]} {year}")
|
ui.page_title(f"Bericht für {current_user.fullname} für {calendar.month_name[month]} {year}")
|
||||||
if current_user.get_archive_status(year, month):
|
if current_user.get_archive_status(year, month):
|
||||||
with ui.column().classes('w-full items-end gap-0'):
|
with ui.column().classes('w-full items-end gap-0'):
|
||||||
@ -80,7 +81,8 @@ def page_overview_month(username: str, year: int, month: int):
|
|||||||
color_day = color_weekend
|
color_day = color_weekend
|
||||||
|
|
||||||
current_day_date = f"{datetime(year, month, day).strftime('%a')}, {day}.{month}.{year}"
|
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}')
|
with ui.link_target(day):
|
||||||
|
ui.markdown(current_day_date).classes(f'border px-{pad_x} py-{pad_y} bg-{color_day}')
|
||||||
|
|
||||||
|
|
||||||
# Abwesenheitseinträge
|
# Abwesenheitseinträge
|
||||||
@ -100,11 +102,11 @@ def page_overview_month(username: str, year: int, month: int):
|
|||||||
for i in range(0, len(timestamps_dict[day]), 2):
|
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>"
|
||||||
|
|
||||||
except:
|
except:
|
||||||
if len(timestamps_dict[day]) % 2 != 0:
|
if len(timestamps_dict[day]) % 2 != 0:
|
||||||
booking_text += datetime.fromtimestamp(int(timestamps_dict[day][i])).strftime('%H:%M')
|
booking_text += datetime.fromtimestamp(int(timestamps_dict[day][i])).strftime('%H:%M') + " - ***Buchung fehlt!***"
|
||||||
|
|
||||||
booking_text_element = ui.markdown(booking_text).classes(f'border px-{pad_x} py-{pad_y} bg-{booking_color} text-{booking_text_color}')
|
booking_text_element = ui.markdown(booking_text).classes(f'border px-{pad_x} py-{pad_y} bg-{booking_color} text-{booking_text_color}')
|
||||||
|
|
||||||
@ -258,7 +260,15 @@ def page_overview_month(username: str, year: int, month: int):
|
|||||||
dialog.open()
|
dialog.open()
|
||||||
|
|
||||||
if archivable == True:
|
if archivable == True:
|
||||||
ui.button("Archivieren", on_click=archive_dialog)
|
if len(days_with_errors) > 0:
|
||||||
|
ui.label("Es gibt Inkonsistenzen in den Buchungen. Folgende Tage müssen überprüft werden:")
|
||||||
|
with ui.grid(columns=len(days_with_errors)):
|
||||||
|
for i in days_with_errors:
|
||||||
|
ui.link(f"{i}.", f'#{i}')
|
||||||
|
|
||||||
|
archive_button = ui.button("Archivieren", on_click=archive_dialog)
|
||||||
|
if len(days_with_errors) > 0:
|
||||||
|
archive_button.disable()
|
||||||
|
|
||||||
archive()
|
archive()
|
||||||
|
|
||||||
|
13
playgound.py
13
playgound.py
@ -1,6 +1,17 @@
|
|||||||
from nicegui import ui
|
import json
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
from nicegui import ui, app
|
||||||
|
|
||||||
|
|
||||||
import segno
|
import segno
|
||||||
|
|
||||||
|
@app.get("/data")
|
||||||
|
async def deliver_data():
|
||||||
|
with open("settings.json") as json_file:
|
||||||
|
data = json.load(json_file)
|
||||||
|
return data
|
||||||
|
|
||||||
string = ""
|
string = ""
|
||||||
for i in range(1000):
|
for i in range(1000):
|
||||||
string += str(i)
|
string += str(i)
|
||||||
|
28
users.py
28
users.py
@ -3,6 +3,8 @@ import hashlib
|
|||||||
# User bezogene Funktionen
|
# User bezogene Funktionen
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from calendar import monthrange
|
||||||
|
from stat import S_IREAD, S_IWUSR
|
||||||
import datetime
|
import datetime
|
||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
@ -222,6 +224,25 @@ class user:
|
|||||||
except:
|
except:
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
|
def archiving_validity_check(self, year: int, month: int):
|
||||||
|
timestampfilename = f"{self.userfolder}/{year}-{month}.txt"
|
||||||
|
try:
|
||||||
|
with open(timestampfilename) as timestampfile:
|
||||||
|
timestamps = timestampfile.readlines()
|
||||||
|
timestamps.sort()
|
||||||
|
days_with_errors = [ ]
|
||||||
|
for day in range(1, monthrange(year, month)[1] + 1):
|
||||||
|
day_dt = datetime.datetime(year, month, day)
|
||||||
|
timestamps_of_this_day = [ ]
|
||||||
|
for i in timestamps:
|
||||||
|
i_dt = datetime.datetime.fromtimestamp(int(i))
|
||||||
|
if day_dt.year == i_dt.year and day_dt.month == i_dt.month and day_dt.day == i_dt.day:
|
||||||
|
timestamps_of_this_day.append(i)
|
||||||
|
if len(timestamps_of_this_day) % 2 != 0:
|
||||||
|
days_with_errors.append(day)
|
||||||
|
return days_with_errors
|
||||||
|
except:
|
||||||
|
return [ ]
|
||||||
def archive_hours(self, year, month, overtime: int):
|
def archive_hours(self, year, month, overtime: int):
|
||||||
|
|
||||||
filename = f"{self.userfolder}/{year}-{month}.json"
|
filename = f"{self.userfolder}/{year}-{month}.json"
|
||||||
@ -230,11 +251,14 @@ class user:
|
|||||||
data["archived"] = 1
|
data["archived"] = 1
|
||||||
data["overtime"] = overtime
|
data["overtime"] = overtime
|
||||||
|
|
||||||
json_dict = json.dumps(data)
|
json_dict = json.dumps(data, indent=4)
|
||||||
|
|
||||||
with open(filename, "w") as outputfile:
|
with open(filename, "w") as outputfile:
|
||||||
outputfile.write(json_dict)
|
outputfile.write(json_dict)
|
||||||
|
# Dateien auf readonly setzen
|
||||||
|
os.chmod(filename, S_IREAD)
|
||||||
|
filename_txt = f"{self.userfolder}/{year}-{month}.txt"
|
||||||
|
os.chmod(filename_txt, S_IREAD)
|
||||||
def get_last_months_overtime(self, year, month):
|
def get_last_months_overtime(self, year, month):
|
||||||
try:
|
try:
|
||||||
if int(month) == 1:
|
if int(month) == 1:
|
||||||
|
2
users/testuser1/2025-3.json
Normal file → Executable file
2
users/testuser1/2025-3.json
Normal file → Executable file
@ -1 +1 @@
|
|||||||
{"archived": 1, "overtime": -528928}
|
{"archived": 0, "overtime": -528928}
|
32
users/testuser1/2025-3.txt
Normal file → Executable file
32
users/testuser1/2025-3.txt
Normal file → Executable file
@ -1,30 +1,4 @@
|
|||||||
1743965819
|
|
||||||
1743965909
|
|
||||||
1743966022
|
|
||||||
1743966045
|
|
||||||
1743966047
|
|
||||||
1743966049
|
|
||||||
1743967346
|
|
||||||
1744889948
|
|
||||||
1744889966
|
|
||||||
1744989797
|
|
||||||
1744989827
|
|
||||||
1744989830
|
|
||||||
1744989883
|
|
||||||
1744989909
|
|
||||||
1744989914
|
|
||||||
1744989916
|
|
||||||
1744991169
|
|
||||||
1744991171
|
|
||||||
1744991288
|
|
||||||
1744991291
|
|
||||||
1744991473
|
|
||||||
1744991477
|
|
||||||
1744991770
|
|
||||||
1744991777
|
|
||||||
1745181046
|
|
||||||
1745181050
|
|
||||||
1745240760
|
|
||||||
1745240762
|
|
||||||
1740996000
|
1740996000
|
||||||
1740997800
|
1742460540
|
||||||
|
1741038540
|
||||||
|
1742464500
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"archived": 0,
|
"archived": 1,
|
||||||
"overtime": 0,
|
"overtime": -877154,
|
||||||
"absence": {
|
"absence": {
|
||||||
"7": "U",
|
"7": "U",
|
||||||
"8": "K",
|
"8": "K",
|
||||||
|
@ -1,21 +1,5 @@
|
|||||||
1744889948
|
1744889948
|
||||||
1744890300
|
1744890300
|
||||||
1744989797
|
|
||||||
1744989827
|
|
||||||
1744989830
|
|
||||||
1744989883
|
|
||||||
1744989909
|
|
||||||
1744989914
|
|
||||||
1744989916
|
|
||||||
1744991169
|
|
||||||
1744991171
|
|
||||||
1744991288
|
|
||||||
1744991291
|
|
||||||
1744991473
|
|
||||||
1744991477
|
|
||||||
1744991770
|
|
||||||
1745215200
|
|
||||||
1745229600
|
|
||||||
1745390818
|
1745390818
|
||||||
1745390894
|
1745390894
|
||||||
1745390894
|
1745390894
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
"archived": 0,
|
"archived": 0,
|
||||||
"overtime": 0,
|
"overtime": 0,
|
||||||
"absence": {
|
"absence": {
|
||||||
"14": "U",
|
|
||||||
"2": "SO"
|
"2": "SO"
|
||||||
},
|
},
|
||||||
"notes": {
|
"notes": {
|
||||||
|
@ -6,3 +6,6 @@
|
|||||||
1746608922
|
1746608922
|
||||||
1746609024
|
1746609024
|
||||||
1746609037
|
1746609037
|
||||||
|
1747206908
|
||||||
|
1747207022
|
||||||
|
1747813500
|
||||||
|
Loading…
x
Reference in New Issue
Block a user