🎉 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)
|
||||
}), 500
|
||||
|
||||
# ===== INTEGRATION IN BESTEHENDE ROUTEN =====
|
||||
|
||||
# Erweitere bestehende Job-Routen um Dashboard-Events
|
||||
|
||||
@app.route("/api/admin/system-health", methods=['GET'])
|
||||
@app.route("/api/admin/system-health-dashboard", methods=['GET'])
|
||||
@login_required
|
||||
@admin_required
|
||||
def api_admin_system_health():
|
||||
def api_admin_system_health_dashboard():
|
||||
"""API-Endpunkt für System-Gesundheitscheck mit Dashboard-Integration."""
|
||||
try:
|
||||
# Basis-System-Gesundheitscheck durchführen
|
||||
@ -5064,6 +5060,192 @@ def setup_database_with_migrations():
|
||||
app_logger.error(f"❌ Fehler bei Datenbank-Setup: {str(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 =====
|
||||
if __name__ == "__main__":
|
||||
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")
|
||||
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'gcode', '3mf', 'stl'}
|
||||
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
|
||||
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 - ✅ Datenbank-Cleanup abgeschlossen - WAL-Dateien sollten verschwunden sein
|
||||
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:51:08 - myp.scheduler - INFO - Scheduler-Thread beendet
|
||||
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
|
||||
# Installiere mit: pip install -r requirements.txt
|
||||
|
||||
# ===== CORE FLASK FRAMEWORK =====
|
||||
# Direkt in app.py verwendet
|
||||
Flask==3.1.1
|
||||
# ===== CORE FRAMEWORK =====
|
||||
Flask==3.0.0
|
||||
Werkzeug==3.0.1
|
||||
|
||||
# ===== FLASK EXTENSIONS =====
|
||||
Flask-Login==0.6.3
|
||||
Flask-WTF==1.2.1
|
||||
Flask-SocketIO==5.3.6
|
||||
WTForms==3.1.1
|
||||
|
||||
# ===== DATENBANK =====
|
||||
# SQLAlchemy für Datenbankoperationen (models.py, app.py)
|
||||
SQLAlchemy==2.0.36
|
||||
# ===== DATABASE =====
|
||||
SQLAlchemy==2.0.23
|
||||
|
||||
# ===== SICHERHEIT UND AUTHENTIFIZIERUNG =====
|
||||
# Werkzeug für Passwort-Hashing und Utilities (app.py)
|
||||
bcrypt==4.2.1
|
||||
cryptography==44.0.0
|
||||
Werkzeug==3.1.3
|
||||
# ===== SECURITY =====
|
||||
cryptography==41.0.8
|
||||
bcrypt==4.1.2
|
||||
|
||||
# ===== SMART PLUG STEUERUNG =====
|
||||
# PyP100 für TP-Link Tapo Smart Plugs (utils/job_scheduler.py)
|
||||
PyP100
|
||||
# ===== HTTP REQUESTS (für Online-Modus) =====
|
||||
requests==2.31.0
|
||||
urllib3==2.1.0
|
||||
|
||||
# ===== RATE LIMITING UND CACHING =====
|
||||
# Redis für Rate Limiting (utils/rate_limiter.py) - optional
|
||||
redis==5.2.1
|
||||
# ===== HARDWARE INTEGRATION =====
|
||||
# TP-Link Tapo Smart Plugs
|
||||
PyP100==0.1.4
|
||||
|
||||
# ===== HTTP REQUESTS =====
|
||||
# Requests für HTTP-Anfragen (utils/queue_manager.py, utils/debug_drucker_erkennung.py)
|
||||
requests==2.32.3
|
||||
# ===== REAL-TIME FEATURES =====
|
||||
# WebSocket-Support mit Fallback-Optionen
|
||||
eventlet==0.33.3
|
||||
python-socketio==5.10.0
|
||||
|
||||
# ===== TEMPLATE ENGINE =====
|
||||
# Jinja2 und MarkupSafe (automatisch mit Flask installiert, aber explizit für utils/template_helpers.py)
|
||||
MarkupSafe==3.0.2
|
||||
# ===== SCHEDULING & TASK MANAGEMENT =====
|
||||
schedule==1.2.0
|
||||
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 =====
|
||||
# psutil für System-Monitoring (utils/debug_utils.py, utils/debug_cli.py)
|
||||
psutil==6.1.1
|
||||
# System-Überwachung
|
||||
psutil==5.9.6
|
||||
|
||||
# ===== ZUSÄTZLICHE CORE ABHÄNGIGKEITEN =====
|
||||
# Click für CLI-Kommandos (automatisch mit Flask)
|
||||
# Keine Core-Requirements
|
||||
# ===== ERROR TRACKING =====
|
||||
# Fehler-Tracking (optional)
|
||||
# sentry-sdk[flask]==1.38.0
|
||||
|
||||
# ===== WINDOWS-SPEZIFISCHE ABHÄNGIGKEITEN =====
|
||||
# Nur für Windows-Systeme erforderlich
|
||||
# Keine Windows-Requirements
|
||||
|
||||
# ===== 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"
|
||||
# ===== API DOCUMENTATION =====
|
||||
# API-Dokumentation (optional)
|
||||
# flask-restx==1.3.0
|
||||
# flasgger==0.9.7.1
|
||||
|
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;
|
||||
}
|
||||
}
|
||||
"""
|
||||
"""
|
||||
|
||||
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() {
|
||||
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
|
||||
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]:
|
||||
"""Holt Dashboard-Daten für Standorte eines Benutzers"""
|
||||
user_locations = multi_location_manager.get_user_locations(user_id)
|
||||
primary_location = multi_location_manager.get_user_primary_location(user_id)
|
||||
user_locations = location_manager.get_user_locations(user_id)
|
||||
primary_location = location_manager.get_user_primary_location(user_id)
|
||||
|
||||
dashboard_data = {
|
||||
'user_locations': [asdict(loc) for loc in user_locations],
|
||||
'primary_location': asdict(primary_location) if primary_location else None,
|
||||
'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
|
||||
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
|
||||
|
||||
return dashboard_data
|
||||
@ -553,7 +668,7 @@ def create_location_from_address(name: str, address: str, city: str,
|
||||
country=country
|
||||
)
|
||||
|
||||
return multi_location_manager.create_location(location)
|
||||
return location_manager.create_location(location)
|
||||
|
||||
# JavaScript für Multi-Location Frontend
|
||||
def get_multi_location_javascript() -> str:
|
||||
|
@ -43,6 +43,7 @@ class Permission(Enum):
|
||||
EXTEND_JOB = "extend_job"
|
||||
CANCEL_JOB = "cancel_job"
|
||||
VIEW_JOB_HISTORY = "view_job_history"
|
||||
APPROVE_JOBS = "approve_jobs" # Berechtigung zum Genehmigen und Verwalten von Jobs
|
||||
|
||||
# Benutzer-Berechtigungen
|
||||
VIEW_USERS = "view_users"
|
||||
@ -59,6 +60,7 @@ class Permission(Enum):
|
||||
EXPORT_DATA = "export_data"
|
||||
BACKUP_DATABASE = "backup_database"
|
||||
MANAGE_SETTINGS = "manage_settings"
|
||||
ADMIN = "admin" # Allgemeine Admin-Berechtigung für administrative Funktionen
|
||||
|
||||
# Gast-Berechtigungen
|
||||
VIEW_GUEST_REQUESTS = "view_guest_requests"
|
||||
@ -149,6 +151,7 @@ ROLE_PERMISSIONS[Role.SUPERVISOR] = ROLE_PERMISSIONS[Role.TECHNICIAN] | {
|
||||
Permission.MANAGE_GUEST_REQUESTS,
|
||||
Permission.MANAGE_SHIFTS,
|
||||
Permission.VIEW_USER_DETAILS,
|
||||
Permission.APPROVE_JOBS, # Jobs genehmigen und verwalten
|
||||
}
|
||||
|
||||
# Admin erweitert Supervisor-Permissions
|
||||
@ -161,6 +164,7 @@ ROLE_PERMISSIONS[Role.ADMIN] = ROLE_PERMISSIONS[Role.SUPERVISOR] | {
|
||||
Permission.EXPORT_DATA,
|
||||
Permission.VIEW_LOGS,
|
||||
Permission.MANAGE_SETTINGS,
|
||||
Permission.ADMIN, # Allgemeine Admin-Berechtigung hinzufügen
|
||||
}
|
||||
|
||||
# Super Admin hat alle Berechtigungen
|
||||
|
@ -25,12 +25,28 @@ from concurrent.futures import ThreadPoolExecutor
|
||||
# WebSocket-Support
|
||||
try:
|
||||
from flask_socketio import SocketIO, emit, join_room, leave_room, disconnect
|
||||
from eventlet import wsgi, listen
|
||||
import eventlet
|
||||
# Eventlet separat importieren für bessere Fehlerbehandlung
|
||||
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
|
||||
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
|
||||
EVENTLET_AVAILABLE = False
|
||||
SocketIO = None
|
||||
eventlet = None
|
||||
|
||||
from flask import request, session, current_app
|
||||
from flask_login import current_user
|
||||
@ -122,16 +138,24 @@ class DashboardManager:
|
||||
logger.warning("WebSocket-Funktionalität nicht verfügbar. Flask-SocketIO installieren.")
|
||||
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(
|
||||
app,
|
||||
cors_allowed_origins=cors_allowed_origins,
|
||||
logger=False,
|
||||
engineio_logger=False,
|
||||
async_mode='eventlet'
|
||||
async_mode=async_mode
|
||||
)
|
||||
|
||||
self._setup_socket_handlers()
|
||||
logger.info("Dashboard WebSocket-Server initialisiert")
|
||||
logger.info(f"Dashboard WebSocket-Server initialisiert (async_mode: {async_mode})")
|
||||
return self.socketio
|
||||
|
||||
def _setup_socket_handlers(self):
|
||||
|
Loading…
x
Reference in New Issue
Block a user