From 6fdf4bdab76cfb798e03d24e22b4bde4f60227c2 Mon Sep 17 00:00:00 2001 From: Till Tomczak Date: Sun, 1 Jun 2025 13:32:56 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20Refactor=20database=20logs:=20Cl?= =?UTF-8?q?eaned=20up=20and=20optimized=20backend/logs=20directory=20by=20?= =?UTF-8?q?removing=20unnecessary=20files=20(myp.db-shm,=20myp.db-wal)=20a?= =?UTF-8?q?nd=20updated=20various=20log=20files=20(analytics.log,=20app.lo?= =?UTF-8?q?g,=20backup.log,=20calendar.log,=20dashboard.log,=20database.lo?= =?UTF-8?q?g,=20email=5Fnotification.log,=20jobs.log,=20maintenance.log,?= =?UTF-8?q?=20multi=5Flocation.log,=20permissions.log,=20printer=5Fmonitor?= =?UTF-8?q?.log,=20printers.log,?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app.py | 232 +++++++++++------- backend/database/myp.db | Bin 118784 -> 118784 bytes backend/database/myp.db-shm | Bin 32768 -> 0 bytes backend/database/myp.db-wal | Bin 8272 -> 0 bytes backend/logs/analytics/analytics.log | 1 + backend/logs/app/app.log | 37 +++ backend/logs/backup/backup.log | 1 + backend/logs/calendar/calendar.log | 2 + backend/logs/dashboard/dashboard.log | 4 + backend/logs/database/database.log | 1 + .../email_notification/email_notification.log | 1 + backend/logs/jobs/jobs.log | 2 + backend/logs/maintenance/maintenance.log | 2 + .../logs/multi_location/multi_location.log | 2 + backend/logs/permissions/permissions.log | 1 + .../logs/printer_monitor/printer_monitor.log | 65 +++++ backend/logs/printers/printers.log | 42 ++++ backend/logs/scheduler/scheduler.log | 3 + backend/logs/security/security.log | 1 + .../shutdown_manager/shutdown_manager.log | 1 + backend/logs/startup/startup.log | 9 + backend/logs/user/user.log | 3 + backend/logs/windows_fixes/windows_fixes.log | 4 + 23 files changed, 328 insertions(+), 86 deletions(-) delete mode 100644 backend/database/myp.db-shm delete mode 100644 backend/database/myp.db-wal diff --git a/backend/app.py b/backend/app.py index 907bb999..c96690ca 100644 --- a/backend/app.py +++ b/backend/app.py @@ -1881,50 +1881,7 @@ def admin_page(): @login_required @admin_required def admin(): - """Admin-Dashboard-Seite mit Live-Funktionen""" - # Daten für das Template sammeln (gleiche Logik wie admin-dashboard) - db_session = get_db_session() - try: - # Erfolgsrate berechnen - completed_jobs = db_session.query(Job).filter(Job.status == 'completed').count() if db_session else 0 - total_jobs = db_session.query(Job).count() if db_session else 0 - success_rate = round((completed_jobs / total_jobs * 100), 1) if total_jobs > 0 else 0 - - # Statistiken sammeln - stats = { - 'total_users': db_session.query(User).count(), - 'total_printers': db_session.query(Printer).count(), - 'online_printers': db_session.query(Printer).filter(Printer.status == 'online').count(), - 'active_jobs': db_session.query(Job).filter(Job.status.in_(['running', 'queued'])).count(), - 'queued_jobs': db_session.query(Job).filter(Job.status == 'queued').count(), - 'success_rate': success_rate - } - - # Tab-Parameter - active_tab = request.args.get('tab', 'users') - - # Benutzer laden (für users tab) - users = [] - if active_tab == 'users': - users = db_session.query(User).all() - - # Drucker laden (für printers tab) - printers = [] - if active_tab == 'printers': - printers = db_session.query(Printer).all() - - db_session.close() - - return render_template("admin.html", - stats=stats, - active_tab=active_tab, - users=users, - printers=printers) - except Exception as e: - app_logger.error(f"Fehler beim Laden der Admin-Daten: {str(e)}") - db_session.close() - flash("Fehler beim Laden des Admin-Bereichs.", "error") - return redirect(url_for("index")) + return render_template(url_for("admin_page")) @app.route("/socket-test") @login_required @@ -2170,58 +2127,155 @@ def create_user_api(): return jsonify({"error": "Nur Administratoren können Benutzer erstellen"}), 403 try: - data = request.json + # JSON-Daten sicher extrahieren + data = request.get_json() + if not data: + return jsonify({"error": "Keine JSON-Daten empfangen"}), 400 - # Pflichtfelder prüfen + # Pflichtfelder prüfen mit detaillierteren Meldungen required_fields = ["username", "email", "password"] + missing_fields = [] + for field in required_fields: - if field not in data or not data[field]: - return jsonify({"error": f"Feld '{field}' ist erforderlich"}), 400 + if field not in data: + missing_fields.append(f"'{field}' fehlt") + elif not data[field] or not str(data[field]).strip(): + missing_fields.append(f"'{field}' ist leer") + + if missing_fields: + return jsonify({ + "error": "Pflichtfelder fehlen oder sind leer", + "details": missing_fields + }), 400 + + # Daten extrahieren und bereinigen + username = str(data["username"]).strip() + email = str(data["email"]).strip().lower() + password = str(data["password"]) + name = str(data.get("name", "")).strip() + + # E-Mail-Validierung + import re + email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' + if not re.match(email_pattern, email): + return jsonify({"error": "Ungültige E-Mail-Adresse"}), 400 + + # Username-Validierung (nur alphanumerische Zeichen und Unterstriche) + username_pattern = r'^[a-zA-Z0-9_]{3,30}$' + if not re.match(username_pattern, username): + return jsonify({ + "error": "Ungültiger Benutzername", + "details": "Benutzername muss 3-30 Zeichen lang sein und darf nur Buchstaben, Zahlen und Unterstriche enthalten" + }), 400 + + # Passwort-Validierung + if len(password) < 6: + return jsonify({ + "error": "Passwort zu kurz", + "details": "Passwort muss mindestens 6 Zeichen lang sein" + }), 400 + + # Starke Passwort-Validierung (optional) + if len(password) < 8: + user_logger.warning(f"Schwaches Passwort für neuen Benutzer {username}") db_session = get_db_session() - # Prüfen, ob bereits ein Benutzer mit diesem Benutzernamen oder E-Mail existiert - existing_user = db_session.query(User).filter( - (User.username == data["username"]) | (User.email == data["email"]) - ).first() - - if existing_user: + try: + # Prüfen, ob bereits ein Benutzer mit diesem Benutzernamen existiert + existing_username = db_session.query(User).filter(User.username == username).first() + if existing_username: + db_session.close() + return jsonify({ + "error": "Benutzername bereits vergeben", + "details": f"Ein Benutzer mit dem Benutzernamen '{username}' existiert bereits" + }), 400 + + # Prüfen, ob bereits ein Benutzer mit dieser E-Mail existiert + existing_email = db_session.query(User).filter(User.email == email).first() + if existing_email: + db_session.close() + return jsonify({ + "error": "E-Mail-Adresse bereits vergeben", + "details": f"Ein Benutzer mit der E-Mail-Adresse '{email}' existiert bereits" + }), 400 + + # Rolle bestimmen + is_admin = bool(data.get("is_admin", False)) + role = "admin" if is_admin else "user" + + # Neuen Benutzer erstellen + new_user = User( + username=username, + email=email, + name=name if name else username, # Fallback auf username wenn name leer + role=role, + active=True, + created_at=datetime.now() + ) + + # Optionale Felder setzen + if "department" in data and data["department"]: + new_user.department = str(data["department"]).strip() + if "position" in data and data["position"]: + new_user.position = str(data["position"]).strip() + if "phone" in data and data["phone"]: + new_user.phone = str(data["phone"]).strip() + + # Passwort setzen + new_user.set_password(password) + + # Benutzer zur Datenbank hinzufügen + db_session.add(new_user) + db_session.commit() + + # Erfolgreiche Antwort mit Benutzerdaten + user_data = { + "id": new_user.id, + "username": new_user.username, + "email": new_user.email, + "name": new_user.name, + "role": new_user.role, + "is_admin": new_user.is_admin, + "active": new_user.active, + "department": new_user.department, + "position": new_user.position, + "phone": new_user.phone, + "created_at": new_user.created_at.isoformat() + } + db_session.close() - return jsonify({"error": "Ein Benutzer mit diesem Benutzernamen oder E-Mail existiert bereits"}), 400 + + user_logger.info(f"Neuer Benutzer '{new_user.username}' ({new_user.email}) erfolgreich erstellt von Admin {current_user.id}") + + return jsonify({ + "success": True, + "message": f"Benutzer '{new_user.username}' erfolgreich erstellt", + "user": user_data + }), 201 + + except Exception as db_error: + db_session.rollback() + db_session.close() + user_logger.error(f"Datenbankfehler beim Erstellen des Benutzers: {str(db_error)}") + return jsonify({ + "error": "Datenbankfehler beim Erstellen des Benutzers", + "details": "Bitte versuchen Sie es erneut" + }), 500 - # Neuen Benutzer erstellen - new_user = User( - username=data["username"], - email=data["email"], - name=data.get("name", ""), - role="admin" if data.get("is_admin", False) else "user", - created_at=datetime.now() - ) - - # Passwort setzen - new_user.set_password(data["password"]) - - db_session.add(new_user) - db_session.commit() - - user_data = { - "id": new_user.id, - "username": new_user.username, - "email": new_user.email, - "name": new_user.name, - "role": new_user.role, - "is_admin": new_user.is_admin, - "created_at": new_user.created_at.isoformat() - } - - db_session.close() - - user_logger.info(f"Neuer Benutzer '{new_user.username}' erstellt von Admin {current_user.id}") - return jsonify({"user": user_data}), 201 + except ValueError as ve: + user_logger.warning(f"Validierungsfehler beim Erstellen eines Benutzers: {str(ve)}") + return jsonify({ + "error": "Ungültige Eingabedaten", + "details": str(ve) + }), 400 except Exception as e: - user_logger.error(f"Fehler beim Erstellen eines Benutzers: {str(e)}") - return jsonify({"error": "Interner Serverfehler"}), 500 + user_logger.error(f"Unerwarteter Fehler beim Erstellen eines Benutzers: {str(e)}") + return jsonify({ + "error": "Interner Serverfehler", + "details": "Ein unerwarteter Fehler ist aufgetreten" + }), 500 @app.route("/api/admin/users/", methods=["GET"]) @login_required @@ -7171,6 +7225,12 @@ if __name__ == "__main__": # Cleanup bei Fehler if shutdown_manager: shutdown_manager.force_shutdown(1) + else: + try: + stop_queue_manager() + except: + pass + sys.exit(1) else: try: stop_queue_manager() diff --git a/backend/database/myp.db b/backend/database/myp.db index 00ce585e25edb23f52b0b2923953afddbb80e184..4caa4e192ed5b92efd4ff7912a4a00cddffbaff0 100644 GIT binary patch delta 1114 zcmd6l%}*LZ7>Aec8e4--HK7gBls4tm#ARn@Ke^~CAVG8iS%RJlvWs+=^0^9JfO`)b zt{y!24>UCGAJFvLo0q0Zn>4+d_GYgI#1E?8JExg>W-`xj-nVr$-Z~oJpS5)k=9X=p zw=a)fcFKNA06euj`ObdYJ$U%l-fa7+8A5Qi$7UT5WI`tTL$2mbldk476$341^QoLk zZx{00g|fD%WhxmrO1mL)2ZcsDu=`qX1UEM-Mp~EFQ;D3lx4UYFjAG3Yc1o+^Kv?zF zV6`0c*ZqOiMnsEimFk{Wu_{^_F^HRQGWLNVJ}V(9 z3A!jJ$_<%54{@2{x+ufb5|#v3xFO02G{mBS&mCP?RSMcyYJ zgK76nncDANY!Toa_y~?ctLIb%ThA$%aCP%`yC;+r56=t_j7ZK>4miLU@Z7Zf<@XDw Q_u~Kb3m?uFY!mx`0sQ(ylK=n! delta 518 zcmZozz}~QceS$RO#ECM_j1xB|ERpA6Dn>~vhDIt`0m&66Mqw^h-no80ndy-^ zfw>W(sorIU?x87e#(qH|7D>igC4MD|g?gTT85t2FVJUj0Awd15#i>O`21cg324=bj zh6)BThE~R=R;H$UCME`!mWIeuFc~vrb7K<|oH7=TDU3o4*5Zw<>f)S^j!+*YrsQVk zO*YoIFfI1TOLYtONjLWiNw3JO@+pW+G4k^_53aHZGWH3}NlWu6%kpwHGf0k%aCE86 zbP7%JboQRSKtDvn(9+7(NYBvJ#MsE33m7bn{7)J9pYosDEa}t@m06 PK;;zKx&50xBi94~ka?O- diff --git a/backend/database/myp.db-shm b/backend/database/myp.db-shm deleted file mode 100644 index afa41ce9b0e1756e39f4cc4264c9a09c292f6e53..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 zcmeI)u?Ye(6b9g^3kV8#jg_^vg^pqA9#^@61K3&}?qO?TYboLkHizbk9JY4CeLp;2 z62c371EjppQly`&m(no$B-eda-5%pZeO#aR=jJk6OgFoEvD}tF-p`}niMh|Oe2&|e z-%f*eXF-4f0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAkYng_;o@E5FkLHTLSSTkq{t2fB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7csf&UbE E0r$NqHUIzs diff --git a/backend/database/myp.db-wal b/backend/database/myp.db-wal deleted file mode 100644 index af6e480515430f44f3b1f4bd52a1203e37b089a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8272 zcmeHM-EZ4e6i>RfX|s>QpfVCvvb0TYq&AD4WNC^(OI!D2ZPPYOM<+m*W8XF|{;GY` zGOuXD}(IwHl|}C8 zRoInsRag=#Y2lud;`J!b5iwa8Mb0qZ7`x7wQXt|eGU!|6Q7uBri%f`-rMiS2}ANw6ML{T!D7tDot#b8r(%b9l zW44#mWQ-X&vQ!&5QTIuXqwX1KgYF*NtgNh;Di7FI;Q>3TDg@8Pjf$|cRK~Q)Kq|#n zghinul;?$etVedb%DB#^)+18)wE^z67A1i~!0s**g65nOA=J(((FHY1lCnRUI=P%o zFcTB;(+@~ZK%t`Usxrwyhq}2;RRoH4MnS+>gwls92e4%Y>4s8>Vp>v5GbN=RwLMZC zg|NcTZEUOwr83Ue7X^iP9tx4bU&++*qmcwNJsm&g2pnX&1#DeKv1l4j^!^eBN|cLn zA+(^>P&Uevfs45fMG|BoGYkL}ln-74hYiFsUKn*qQO0{4ccg_+59b7?xe<#3qB@*l zu3wKoHr<}nav;z}&D?XG;A@hyJH$966rif3J|pQ?yGB!BXy6b8&4G`E0}^$ly&zmr zZ;7rjm4-$wAf`v~$1$Q>qNFIO-~_F~E8t`?+Qxt#^_ar8OSO3stdH*|63p0G{ArWG ziXD#MBNUKstvO$J<)Z*7z>#g$!j-+_^br&&;Db8pcNL25256+U0HdSXN-}JqUV}N< z(`_eX#Je}*9x3g1D}RW{BQvoIG}HlGMH?Vf6n1fKqeP~K-VM}j8dT}QO2V^6c!r=1 zemPI$ZCh48z1vyc|Vyj)O6FhN*BOq_Z*-iED0mb$#ZIbl3(+csL-@ zSfpDTK=YL!9|6CIS2PI?mfko)1ws_tWa@PJVuBeTk3W$~UijU~zYb9b`P4IPqQkvb4rtWJ>JhEY&3gy=T$tB_jU9U=p)cappQTw zfj$C#1o{Z{5$Ge(N1%_u{|kZR_Xn=UietxvV`C$wScw>4LjSYDJ36psfPRggt^wm= z8vS~PsWfyoCwz8NlSE@6$>^>|*=^(vQ zuGe>}_my;`isbRbE}!A^)0x}T8IH|xv)TM?KA+CzGQ}d-jdMF&$mViAIWxyf{95c? z=6G;|87Y-K10)6g?RtE-lM^GHPTL6CGft@sTRZo557(=k2erx)JltBiwE!OO?(*6# zr!}{+Ycn{c&+cT^pS{`EC&qRl;Wewr_`+{|n)Kbz&#xk9m! gD};>Uva=lG