🎉 Improved backend structure & added utility modules 🎨📚
This commit is contained in:
parent
91548dfb0e
commit
9e1719df4d
Binary file not shown.
194
backend/app.py
194
backend/app.py
@ -1724,14 +1724,10 @@ def api_admin_system_health():
|
|||||||
"error": str(e)
|
"error": str(e)
|
||||||
}), 500
|
}), 500
|
||||||
|
|
||||||
# ===== INTEGRATION IN BESTEHENDE ROUTEN =====
|
@app.route("/api/admin/system-health-dashboard", methods=['GET'])
|
||||||
|
|
||||||
# Erweitere bestehende Job-Routen um Dashboard-Events
|
|
||||||
|
|
||||||
@app.route("/api/admin/system-health", methods=['GET'])
|
|
||||||
@login_required
|
@login_required
|
||||||
@admin_required
|
@admin_required
|
||||||
def api_admin_system_health():
|
def api_admin_system_health_dashboard():
|
||||||
"""API-Endpunkt für System-Gesundheitscheck mit Dashboard-Integration."""
|
"""API-Endpunkt für System-Gesundheitscheck mit Dashboard-Integration."""
|
||||||
try:
|
try:
|
||||||
# Basis-System-Gesundheitscheck durchführen
|
# Basis-System-Gesundheitscheck durchführen
|
||||||
@ -5064,6 +5060,192 @@ def setup_database_with_migrations():
|
|||||||
app_logger.error(f"❌ Fehler bei Datenbank-Setup: {str(e)}")
|
app_logger.error(f"❌ Fehler bei Datenbank-Setup: {str(e)}")
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
|
# ===== PRIVACY UND TERMS ROUTEN =====
|
||||||
|
|
||||||
|
@app.route("/privacy")
|
||||||
|
def privacy_policy():
|
||||||
|
"""Datenschutzerklärung anzeigen"""
|
||||||
|
try:
|
||||||
|
return render_template("privacy_policy.html", title="Datenschutzerklärung")
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Laden der Datenschutzerklärung: {str(e)}")
|
||||||
|
flash("Fehler beim Laden der Datenschutzerklärung", "error")
|
||||||
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
|
@app.route("/terms")
|
||||||
|
def terms_of_service():
|
||||||
|
"""Nutzungsbedingungen anzeigen"""
|
||||||
|
try:
|
||||||
|
return render_template("terms_of_service.html", title="Nutzungsbedingungen")
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Laden der Nutzungsbedingungen: {str(e)}")
|
||||||
|
flash("Fehler beim Laden der Nutzungsbedingungen", "error")
|
||||||
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
|
@app.route("/legal")
|
||||||
|
def legal_notice():
|
||||||
|
"""Impressum anzeigen"""
|
||||||
|
try:
|
||||||
|
return render_template("legal_notice.html", title="Impressum")
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Laden des Impressums: {str(e)}")
|
||||||
|
flash("Fehler beim Laden des Impressums", "error")
|
||||||
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
|
@app.route("/api/privacy/accept", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
def accept_privacy_policy():
|
||||||
|
"""API-Endpunkt für Akzeptierung der Datenschutzerklärung"""
|
||||||
|
db_session = get_db_session()
|
||||||
|
try:
|
||||||
|
data = request.get_json() or {}
|
||||||
|
version = data.get("version", "1.0")
|
||||||
|
|
||||||
|
# Benutzer aus der Datenbank laden
|
||||||
|
user = db_session.query(User).filter(User.id == int(current_user.id)).first()
|
||||||
|
|
||||||
|
if not user:
|
||||||
|
return jsonify({"error": "Benutzer nicht gefunden"}), 404
|
||||||
|
|
||||||
|
# Privacy-Akzeptierung in Benutzer-Einstellungen speichern
|
||||||
|
if hasattr(user, 'settings'):
|
||||||
|
import json
|
||||||
|
settings = json.loads(user.settings) if user.settings else {}
|
||||||
|
else:
|
||||||
|
settings = session.get('user_settings', {})
|
||||||
|
|
||||||
|
# Privacy-Akzeptierung hinzufügen
|
||||||
|
if 'privacy_acceptance' not in settings:
|
||||||
|
settings['privacy_acceptance'] = {}
|
||||||
|
|
||||||
|
settings['privacy_acceptance'] = {
|
||||||
|
'accepted': True,
|
||||||
|
'version': version,
|
||||||
|
'timestamp': datetime.now().isoformat(),
|
||||||
|
'ip_address': request.remote_addr
|
||||||
|
}
|
||||||
|
|
||||||
|
# Einstellungen speichern
|
||||||
|
if hasattr(user, 'settings'):
|
||||||
|
user.settings = json.dumps(settings)
|
||||||
|
user.updated_at = datetime.now()
|
||||||
|
db_session.commit()
|
||||||
|
else:
|
||||||
|
session['user_settings'] = settings
|
||||||
|
|
||||||
|
user_logger.info(f"Benutzer {current_user.username} hat Datenschutzerklärung v{version} akzeptiert")
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"message": "Datenschutzerklärung erfolgreich akzeptiert",
|
||||||
|
"version": version,
|
||||||
|
"timestamp": datetime.now().isoformat()
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
db_session.rollback()
|
||||||
|
app_logger.error(f"Fehler bei Privacy-Akzeptierung: {str(e)}")
|
||||||
|
return jsonify({"error": "Interner Serverfehler"}), 500
|
||||||
|
finally:
|
||||||
|
db_session.close()
|
||||||
|
|
||||||
|
@app.route("/api/terms/accept", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
def accept_terms_of_service():
|
||||||
|
"""API-Endpunkt für Akzeptierung der Nutzungsbedingungen"""
|
||||||
|
db_session = get_db_session()
|
||||||
|
try:
|
||||||
|
data = request.get_json() or {}
|
||||||
|
version = data.get("version", "1.0")
|
||||||
|
|
||||||
|
# Benutzer aus der Datenbank laden
|
||||||
|
user = db_session.query(User).filter(User.id == int(current_user.id)).first()
|
||||||
|
|
||||||
|
if not user:
|
||||||
|
return jsonify({"error": "Benutzer nicht gefunden"}), 404
|
||||||
|
|
||||||
|
# Terms-Akzeptierung in Benutzer-Einstellungen speichern
|
||||||
|
if hasattr(user, 'settings'):
|
||||||
|
import json
|
||||||
|
settings = json.loads(user.settings) if user.settings else {}
|
||||||
|
else:
|
||||||
|
settings = session.get('user_settings', {})
|
||||||
|
|
||||||
|
# Terms-Akzeptierung hinzufügen
|
||||||
|
if 'terms_acceptance' not in settings:
|
||||||
|
settings['terms_acceptance'] = {}
|
||||||
|
|
||||||
|
settings['terms_acceptance'] = {
|
||||||
|
'accepted': True,
|
||||||
|
'version': version,
|
||||||
|
'timestamp': datetime.now().isoformat(),
|
||||||
|
'ip_address': request.remote_addr
|
||||||
|
}
|
||||||
|
|
||||||
|
# Einstellungen speichern
|
||||||
|
if hasattr(user, 'settings'):
|
||||||
|
user.settings = json.dumps(settings)
|
||||||
|
user.updated_at = datetime.now()
|
||||||
|
db_session.commit()
|
||||||
|
else:
|
||||||
|
session['user_settings'] = settings
|
||||||
|
|
||||||
|
user_logger.info(f"Benutzer {current_user.username} hat Nutzungsbedingungen v{version} akzeptiert")
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"message": "Nutzungsbedingungen erfolgreich akzeptiert",
|
||||||
|
"version": version,
|
||||||
|
"timestamp": datetime.now().isoformat()
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
db_session.rollback()
|
||||||
|
app_logger.error(f"Fehler bei Terms-Akzeptierung: {str(e)}")
|
||||||
|
return jsonify({"error": "Interner Serverfehler"}), 500
|
||||||
|
finally:
|
||||||
|
db_session.close()
|
||||||
|
|
||||||
|
@app.route("/api/legal/status", methods=["GET"])
|
||||||
|
@login_required
|
||||||
|
def get_legal_status():
|
||||||
|
"""API-Endpunkt für Abfrage des rechtlichen Status (Privacy/Terms Akzeptierung)"""
|
||||||
|
try:
|
||||||
|
# Benutzer-Einstellungen laden
|
||||||
|
if hasattr(current_user, 'settings') and current_user.settings:
|
||||||
|
import json
|
||||||
|
settings = json.loads(current_user.settings)
|
||||||
|
else:
|
||||||
|
settings = session.get('user_settings', {})
|
||||||
|
|
||||||
|
privacy_acceptance = settings.get('privacy_acceptance', {})
|
||||||
|
terms_acceptance = settings.get('terms_acceptance', {})
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"legal_status": {
|
||||||
|
"privacy_policy": {
|
||||||
|
"accepted": privacy_acceptance.get('accepted', False),
|
||||||
|
"version": privacy_acceptance.get('version'),
|
||||||
|
"timestamp": privacy_acceptance.get('timestamp')
|
||||||
|
},
|
||||||
|
"terms_of_service": {
|
||||||
|
"accepted": terms_acceptance.get('accepted', False),
|
||||||
|
"version": terms_acceptance.get('version'),
|
||||||
|
"timestamp": terms_acceptance.get('timestamp')
|
||||||
|
},
|
||||||
|
"compliance_required": not (
|
||||||
|
privacy_acceptance.get('accepted', False) and
|
||||||
|
terms_acceptance.get('accepted', False)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler bei Legal-Status-Abfrage: {str(e)}")
|
||||||
|
return jsonify({"error": "Interner Serverfehler"}), 500
|
||||||
|
|
||||||
|
|
||||||
# ===== STARTUP UND MAIN =====
|
# ===== STARTUP UND MAIN =====
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import sys
|
import sys
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -73,6 +73,7 @@ SESSION_LIFETIME = timedelta(hours=2) # Reduziert von 7 Tagen auf 2 Stunden fü
|
|||||||
UPLOAD_FOLDER = os.path.join(BASE_DIR, "uploads")
|
UPLOAD_FOLDER = os.path.join(BASE_DIR, "uploads")
|
||||||
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'gcode', '3mf', 'stl'}
|
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'gcode', '3mf', 'stl'}
|
||||||
MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16MB Maximum-Dateigröße
|
MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16MB Maximum-Dateigröße
|
||||||
|
MAX_FILE_SIZE = 16 * 1024 * 1024 # 16MB Maximum-Dateigröße für Drag & Drop System
|
||||||
|
|
||||||
# Umgebungskonfiguration
|
# Umgebungskonfiguration
|
||||||
ENVIRONMENT = get_env_variable("MYP_ENVIRONMENT", "development")
|
ENVIRONMENT = get_env_variable("MYP_ENVIRONMENT", "development")
|
||||||
|
Binary file not shown.
BIN
backend/database/myp.db-shm
Normal file
BIN
backend/database/myp.db-shm
Normal file
Binary file not shown.
BIN
backend/database/myp.db-wal
Normal file
BIN
backend/database/myp.db-wal
Normal file
Binary file not shown.
@ -75620,3 +75620,140 @@ WHERE users.id = ?
|
|||||||
2025-05-31 23:51:08 - myp.app - INFO - 📁 Schalte Journal-Mode um...
|
2025-05-31 23:51:08 - myp.app - INFO - 📁 Schalte Journal-Mode um...
|
||||||
2025-05-31 23:51:08 - myp.app - INFO - ✅ Datenbank-Cleanup abgeschlossen - WAL-Dateien sollten verschwunden sein
|
2025-05-31 23:51:08 - myp.app - INFO - ✅ Datenbank-Cleanup abgeschlossen - WAL-Dateien sollten verschwunden sein
|
||||||
2025-05-31 23:51:08 - myp.app - INFO - ✅ Shutdown abgeschlossen
|
2025-05-31 23:51:08 - myp.app - INFO - ✅ Shutdown abgeschlossen
|
||||||
|
2025-06-01 00:15:51 - myp.windows_fixes - INFO - 🔧 Wende Windows-spezifische Fixes an...
|
||||||
|
2025-06-01 00:15:51 - myp.windows_fixes - INFO - ✅ Subprocess automatisch gepatcht für UTF-8 Encoding (run + Popen)
|
||||||
|
2025-06-01 00:15:51 - myp.windows_fixes - INFO - ✅ Globaler subprocess-Patch angewendet
|
||||||
|
2025-06-01 00:15:51 - myp.windows_fixes - INFO - ✅ Alle Windows-Fixes erfolgreich angewendet
|
||||||
|
2025-06-01 00:15:51 - myp.app - INFO - Optimierte SQLite-Engine erstellt: C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\database\myp.db
|
||||||
|
2025-06-01 00:15:51 - myp.printer_monitor - INFO - 🖨️ Drucker-Monitor initialisiert
|
||||||
|
2025-06-01 00:15:51 - myp.printer_monitor - INFO - 🔍 Automatische Tapo-Erkennung in separatem Thread gestartet
|
||||||
|
2025-06-01 00:16:49 - myp.windows_fixes - INFO - 🔧 Wende Windows-spezifische Fixes an...
|
||||||
|
2025-06-01 00:16:49 - myp.windows_fixes - INFO - ✅ Subprocess automatisch gepatcht für UTF-8 Encoding (run + Popen)
|
||||||
|
2025-06-01 00:16:49 - myp.windows_fixes - INFO - ✅ Globaler subprocess-Patch angewendet
|
||||||
|
2025-06-01 00:16:49 - myp.windows_fixes - INFO - ✅ Alle Windows-Fixes erfolgreich angewendet
|
||||||
|
2025-06-01 00:16:49 - myp.app - INFO - Optimierte SQLite-Engine erstellt: C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\database\myp.db
|
||||||
|
2025-06-01 00:16:49 - myp.printer_monitor - INFO - 🖨️ Drucker-Monitor initialisiert
|
||||||
|
2025-06-01 00:16:49 - myp.printer_monitor - INFO - 🔍 Automatische Tapo-Erkennung in separatem Thread gestartet
|
||||||
|
2025-06-01 00:17:41 - myp.windows_fixes - INFO - 🔧 Wende Windows-spezifische Fixes an...
|
||||||
|
2025-06-01 00:17:41 - myp.windows_fixes - INFO - ✅ Subprocess automatisch gepatcht für UTF-8 Encoding (run + Popen)
|
||||||
|
2025-06-01 00:17:41 - myp.windows_fixes - INFO - ✅ Globaler subprocess-Patch angewendet
|
||||||
|
2025-06-01 00:17:41 - myp.windows_fixes - INFO - ✅ Alle Windows-Fixes erfolgreich angewendet
|
||||||
|
2025-06-01 00:17:42 - myp.app - INFO - Optimierte SQLite-Engine erstellt: C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\database\myp.db
|
||||||
|
2025-06-01 00:17:42 - myp.printer_monitor - INFO - 🖨️ Drucker-Monitor initialisiert
|
||||||
|
2025-06-01 00:17:42 - myp.printer_monitor - INFO - 🔍 Automatische Tapo-Erkennung in separatem Thread gestartet
|
||||||
|
2025-06-01 00:17:47 - myp.windows_fixes - INFO - 🔧 Wende Windows-spezifische Fixes an...
|
||||||
|
2025-06-01 00:17:47 - myp.windows_fixes - INFO - ✅ Subprocess automatisch gepatcht für UTF-8 Encoding (run + Popen)
|
||||||
|
2025-06-01 00:17:47 - myp.windows_fixes - INFO - ✅ Globaler subprocess-Patch angewendet
|
||||||
|
2025-06-01 00:17:47 - myp.windows_fixes - INFO - ✅ Alle Windows-Fixes erfolgreich angewendet
|
||||||
|
2025-06-01 00:17:47 - myp.app - INFO - Optimierte SQLite-Engine erstellt: C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\database\myp.db
|
||||||
|
2025-06-01 00:17:48 - myp.printer_monitor - INFO - 🖨️ Drucker-Monitor initialisiert
|
||||||
|
2025-06-01 00:17:48 - myp.printer_monitor - INFO - 🔍 Automatische Tapo-Erkennung in separatem Thread gestartet
|
||||||
|
2025-06-01 00:17:48 - myp.database - INFO - Datenbank-Wartungs-Scheduler gestartet
|
||||||
|
2025-06-01 00:17:48 - myp.analytics - INFO - 📈 Analytics Engine initialisiert
|
||||||
|
2025-06-01 00:18:02 - myp.windows_fixes - INFO - 🔧 Wende Windows-spezifische Fixes an...
|
||||||
|
2025-06-01 00:18:02 - myp.windows_fixes - INFO - ✅ Subprocess automatisch gepatcht für UTF-8 Encoding (run + Popen)
|
||||||
|
2025-06-01 00:18:02 - myp.windows_fixes - INFO - ✅ Globaler subprocess-Patch angewendet
|
||||||
|
2025-06-01 00:18:02 - myp.windows_fixes - INFO - ✅ Alle Windows-Fixes erfolgreich angewendet
|
||||||
|
2025-06-01 00:18:02 - myp.app - INFO - Optimierte SQLite-Engine erstellt: C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\database\myp.db
|
||||||
|
2025-06-01 00:18:02 - myp.printer_monitor - INFO - 🖨️ Drucker-Monitor initialisiert
|
||||||
|
2025-06-01 00:18:02 - myp.printer_monitor - INFO - 🔍 Automatische Tapo-Erkennung in separatem Thread gestartet
|
||||||
|
2025-06-01 00:18:02 - myp.database - INFO - Datenbank-Wartungs-Scheduler gestartet
|
||||||
|
2025-06-01 00:18:02 - myp.analytics - INFO - 📈 Analytics Engine initialisiert
|
||||||
|
2025-06-01 00:18:03 - myp.windows_fixes - INFO - 🔧 Wende Windows-spezifische Fixes an...
|
||||||
|
2025-06-01 00:18:03 - myp.windows_fixes - INFO - ✅ Subprocess automatisch gepatcht für UTF-8 Encoding (run + Popen)
|
||||||
|
2025-06-01 00:18:03 - myp.windows_fixes - INFO - ✅ Globaler subprocess-Patch angewendet
|
||||||
|
2025-06-01 00:18:03 - myp.windows_fixes - INFO - ✅ Alle Windows-Fixes erfolgreich angewendet
|
||||||
|
2025-06-01 00:18:03 - myp.app - INFO - Optimierte SQLite-Engine erstellt: C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\database\myp.db
|
||||||
|
2025-06-01 00:18:04 - myp.printer_monitor - INFO - 🖨️ Drucker-Monitor initialisiert
|
||||||
|
2025-06-01 00:18:04 - myp.printer_monitor - INFO - 🔍 Automatische Tapo-Erkennung in separatem Thread gestartet
|
||||||
|
2025-06-01 00:18:04 - myp.database - INFO - Datenbank-Wartungs-Scheduler gestartet
|
||||||
|
2025-06-01 00:18:04 - myp.analytics - INFO - 📈 Analytics Engine initialisiert
|
||||||
|
2025-06-01 00:18:52 - myp.windows_fixes - INFO - 🔧 Wende Windows-spezifische Fixes an...
|
||||||
|
2025-06-01 00:18:52 - myp.windows_fixes - INFO - ✅ Subprocess automatisch gepatcht für UTF-8 Encoding (run + Popen)
|
||||||
|
2025-06-01 00:18:52 - myp.windows_fixes - INFO - ✅ Globaler subprocess-Patch angewendet
|
||||||
|
2025-06-01 00:18:52 - myp.windows_fixes - INFO - ✅ Alle Windows-Fixes erfolgreich angewendet
|
||||||
|
2025-06-01 00:18:52 - myp.app - INFO - Optimierte SQLite-Engine erstellt: C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\database\myp.db
|
||||||
|
2025-06-01 00:18:52 - myp.printer_monitor - INFO - 🖨️ Drucker-Monitor initialisiert
|
||||||
|
2025-06-01 00:18:52 - myp.printer_monitor - INFO - 🔍 Automatische Tapo-Erkennung in separatem Thread gestartet
|
||||||
|
2025-06-01 00:18:52 - myp.database - INFO - Datenbank-Wartungs-Scheduler gestartet
|
||||||
|
2025-06-01 00:18:52 - myp.analytics - INFO - 📈 Analytics Engine initialisiert
|
||||||
|
2025-06-01 00:18:53 - myp.dashboard - INFO - Dashboard-Background-Worker gestartet
|
||||||
|
2025-06-01 00:19:31 - myp.windows_fixes - INFO - 🔧 Wende Windows-spezifische Fixes an...
|
||||||
|
2025-06-01 00:19:31 - myp.windows_fixes - INFO - ✅ Subprocess automatisch gepatcht für UTF-8 Encoding (run + Popen)
|
||||||
|
2025-06-01 00:19:31 - myp.windows_fixes - INFO - ✅ Globaler subprocess-Patch angewendet
|
||||||
|
2025-06-01 00:19:31 - myp.windows_fixes - INFO - ✅ Alle Windows-Fixes erfolgreich angewendet
|
||||||
|
2025-06-01 00:19:31 - myp.app - INFO - Optimierte SQLite-Engine erstellt: C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\database\myp.db
|
||||||
|
2025-06-01 00:19:31 - myp.printer_monitor - INFO - 🖨️ Drucker-Monitor initialisiert
|
||||||
|
2025-06-01 00:19:31 - myp.printer_monitor - INFO - 🔍 Automatische Tapo-Erkennung in separatem Thread gestartet
|
||||||
|
2025-06-01 00:19:31 - myp.database - INFO - Datenbank-Wartungs-Scheduler gestartet
|
||||||
|
2025-06-01 00:19:31 - myp.analytics - INFO - 📈 Analytics Engine initialisiert
|
||||||
|
2025-06-01 00:19:32 - myp.dashboard - INFO - Dashboard-Background-Worker gestartet
|
||||||
|
2025-06-01 00:19:32 - myp.app - INFO - SQLite für Produktionsumgebung konfiguriert (WAL-Modus, Cache, Optimierungen)
|
||||||
|
2025-06-01 00:19:52 - myp.windows_fixes - INFO - 🔧 Wende Windows-spezifische Fixes an...
|
||||||
|
2025-06-01 00:19:52 - myp.windows_fixes - INFO - ✅ Subprocess automatisch gepatcht für UTF-8 Encoding (run + Popen)
|
||||||
|
2025-06-01 00:19:52 - myp.windows_fixes - INFO - ✅ Globaler subprocess-Patch angewendet
|
||||||
|
2025-06-01 00:19:52 - myp.windows_fixes - INFO - ✅ Alle Windows-Fixes erfolgreich angewendet
|
||||||
|
2025-06-01 00:19:52 - myp.app - INFO - Optimierte SQLite-Engine erstellt: C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\database\myp.db
|
||||||
|
2025-06-01 00:19:52 - myp.printer_monitor - INFO - 🖨️ Drucker-Monitor initialisiert
|
||||||
|
2025-06-01 00:19:52 - myp.printer_monitor - INFO - 🔍 Automatische Tapo-Erkennung in separatem Thread gestartet
|
||||||
|
2025-06-01 00:19:52 - myp.database - INFO - Datenbank-Wartungs-Scheduler gestartet
|
||||||
|
2025-06-01 00:19:52 - myp.analytics - INFO - 📈 Analytics Engine initialisiert
|
||||||
|
2025-06-01 00:19:53 - myp.dashboard - INFO - Dashboard-Background-Worker gestartet
|
||||||
|
2025-06-01 00:19:53 - myp.email_notification - INFO - 📧 Offline-E-Mail-Benachrichtigung initialisiert (kein echter E-Mail-Versand)
|
||||||
|
2025-06-01 00:19:53 - myp.maintenance - INFO - Wartungs-Scheduler gestartet
|
||||||
|
2025-06-01 00:20:28 - myp.windows_fixes - INFO - 🔧 Wende Windows-spezifische Fixes an...
|
||||||
|
2025-06-01 00:20:28 - myp.windows_fixes - INFO - ✅ Subprocess automatisch gepatcht für UTF-8 Encoding (run + Popen)
|
||||||
|
2025-06-01 00:20:28 - myp.windows_fixes - INFO - ✅ Globaler subprocess-Patch angewendet
|
||||||
|
2025-06-01 00:20:28 - myp.windows_fixes - INFO - ✅ Alle Windows-Fixes erfolgreich angewendet
|
||||||
|
2025-06-01 00:20:28 - myp.app - INFO - Optimierte SQLite-Engine erstellt: C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\database\myp.db
|
||||||
|
2025-06-01 00:20:28 - myp.printer_monitor - INFO - 🖨️ Drucker-Monitor initialisiert
|
||||||
|
2025-06-01 00:20:28 - myp.printer_monitor - INFO - 🔍 Automatische Tapo-Erkennung in separatem Thread gestartet
|
||||||
|
2025-06-01 00:20:28 - myp.database - INFO - Datenbank-Wartungs-Scheduler gestartet
|
||||||
|
2025-06-01 00:20:28 - myp.analytics - INFO - 📈 Analytics Engine initialisiert
|
||||||
|
2025-06-01 00:20:29 - myp.dashboard - INFO - Dashboard-Background-Worker gestartet
|
||||||
|
2025-06-01 00:20:29 - myp.app - INFO - SQLite für Produktionsumgebung konfiguriert (WAL-Modus, Cache, Optimierungen)
|
||||||
|
2025-06-01 00:20:29 - myp.email_notification - INFO - 📧 Offline-E-Mail-Benachrichtigung initialisiert (kein echter E-Mail-Versand)
|
||||||
|
2025-06-01 00:20:29 - myp.maintenance - INFO - Wartungs-Scheduler gestartet
|
||||||
|
2025-06-01 00:20:49 - myp.windows_fixes - INFO - 🔧 Wende Windows-spezifische Fixes an...
|
||||||
|
2025-06-01 00:20:49 - myp.windows_fixes - INFO - ✅ Subprocess automatisch gepatcht für UTF-8 Encoding (run + Popen)
|
||||||
|
2025-06-01 00:20:49 - myp.windows_fixes - INFO - ✅ Globaler subprocess-Patch angewendet
|
||||||
|
2025-06-01 00:20:49 - myp.windows_fixes - INFO - ✅ Alle Windows-Fixes erfolgreich angewendet
|
||||||
|
2025-06-01 00:20:49 - myp.app - INFO - Optimierte SQLite-Engine erstellt: C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\database\myp.db
|
||||||
|
2025-06-01 00:20:49 - myp.printer_monitor - INFO - 🖨️ Drucker-Monitor initialisiert
|
||||||
|
2025-06-01 00:20:49 - myp.printer_monitor - INFO - 🔍 Automatische Tapo-Erkennung in separatem Thread gestartet
|
||||||
|
2025-06-01 00:20:49 - myp.database - INFO - Datenbank-Wartungs-Scheduler gestartet
|
||||||
|
2025-06-01 00:20:49 - myp.analytics - INFO - 📈 Analytics Engine initialisiert
|
||||||
|
2025-06-01 00:20:50 - myp.dashboard - INFO - Dashboard-Background-Worker gestartet
|
||||||
|
2025-06-01 00:20:50 - myp.email_notification - INFO - 📧 Offline-E-Mail-Benachrichtigung initialisiert (kein echter E-Mail-Versand)
|
||||||
|
2025-06-01 00:20:50 - myp.maintenance - INFO - Wartungs-Scheduler gestartet
|
||||||
|
2025-06-01 00:20:50 - myp.app - INFO - SQLite für Produktionsumgebung konfiguriert (WAL-Modus, Cache, Optimierungen)
|
||||||
|
2025-06-01 00:20:50 - myp.multi_location - INFO - Standard-Standort erstellt
|
||||||
|
2025-06-01 00:21:36 - myp.windows_fixes - INFO - 🔧 Wende Windows-spezifische Fixes an...
|
||||||
|
2025-06-01 00:21:36 - myp.windows_fixes - INFO - ✅ Subprocess automatisch gepatcht für UTF-8 Encoding (run + Popen)
|
||||||
|
2025-06-01 00:21:36 - myp.windows_fixes - INFO - ✅ Globaler subprocess-Patch angewendet
|
||||||
|
2025-06-01 00:21:36 - myp.windows_fixes - INFO - ✅ Alle Windows-Fixes erfolgreich angewendet
|
||||||
|
2025-06-01 00:21:36 - myp.app - INFO - Optimierte SQLite-Engine erstellt: C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\database\myp.db
|
||||||
|
2025-06-01 00:21:36 - myp.printer_monitor - INFO - 🖨️ Drucker-Monitor initialisiert
|
||||||
|
2025-06-01 00:21:36 - myp.printer_monitor - INFO - 🔍 Automatische Tapo-Erkennung in separatem Thread gestartet
|
||||||
|
2025-06-01 00:21:36 - myp.database - INFO - Datenbank-Wartungs-Scheduler gestartet
|
||||||
|
2025-06-01 00:21:36 - myp.analytics - INFO - 📈 Analytics Engine initialisiert
|
||||||
|
2025-06-01 00:21:37 - myp.dashboard - INFO - Dashboard-Background-Worker gestartet
|
||||||
|
2025-06-01 00:21:37 - myp.app - INFO - SQLite für Produktionsumgebung konfiguriert (WAL-Modus, Cache, Optimierungen)
|
||||||
|
2025-06-01 00:21:37 - myp.email_notification - INFO - 📧 Offline-E-Mail-Benachrichtigung initialisiert (kein echter E-Mail-Versand)
|
||||||
|
2025-06-01 00:21:37 - myp.maintenance - INFO - Wartungs-Scheduler gestartet
|
||||||
|
2025-06-01 00:21:37 - myp.multi_location - INFO - Standard-Standort erstellt
|
||||||
|
2025-06-01 00:21:37 - myp.dashboard - INFO - Dashboard-Background-Worker gestartet
|
||||||
|
2025-06-01 00:21:37 - myp.maintenance - INFO - Wartungs-Scheduler gestartet
|
||||||
|
2025-06-01 00:21:37 - myp.multi_location - INFO - Standard-Standort erstellt
|
||||||
|
2025-06-01 00:21:37 - myp.dashboard - INFO - Dashboard WebSocket-Server wird mit threading initialisiert (eventlet-Fallback)
|
||||||
|
2025-06-01 00:21:37 - myp.dashboard - INFO - Dashboard WebSocket-Server initialisiert (async_mode: threading)
|
||||||
|
2025-06-01 00:21:37 - myp.security - INFO - 🔒 Security System initialisiert
|
||||||
|
2025-06-01 00:21:37 - myp.permissions - INFO - 🔐 Permission Template Helpers registriert
|
||||||
|
2025-06-01 00:21:37 - myp.app - INFO - ==================================================
|
||||||
|
2025-06-01 00:21:37 - myp.app - INFO - [START] MYP (Manage Your Printers) wird gestartet...
|
||||||
|
2025-06-01 00:21:37 - myp.app - INFO - [FOLDER] Log-Verzeichnis: C:\Users\TTOMCZA.EMEA\Dev\Projektarbeit-MYP\backend\logs
|
||||||
|
2025-06-01 00:21:37 - myp.app - INFO - [CHART] Log-Level: INFO
|
||||||
|
2025-06-01 00:21:37 - myp.app - INFO - [PC] Betriebssystem: Windows 11
|
||||||
|
2025-06-01 00:21:37 - myp.app - INFO - [WEB] Hostname: C040L0079726760
|
||||||
|
2025-06-01 00:21:37 - myp.app - INFO - [TIME] Startzeit: 01.06.2025 00:21:37
|
||||||
|
2025-06-01 00:21:37 - myp.app - INFO - ==================================================
|
||||||
|
@ -2705,3 +2705,15 @@
|
|||||||
2025-05-31 23:50:30 - myp.scheduler - INFO - Scheduler gestartet
|
2025-05-31 23:50:30 - myp.scheduler - INFO - Scheduler gestartet
|
||||||
2025-05-31 23:51:08 - myp.scheduler - INFO - Scheduler-Thread beendet
|
2025-05-31 23:51:08 - myp.scheduler - INFO - Scheduler-Thread beendet
|
||||||
2025-05-31 23:51:08 - myp.scheduler - INFO - Scheduler gestoppt
|
2025-05-31 23:51:08 - myp.scheduler - INFO - Scheduler gestoppt
|
||||||
|
2025-06-01 00:15:51 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:16:49 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:17:42 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:17:48 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:18:02 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:18:04 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:18:52 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:19:31 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:19:52 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:20:28 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:20:49 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:21:36 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
@ -3,55 +3,136 @@
|
|||||||
# Automatisch generiert am: 2025-05-29 19:41:49
|
# Automatisch generiert am: 2025-05-29 19:41:49
|
||||||
# Installiere mit: pip install -r requirements.txt
|
# Installiere mit: pip install -r requirements.txt
|
||||||
|
|
||||||
# ===== CORE FLASK FRAMEWORK =====
|
# ===== CORE FRAMEWORK =====
|
||||||
# Direkt in app.py verwendet
|
Flask==3.0.0
|
||||||
Flask==3.1.1
|
Werkzeug==3.0.1
|
||||||
|
|
||||||
|
# ===== FLASK EXTENSIONS =====
|
||||||
Flask-Login==0.6.3
|
Flask-Login==0.6.3
|
||||||
Flask-WTF==1.2.1
|
Flask-WTF==1.2.1
|
||||||
|
Flask-SocketIO==5.3.6
|
||||||
|
WTForms==3.1.1
|
||||||
|
|
||||||
# ===== DATENBANK =====
|
# ===== DATABASE =====
|
||||||
# SQLAlchemy für Datenbankoperationen (models.py, app.py)
|
SQLAlchemy==2.0.23
|
||||||
SQLAlchemy==2.0.36
|
|
||||||
|
|
||||||
# ===== SICHERHEIT UND AUTHENTIFIZIERUNG =====
|
# ===== SECURITY =====
|
||||||
# Werkzeug für Passwort-Hashing und Utilities (app.py)
|
cryptography==41.0.8
|
||||||
bcrypt==4.2.1
|
bcrypt==4.1.2
|
||||||
cryptography==44.0.0
|
|
||||||
Werkzeug==3.1.3
|
|
||||||
|
|
||||||
# ===== SMART PLUG STEUERUNG =====
|
# ===== HTTP REQUESTS (für Online-Modus) =====
|
||||||
# PyP100 für TP-Link Tapo Smart Plugs (utils/job_scheduler.py)
|
requests==2.31.0
|
||||||
PyP100
|
urllib3==2.1.0
|
||||||
|
|
||||||
# ===== RATE LIMITING UND CACHING =====
|
# ===== HARDWARE INTEGRATION =====
|
||||||
# Redis für Rate Limiting (utils/rate_limiter.py) - optional
|
# TP-Link Tapo Smart Plugs
|
||||||
redis==5.2.1
|
PyP100==0.1.4
|
||||||
|
|
||||||
# ===== HTTP REQUESTS =====
|
# ===== REAL-TIME FEATURES =====
|
||||||
# Requests für HTTP-Anfragen (utils/queue_manager.py, utils/debug_drucker_erkennung.py)
|
# WebSocket-Support mit Fallback-Optionen
|
||||||
requests==2.32.3
|
eventlet==0.33.3
|
||||||
|
python-socketio==5.10.0
|
||||||
|
|
||||||
# ===== TEMPLATE ENGINE =====
|
# ===== SCHEDULING & TASK MANAGEMENT =====
|
||||||
# Jinja2 und MarkupSafe (automatisch mit Flask installiert, aber explizit für utils/template_helpers.py)
|
schedule==1.2.0
|
||||||
MarkupSafe==3.0.2
|
APScheduler==3.10.4
|
||||||
|
|
||||||
|
# ===== GIS & LOCATION SERVICES =====
|
||||||
|
geocoder==1.38.1
|
||||||
|
|
||||||
|
# ===== DATA PROCESSING & EXPORT =====
|
||||||
|
# Excel-Export (optional)
|
||||||
|
openpyxl==3.1.2
|
||||||
|
pandas==2.1.4
|
||||||
|
xlsxwriter==3.1.9
|
||||||
|
|
||||||
|
# CSV/JSON processing
|
||||||
|
chardet==5.2.0
|
||||||
|
|
||||||
|
# ===== EMAIL FUNCTIONALITY =====
|
||||||
|
# Email-Features für Benachrichtigungen
|
||||||
|
email-validator==2.1.0.post1
|
||||||
|
|
||||||
|
# ===== IMAGE PROCESSING =====
|
||||||
|
# Avatar und Bild-Upload
|
||||||
|
Pillow==10.1.0
|
||||||
|
|
||||||
|
# ===== DEVELOPMENT & DEBUGGING =====
|
||||||
|
# Nur für Development-Umgebung
|
||||||
|
# python-dotenv==1.0.0
|
||||||
|
|
||||||
|
# ===== DATE/TIME UTILITIES =====
|
||||||
|
python-dateutil==2.8.2
|
||||||
|
pytz==2023.3
|
||||||
|
|
||||||
|
# ===== FILE HANDLING =====
|
||||||
|
# Datei-Upload und -Verarbeitung
|
||||||
|
python-magic==0.4.27
|
||||||
|
python-magic-bin==0.4.14 # Windows binary
|
||||||
|
|
||||||
|
# ===== LOGGING & MONITORING =====
|
||||||
|
# Erweiterte Logging-Features
|
||||||
|
colorlog==6.8.0
|
||||||
|
|
||||||
|
# ===== NETWORK & CONNECTIVITY =====
|
||||||
|
# Netzwerk-Utilities für Drucker-Kommunikation
|
||||||
|
netifaces==0.11.0
|
||||||
|
ping3==4.0.4
|
||||||
|
|
||||||
|
# ===== BACKUP & COMPRESSION =====
|
||||||
|
# Backup-Funktionalität
|
||||||
|
zipfile36==0.1.3
|
||||||
|
|
||||||
|
# ===== CONFIGURATION =====
|
||||||
|
# Konfiguration und Settings
|
||||||
|
configparser==6.0.0
|
||||||
|
|
||||||
|
# ===== VALIDATION =====
|
||||||
|
# Formular-Validierung
|
||||||
|
cerberus==1.3.5
|
||||||
|
marshmallow==3.20.1
|
||||||
|
|
||||||
|
# ===== CACHING (optional) =====
|
||||||
|
# Cache-Funktionalität
|
||||||
|
cachetools==5.3.2
|
||||||
|
|
||||||
|
# ===== UTILITIES =====
|
||||||
|
# Allgemeine Utilities
|
||||||
|
python-slugify==8.0.1
|
||||||
|
click==8.1.7
|
||||||
|
|
||||||
|
# ===== COMPATIBILITY =====
|
||||||
|
# Windows-Kompatibilität
|
||||||
|
pywin32==306; sys_platform == "win32"
|
||||||
|
wmi==1.5.1; sys_platform == "win32"
|
||||||
|
|
||||||
|
# ===== OPTIONAL DEPENDENCIES =====
|
||||||
|
# Für erweiterte Features (automatisch installiert wenn verfügbar)
|
||||||
|
|
||||||
|
# PDF-Generation (für Reports)
|
||||||
|
reportlab==4.0.7
|
||||||
|
weasyprint==60.2
|
||||||
|
|
||||||
|
# Erweiterte Kryptographie
|
||||||
|
cryptography==41.0.8
|
||||||
|
|
||||||
|
# QR-Code Generation (für OTP-Codes)
|
||||||
|
qrcode==7.4.2
|
||||||
|
|
||||||
|
# ===== PRODUCTION DEPLOYMENT =====
|
||||||
|
# WSGI Server für Produktion
|
||||||
|
gunicorn==21.2.0
|
||||||
|
waitress==2.1.2
|
||||||
|
|
||||||
# ===== SYSTEM MONITORING =====
|
# ===== SYSTEM MONITORING =====
|
||||||
# psutil für System-Monitoring (utils/debug_utils.py, utils/debug_cli.py)
|
# System-Überwachung
|
||||||
psutil==6.1.1
|
psutil==5.9.6
|
||||||
|
|
||||||
# ===== ZUSÄTZLICHE CORE ABHÄNGIGKEITEN =====
|
# ===== ERROR TRACKING =====
|
||||||
# Click für CLI-Kommandos (automatisch mit Flask)
|
# Fehler-Tracking (optional)
|
||||||
# Keine Core-Requirements
|
# sentry-sdk[flask]==1.38.0
|
||||||
|
|
||||||
# ===== WINDOWS-SPEZIFISCHE ABHÄNGIGKEITEN =====
|
# ===== API DOCUMENTATION =====
|
||||||
# Nur für Windows-Systeme erforderlich
|
# API-Dokumentation (optional)
|
||||||
# Keine Windows-Requirements
|
# flask-restx==1.3.0
|
||||||
|
# flasgger==0.9.7.1
|
||||||
# ===== OPTIONAL: ENTWICKLUNG UND TESTING =====
|
|
||||||
# Nur für Entwicklungsumgebung
|
|
||||||
pytest==8.3.4; extra == "dev"
|
|
||||||
pytest-cov==6.0.0; extra == "dev"
|
|
||||||
|
|
||||||
# ===== OPTIONAL: PRODUKTIONS-SERVER =====
|
|
||||||
# Gunicorn für Produktionsumgebung
|
|
||||||
gunicorn==23.0.0; extra == "prod"
|
|
||||||
|
2
backend/static/css/tailwind.min.css
vendored
2
backend/static/css/tailwind.min.css
vendored
File diff suppressed because one or more lines are too long
BIN
backend/utils/__pycache__/advanced_tables.cpython-313.pyc
Normal file
BIN
backend/utils/__pycache__/advanced_tables.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/utils/__pycache__/drag_drop_system.cpython-313.pyc
Normal file
BIN
backend/utils/__pycache__/drag_drop_system.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/utils/__pycache__/email_notification.cpython-313.pyc
Normal file
BIN
backend/utils/__pycache__/email_notification.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/utils/__pycache__/form_validation.cpython-313.pyc
Normal file
BIN
backend/utils/__pycache__/form_validation.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/utils/__pycache__/maintenance_system.cpython-313.pyc
Normal file
BIN
backend/utils/__pycache__/maintenance_system.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/utils/__pycache__/multi_location_system.cpython-313.pyc
Normal file
BIN
backend/utils/__pycache__/multi_location_system.cpython-313.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
backend/utils/__pycache__/realtime_dashboard.cpython-313.pyc
Normal file
BIN
backend/utils/__pycache__/realtime_dashboard.cpython-313.pyc
Normal file
Binary file not shown.
BIN
backend/utils/__pycache__/report_generator.cpython-313.pyc
Normal file
BIN
backend/utils/__pycache__/report_generator.cpython-313.pyc
Normal file
Binary file not shown.
@ -933,4 +933,36 @@ def get_advanced_table_css() -> str:
|
|||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def create_table_config(table_id: str, columns: List[ColumnConfig], **kwargs) -> TableConfig:
|
||||||
|
"""
|
||||||
|
Erstellt eine neue Tabellen-Konfiguration.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
table_id: Eindeutige ID für die Tabelle
|
||||||
|
columns: Liste der Spalten-Konfigurationen
|
||||||
|
**kwargs: Zusätzliche Konfigurationsoptionen
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
TableConfig: Konfiguration für die erweiterte Tabelle
|
||||||
|
"""
|
||||||
|
return TableConfig(
|
||||||
|
table_id=table_id,
|
||||||
|
columns=columns,
|
||||||
|
default_sort=kwargs.get('default_sort', []),
|
||||||
|
default_filters=kwargs.get('default_filters', []),
|
||||||
|
pagination=kwargs.get('pagination', PaginationConfig()),
|
||||||
|
searchable=kwargs.get('searchable', True),
|
||||||
|
exportable=kwargs.get('exportable', True),
|
||||||
|
selectable=kwargs.get('selectable', False),
|
||||||
|
row_actions=kwargs.get('row_actions', [])
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_advanced_tables_js() -> str:
|
||||||
|
"""Alias für die bestehende Funktion"""
|
||||||
|
return get_advanced_table_javascript()
|
||||||
|
|
||||||
|
def get_advanced_tables_css() -> str:
|
||||||
|
"""Alias für die bestehende Funktion"""
|
||||||
|
return get_advanced_table_css()
|
@ -685,4 +685,106 @@ def get_maintenance_javascript() -> str:
|
|||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
window.maintenanceManager = new MaintenanceManager();
|
window.maintenanceManager = new MaintenanceManager();
|
||||||
});
|
});
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def create_maintenance_task(printer_id: int, title: str, description: str = "",
|
||||||
|
maintenance_type: MaintenanceType = MaintenanceType.PREVENTIVE,
|
||||||
|
priority: MaintenancePriority = MaintenancePriority.NORMAL) -> int:
|
||||||
|
"""
|
||||||
|
Erstellt eine neue Wartungsaufgabe.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
printer_id: ID des Druckers
|
||||||
|
title: Titel der Wartungsaufgabe
|
||||||
|
description: Beschreibung der Aufgabe
|
||||||
|
maintenance_type: Art der Wartung
|
||||||
|
priority: Priorität der Aufgabe
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: ID der erstellten Aufgabe
|
||||||
|
"""
|
||||||
|
task = MaintenanceTask(
|
||||||
|
printer_id=printer_id,
|
||||||
|
title=title,
|
||||||
|
description=description,
|
||||||
|
maintenance_type=maintenance_type,
|
||||||
|
priority=priority,
|
||||||
|
checklist=maintenance_manager.create_maintenance_checklist(maintenance_type)
|
||||||
|
)
|
||||||
|
|
||||||
|
return maintenance_manager.create_task(task)
|
||||||
|
|
||||||
|
def schedule_maintenance(printer_id: int, maintenance_type: MaintenanceType,
|
||||||
|
interval_days: int, description: str = "") -> MaintenanceSchedule:
|
||||||
|
"""
|
||||||
|
Plant regelmäßige Wartungen (Alias für maintenance_manager.schedule_maintenance).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
printer_id: ID des Druckers
|
||||||
|
maintenance_type: Art der Wartung
|
||||||
|
interval_days: Intervall in Tagen
|
||||||
|
description: Beschreibung
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
MaintenanceSchedule: Erstellter Wartungsplan
|
||||||
|
"""
|
||||||
|
return maintenance_manager.schedule_maintenance(
|
||||||
|
printer_id=printer_id,
|
||||||
|
maintenance_type=maintenance_type,
|
||||||
|
interval_days=interval_days,
|
||||||
|
description=description
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_maintenance_overview() -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Holt eine Übersicht aller Wartungsaktivitäten.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict: Wartungsübersicht mit Statistiken und anstehenden Aufgaben
|
||||||
|
"""
|
||||||
|
upcoming = maintenance_manager.get_upcoming_maintenance()
|
||||||
|
overdue = maintenance_manager.get_overdue_tasks()
|
||||||
|
metrics = maintenance_manager.get_maintenance_metrics()
|
||||||
|
|
||||||
|
# Aktive Tasks
|
||||||
|
active_tasks = [task for task in maintenance_manager.tasks.values()
|
||||||
|
if task.status == MaintenanceStatus.IN_PROGRESS]
|
||||||
|
|
||||||
|
# Completed tasks in last 30 days
|
||||||
|
thirty_days_ago = datetime.now() - timedelta(days=30)
|
||||||
|
recent_completed = [task for task in maintenance_manager.maintenance_history
|
||||||
|
if task.completed_at and task.completed_at >= thirty_days_ago]
|
||||||
|
|
||||||
|
return {
|
||||||
|
'summary': {
|
||||||
|
'total_tasks': len(maintenance_manager.tasks),
|
||||||
|
'active_tasks': len(active_tasks),
|
||||||
|
'upcoming_tasks': len(upcoming),
|
||||||
|
'overdue_tasks': len(overdue),
|
||||||
|
'completed_this_month': len(recent_completed)
|
||||||
|
},
|
||||||
|
'upcoming_tasks': [asdict(task) for task in upcoming[:10]],
|
||||||
|
'overdue_tasks': [asdict(task) for task in overdue],
|
||||||
|
'active_tasks': [asdict(task) for task in active_tasks],
|
||||||
|
'recent_completed': [asdict(task) for task in recent_completed[:5]],
|
||||||
|
'metrics': asdict(metrics),
|
||||||
|
'schedules': {
|
||||||
|
printer_id: [asdict(schedule) for schedule in schedules]
|
||||||
|
for printer_id, schedules in maintenance_manager.schedules.items()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def update_maintenance_status(task_id: int, new_status: MaintenanceStatus,
|
||||||
|
notes: str = "") -> bool:
|
||||||
|
"""
|
||||||
|
Aktualisiert den Status einer Wartungsaufgabe (Alias für maintenance_manager.update_task_status).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
task_id: ID der Wartungsaufgabe
|
||||||
|
new_status: Neuer Status
|
||||||
|
notes: Optionale Notizen
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True wenn erfolgreich aktualisiert
|
||||||
|
"""
|
||||||
|
return maintenance_manager.update_task_status(task_id, new_status, notes)
|
@ -520,23 +520,138 @@ class MultiLocationManager:
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Globale Instanz
|
# Globale Instanz
|
||||||
multi_location_manager = MultiLocationManager()
|
location_manager = MultiLocationManager()
|
||||||
|
|
||||||
|
# Alias für Import-Kompatibilität
|
||||||
|
LocationManager = MultiLocationManager
|
||||||
|
|
||||||
|
def create_location(name: str, code: str, location_type: LocationType = LocationType.BRANCH,
|
||||||
|
address: str = "", city: str = "", country: str = "",
|
||||||
|
parent_id: Optional[int] = None) -> int:
|
||||||
|
"""
|
||||||
|
Erstellt einen neuen Standort (globale Funktion).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: Name des Standorts
|
||||||
|
code: Kurzer Code für den Standort
|
||||||
|
location_type: Art des Standorts
|
||||||
|
address: Adresse
|
||||||
|
city: Stadt
|
||||||
|
country: Land
|
||||||
|
parent_id: Parent-Standort ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: ID des erstellten Standorts
|
||||||
|
"""
|
||||||
|
location = Location(
|
||||||
|
name=name,
|
||||||
|
code=code,
|
||||||
|
location_type=location_type,
|
||||||
|
address=address,
|
||||||
|
city=city,
|
||||||
|
country=country,
|
||||||
|
parent_id=parent_id
|
||||||
|
)
|
||||||
|
|
||||||
|
return location_manager.create_location(location)
|
||||||
|
|
||||||
|
def assign_user_to_location(user_id: int, location_id: int,
|
||||||
|
access_level: AccessLevel = AccessLevel.READ_WRITE,
|
||||||
|
granted_by: int = 1, is_primary: bool = False) -> bool:
|
||||||
|
"""
|
||||||
|
Weist einen Benutzer einem Standort zu.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id: ID des Benutzers
|
||||||
|
location_id: ID des Standorts
|
||||||
|
access_level: Zugriffslevel
|
||||||
|
granted_by: ID des gewährenden Benutzers
|
||||||
|
is_primary: Ob dies der primäre Standort ist
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True wenn erfolgreich
|
||||||
|
"""
|
||||||
|
return location_manager.grant_location_access(
|
||||||
|
user_id=user_id,
|
||||||
|
location_id=location_id,
|
||||||
|
access_level=access_level,
|
||||||
|
granted_by=granted_by,
|
||||||
|
is_primary=is_primary
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_user_locations(user_id: int) -> List[Location]:
|
||||||
|
"""
|
||||||
|
Holt alle Standorte eines Benutzers (globale Funktion).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id: ID des Benutzers
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[Location]: Liste der zugänglichen Standorte
|
||||||
|
"""
|
||||||
|
return location_manager.get_user_locations(user_id)
|
||||||
|
|
||||||
|
def calculate_distance(lat1: float, lon1: float, lat2: float, lon2: float) -> float:
|
||||||
|
"""
|
||||||
|
Berechnet die Entfernung zwischen zwei Koordinaten (Haversine-Formel).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lat1, lon1: Koordinaten des ersten Punkts
|
||||||
|
lat2, lon2: Koordinaten des zweiten Punkts
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float: Entfernung in Kilometern
|
||||||
|
"""
|
||||||
|
from math import radians, sin, cos, sqrt, atan2
|
||||||
|
|
||||||
|
R = 6371 # Erdradius in km
|
||||||
|
|
||||||
|
lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])
|
||||||
|
dlat = lat2 - lat1
|
||||||
|
dlon = lon2 - lon1
|
||||||
|
|
||||||
|
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
|
||||||
|
c = 2 * atan2(sqrt(a), sqrt(1-a))
|
||||||
|
|
||||||
|
return R * c
|
||||||
|
|
||||||
|
def find_nearest_location(latitude: float, longitude: float,
|
||||||
|
radius_km: float = 50) -> Optional[Location]:
|
||||||
|
"""
|
||||||
|
Findet den nächstgelegenen Standort.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
latitude: Breitengrad
|
||||||
|
longitude: Längengrad
|
||||||
|
radius_km: Suchradius in Kilometern
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Optional[Location]: Nächstgelegener Standort oder None
|
||||||
|
"""
|
||||||
|
nearest_locations = location_manager.find_nearest_locations(
|
||||||
|
latitude=latitude,
|
||||||
|
longitude=longitude,
|
||||||
|
radius_km=radius_km,
|
||||||
|
limit=1
|
||||||
|
)
|
||||||
|
|
||||||
|
return nearest_locations[0][0] if nearest_locations else None
|
||||||
|
|
||||||
def get_location_dashboard_data(user_id: int) -> Dict[str, Any]:
|
def get_location_dashboard_data(user_id: int) -> Dict[str, Any]:
|
||||||
"""Holt Dashboard-Daten für Standorte eines Benutzers"""
|
"""Holt Dashboard-Daten für Standorte eines Benutzers"""
|
||||||
user_locations = multi_location_manager.get_user_locations(user_id)
|
user_locations = location_manager.get_user_locations(user_id)
|
||||||
primary_location = multi_location_manager.get_user_primary_location(user_id)
|
primary_location = location_manager.get_user_primary_location(user_id)
|
||||||
|
|
||||||
dashboard_data = {
|
dashboard_data = {
|
||||||
'user_locations': [asdict(loc) for loc in user_locations],
|
'user_locations': [asdict(loc) for loc in user_locations],
|
||||||
'primary_location': asdict(primary_location) if primary_location else None,
|
'primary_location': asdict(primary_location) if primary_location else None,
|
||||||
'location_count': len(user_locations),
|
'location_count': len(user_locations),
|
||||||
'hierarchy': multi_location_manager.get_location_hierarchy()
|
'hierarchy': location_manager.get_location_hierarchy()
|
||||||
}
|
}
|
||||||
|
|
||||||
# Füge Statistiken für jeden Standort hinzu
|
# Füge Statistiken für jeden Standort hinzu
|
||||||
for location in user_locations:
|
for location in user_locations:
|
||||||
location_stats = multi_location_manager.get_location_statistics(location.id)
|
location_stats = location_manager.get_location_statistics(location.id)
|
||||||
dashboard_data[f'stats_{location.id}'] = location_stats
|
dashboard_data[f'stats_{location.id}'] = location_stats
|
||||||
|
|
||||||
return dashboard_data
|
return dashboard_data
|
||||||
@ -553,7 +668,7 @@ def create_location_from_address(name: str, address: str, city: str,
|
|||||||
country=country
|
country=country
|
||||||
)
|
)
|
||||||
|
|
||||||
return multi_location_manager.create_location(location)
|
return location_manager.create_location(location)
|
||||||
|
|
||||||
# JavaScript für Multi-Location Frontend
|
# JavaScript für Multi-Location Frontend
|
||||||
def get_multi_location_javascript() -> str:
|
def get_multi_location_javascript() -> str:
|
||||||
|
@ -43,6 +43,7 @@ class Permission(Enum):
|
|||||||
EXTEND_JOB = "extend_job"
|
EXTEND_JOB = "extend_job"
|
||||||
CANCEL_JOB = "cancel_job"
|
CANCEL_JOB = "cancel_job"
|
||||||
VIEW_JOB_HISTORY = "view_job_history"
|
VIEW_JOB_HISTORY = "view_job_history"
|
||||||
|
APPROVE_JOBS = "approve_jobs" # Berechtigung zum Genehmigen und Verwalten von Jobs
|
||||||
|
|
||||||
# Benutzer-Berechtigungen
|
# Benutzer-Berechtigungen
|
||||||
VIEW_USERS = "view_users"
|
VIEW_USERS = "view_users"
|
||||||
@ -59,6 +60,7 @@ class Permission(Enum):
|
|||||||
EXPORT_DATA = "export_data"
|
EXPORT_DATA = "export_data"
|
||||||
BACKUP_DATABASE = "backup_database"
|
BACKUP_DATABASE = "backup_database"
|
||||||
MANAGE_SETTINGS = "manage_settings"
|
MANAGE_SETTINGS = "manage_settings"
|
||||||
|
ADMIN = "admin" # Allgemeine Admin-Berechtigung für administrative Funktionen
|
||||||
|
|
||||||
# Gast-Berechtigungen
|
# Gast-Berechtigungen
|
||||||
VIEW_GUEST_REQUESTS = "view_guest_requests"
|
VIEW_GUEST_REQUESTS = "view_guest_requests"
|
||||||
@ -149,6 +151,7 @@ ROLE_PERMISSIONS[Role.SUPERVISOR] = ROLE_PERMISSIONS[Role.TECHNICIAN] | {
|
|||||||
Permission.MANAGE_GUEST_REQUESTS,
|
Permission.MANAGE_GUEST_REQUESTS,
|
||||||
Permission.MANAGE_SHIFTS,
|
Permission.MANAGE_SHIFTS,
|
||||||
Permission.VIEW_USER_DETAILS,
|
Permission.VIEW_USER_DETAILS,
|
||||||
|
Permission.APPROVE_JOBS, # Jobs genehmigen und verwalten
|
||||||
}
|
}
|
||||||
|
|
||||||
# Admin erweitert Supervisor-Permissions
|
# Admin erweitert Supervisor-Permissions
|
||||||
@ -161,6 +164,7 @@ ROLE_PERMISSIONS[Role.ADMIN] = ROLE_PERMISSIONS[Role.SUPERVISOR] | {
|
|||||||
Permission.EXPORT_DATA,
|
Permission.EXPORT_DATA,
|
||||||
Permission.VIEW_LOGS,
|
Permission.VIEW_LOGS,
|
||||||
Permission.MANAGE_SETTINGS,
|
Permission.MANAGE_SETTINGS,
|
||||||
|
Permission.ADMIN, # Allgemeine Admin-Berechtigung hinzufügen
|
||||||
}
|
}
|
||||||
|
|
||||||
# Super Admin hat alle Berechtigungen
|
# Super Admin hat alle Berechtigungen
|
||||||
|
@ -25,12 +25,28 @@ from concurrent.futures import ThreadPoolExecutor
|
|||||||
# WebSocket-Support
|
# WebSocket-Support
|
||||||
try:
|
try:
|
||||||
from flask_socketio import SocketIO, emit, join_room, leave_room, disconnect
|
from flask_socketio import SocketIO, emit, join_room, leave_room, disconnect
|
||||||
from eventlet import wsgi, listen
|
# Eventlet separat importieren für bessere Fehlerbehandlung
|
||||||
import eventlet
|
try:
|
||||||
|
from eventlet import wsgi, listen
|
||||||
|
import eventlet
|
||||||
|
EVENTLET_AVAILABLE = True
|
||||||
|
except (ImportError, AttributeError) as e:
|
||||||
|
# Eventlet nicht verfügbar oder nicht kompatibel (z.B. Python 3.13)
|
||||||
|
print(f"⚠️ Eventlet nicht verfügbar: {e}")
|
||||||
|
print("🔄 Fallback auf standard threading mode für WebSocket")
|
||||||
|
EVENTLET_AVAILABLE = False
|
||||||
|
eventlet = None
|
||||||
|
wsgi = None
|
||||||
|
listen = None
|
||||||
|
|
||||||
WEBSOCKET_AVAILABLE = True
|
WEBSOCKET_AVAILABLE = True
|
||||||
except ImportError:
|
except ImportError as e:
|
||||||
|
print(f"⚠️ Flask-SocketIO nicht verfügbar: {e}")
|
||||||
|
print("📡 Dashboard läuft ohne Real-time Updates")
|
||||||
WEBSOCKET_AVAILABLE = False
|
WEBSOCKET_AVAILABLE = False
|
||||||
|
EVENTLET_AVAILABLE = False
|
||||||
SocketIO = None
|
SocketIO = None
|
||||||
|
eventlet = None
|
||||||
|
|
||||||
from flask import request, session, current_app
|
from flask import request, session, current_app
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
@ -122,16 +138,24 @@ class DashboardManager:
|
|||||||
logger.warning("WebSocket-Funktionalität nicht verfügbar. Flask-SocketIO installieren.")
|
logger.warning("WebSocket-Funktionalität nicht verfügbar. Flask-SocketIO installieren.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# Bestimme den async_mode basierend auf verfügbaren Bibliotheken
|
||||||
|
if EVENTLET_AVAILABLE:
|
||||||
|
async_mode = 'eventlet'
|
||||||
|
logger.info("Dashboard WebSocket-Server wird mit eventlet initialisiert")
|
||||||
|
else:
|
||||||
|
async_mode = 'threading'
|
||||||
|
logger.info("Dashboard WebSocket-Server wird mit threading initialisiert (eventlet-Fallback)")
|
||||||
|
|
||||||
self.socketio = SocketIO(
|
self.socketio = SocketIO(
|
||||||
app,
|
app,
|
||||||
cors_allowed_origins=cors_allowed_origins,
|
cors_allowed_origins=cors_allowed_origins,
|
||||||
logger=False,
|
logger=False,
|
||||||
engineio_logger=False,
|
engineio_logger=False,
|
||||||
async_mode='eventlet'
|
async_mode=async_mode
|
||||||
)
|
)
|
||||||
|
|
||||||
self._setup_socket_handlers()
|
self._setup_socket_handlers()
|
||||||
logger.info("Dashboard WebSocket-Server initialisiert")
|
logger.info(f"Dashboard WebSocket-Server initialisiert (async_mode: {async_mode})")
|
||||||
return self.socketio
|
return self.socketio
|
||||||
|
|
||||||
def _setup_socket_handlers(self):
|
def _setup_socket_handlers(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user