🎉 Refactor backend files & add documentation 📚, remove legacy installer scripts. #123
This commit is contained in:
parent
9e1719df4d
commit
7f38f8a7e5
530
backend/app.py
530
backend/app.py
@ -1595,7 +1595,44 @@ def admin():
|
|||||||
flash("Nur Administratoren haben Zugriff auf diesen Bereich.", "error")
|
flash("Nur Administratoren haben Zugriff auf diesen Bereich.", "error")
|
||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
return render_template("admin.html")
|
# Daten für das Template sammeln (gleiche Logik wie admin-dashboard)
|
||||||
|
db_session = get_db_session()
|
||||||
|
try:
|
||||||
|
# Statistiken sammeln
|
||||||
|
stats = {
|
||||||
|
'total_users': db_session.query(User).count(),
|
||||||
|
'total_printers': db_session.query(Printer).count(),
|
||||||
|
'online_printers': db_session.query(Printer).filter(Printer.status == 'online').count(),
|
||||||
|
'active_jobs': db_session.query(Job).filter(Job.status.in_(['running', 'queued'])).count(),
|
||||||
|
'queued_jobs': db_session.query(Job).filter(Job.status == 'queued').count(),
|
||||||
|
'success_rate': 85 # Placeholder - könnte aus echten Daten berechnet werden
|
||||||
|
}
|
||||||
|
|
||||||
|
# Tab-Parameter
|
||||||
|
active_tab = request.args.get('tab', 'users')
|
||||||
|
|
||||||
|
# Benutzer laden (für users tab)
|
||||||
|
users = []
|
||||||
|
if active_tab == 'users':
|
||||||
|
users = db_session.query(User).all()
|
||||||
|
|
||||||
|
# Drucker laden (für printers tab)
|
||||||
|
printers = []
|
||||||
|
if active_tab == 'printers':
|
||||||
|
printers = db_session.query(Printer).all()
|
||||||
|
|
||||||
|
db_session.close()
|
||||||
|
|
||||||
|
return render_template("admin.html",
|
||||||
|
stats=stats,
|
||||||
|
active_tab=active_tab,
|
||||||
|
users=users,
|
||||||
|
printers=printers)
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Laden der Admin-Daten: {str(e)}")
|
||||||
|
db_session.close()
|
||||||
|
flash("Fehler beim Laden des Admin-Bereichs.", "error")
|
||||||
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
@app.route("/socket-test")
|
@app.route("/socket-test")
|
||||||
@login_required
|
@login_required
|
||||||
@ -1643,7 +1680,68 @@ def admin_page():
|
|||||||
"""Erweiterte Admin-Dashboard-Seite mit Live-Funktionen"""
|
"""Erweiterte Admin-Dashboard-Seite mit Live-Funktionen"""
|
||||||
if not current_user.is_admin:
|
if not current_user.is_admin:
|
||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
return render_template("admin_dashboard.html", title="Admin Dashboard")
|
|
||||||
|
# Daten für das Template sammeln
|
||||||
|
db_session = get_db_session()
|
||||||
|
try:
|
||||||
|
# Statistiken sammeln
|
||||||
|
stats = {
|
||||||
|
'total_users': db_session.query(User).count(),
|
||||||
|
'total_printers': db_session.query(Printer).count(),
|
||||||
|
'online_printers': db_session.query(Printer).filter(Printer.status == 'online').count(),
|
||||||
|
'active_jobs': db_session.query(Job).filter(Job.status.in_(['running', 'queued'])).count(),
|
||||||
|
'queued_jobs': db_session.query(Job).filter(Job.status == 'queued').count(),
|
||||||
|
'success_rate': 85 # Placeholder - könnte aus echten Daten berechnet werden
|
||||||
|
}
|
||||||
|
|
||||||
|
# Tab-Parameter
|
||||||
|
active_tab = request.args.get('tab', 'users')
|
||||||
|
|
||||||
|
# Benutzer laden (für users tab)
|
||||||
|
users = []
|
||||||
|
if active_tab == 'users':
|
||||||
|
users = db_session.query(User).all()
|
||||||
|
|
||||||
|
# Drucker laden (für printers tab)
|
||||||
|
printers = []
|
||||||
|
if active_tab == 'printers':
|
||||||
|
printers = db_session.query(Printer).all()
|
||||||
|
|
||||||
|
db_session.close()
|
||||||
|
|
||||||
|
return render_template("admin.html",
|
||||||
|
title="Admin Dashboard",
|
||||||
|
stats=stats,
|
||||||
|
active_tab=active_tab,
|
||||||
|
users=users,
|
||||||
|
printers=printers)
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Laden der Admin-Dashboard-Daten: {str(e)}")
|
||||||
|
db_session.close()
|
||||||
|
flash("Fehler beim Laden des Admin-Dashboards.", "error")
|
||||||
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
|
# ===== RECHTLICHE SEITEN =====
|
||||||
|
|
||||||
|
@app.route("/privacy")
|
||||||
|
def privacy():
|
||||||
|
"""Datenschutzerklärung-Seite"""
|
||||||
|
return render_template("privacy.html", title="Datenschutzerklärung")
|
||||||
|
|
||||||
|
@app.route("/terms")
|
||||||
|
def terms():
|
||||||
|
"""Nutzungsbedingungen-Seite"""
|
||||||
|
return render_template("terms.html", title="Nutzungsbedingungen")
|
||||||
|
|
||||||
|
@app.route("/imprint")
|
||||||
|
def imprint():
|
||||||
|
"""Impressum-Seite"""
|
||||||
|
return render_template("imprint.html", title="Impressum")
|
||||||
|
|
||||||
|
@app.route("/legal")
|
||||||
|
def legal():
|
||||||
|
"""Rechtliche Hinweise-Übersichtsseite"""
|
||||||
|
return render_template("legal.html", title="Rechtliche Hinweise")
|
||||||
|
|
||||||
# ===== NEUE SYSTEM UI-ROUTEN =====
|
# ===== NEUE SYSTEM UI-ROUTEN =====
|
||||||
|
|
||||||
@ -5060,190 +5158,282 @@ 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 =====
|
# ===== LOG-MANAGEMENT API =====
|
||||||
|
|
||||||
@app.route("/privacy")
|
@app.route("/api/logs", methods=['GET'])
|
||||||
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
|
@login_required
|
||||||
def accept_privacy_policy():
|
@admin_required
|
||||||
"""API-Endpunkt für Akzeptierung der Datenschutzerklärung"""
|
def api_logs():
|
||||||
db_session = get_db_session()
|
"""
|
||||||
|
API-Endpunkt für Log-Daten-Abruf
|
||||||
|
|
||||||
|
Query Parameter:
|
||||||
|
level: Log-Level Filter (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
||||||
|
limit: Anzahl der Einträge (Standard: 100, Max: 1000)
|
||||||
|
offset: Offset für Paginierung (Standard: 0)
|
||||||
|
search: Suchbegriff für Log-Nachrichten
|
||||||
|
start_date: Start-Datum (ISO-Format)
|
||||||
|
end_date: End-Datum (ISO-Format)
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
data = request.get_json() or {}
|
# Parameter aus Query-String extrahieren
|
||||||
version = data.get("version", "1.0")
|
level = request.args.get('level', '').upper()
|
||||||
|
limit = min(int(request.args.get('limit', 100)), 1000)
|
||||||
|
offset = int(request.args.get('offset', 0))
|
||||||
|
search = request.args.get('search', '').strip()
|
||||||
|
start_date = request.args.get('start_date')
|
||||||
|
end_date = request.args.get('end_date')
|
||||||
|
|
||||||
# Benutzer aus der Datenbank laden
|
# Log-Dateien aus dem logs-Verzeichnis lesen
|
||||||
user = db_session.query(User).filter(User.id == int(current_user.id)).first()
|
import os
|
||||||
|
import glob
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
if not user:
|
logs_dir = os.path.join(os.path.dirname(__file__), 'logs')
|
||||||
return jsonify({"error": "Benutzer nicht gefunden"}), 404
|
log_entries = []
|
||||||
|
|
||||||
# Privacy-Akzeptierung in Benutzer-Einstellungen speichern
|
if os.path.exists(logs_dir):
|
||||||
if hasattr(user, 'settings'):
|
# Alle .log Dateien finden
|
||||||
import json
|
log_files = glob.glob(os.path.join(logs_dir, '*.log'))
|
||||||
settings = json.loads(user.settings) if user.settings else {}
|
log_files.sort(key=os.path.getmtime, reverse=True) # Neueste zuerst
|
||||||
else:
|
|
||||||
settings = session.get('user_settings', {})
|
|
||||||
|
|
||||||
# Privacy-Akzeptierung hinzufügen
|
# Datum-Filter vorbereiten
|
||||||
if 'privacy_acceptance' not in settings:
|
start_dt = None
|
||||||
settings['privacy_acceptance'] = {}
|
end_dt = None
|
||||||
|
if start_date:
|
||||||
|
try:
|
||||||
|
start_dt = datetime.fromisoformat(start_date.replace('Z', '+00:00'))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if end_date:
|
||||||
|
try:
|
||||||
|
end_dt = datetime.fromisoformat(end_date.replace('Z', '+00:00'))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
settings['privacy_acceptance'] = {
|
# Log-Dateien durchgehen (maximal die letzten 5 Dateien)
|
||||||
'accepted': True,
|
for log_file in log_files[:5]:
|
||||||
'version': version,
|
try:
|
||||||
'timestamp': datetime.now().isoformat(),
|
with open(log_file, 'r', encoding='utf-8') as f:
|
||||||
'ip_address': request.remote_addr
|
lines = f.readlines()
|
||||||
}
|
|
||||||
|
|
||||||
# Einstellungen speichern
|
# Zeilen rückwärts durchgehen (neueste zuerst)
|
||||||
if hasattr(user, 'settings'):
|
for line in reversed(lines):
|
||||||
user.settings = json.dumps(settings)
|
line = line.strip()
|
||||||
user.updated_at = datetime.now()
|
if not line:
|
||||||
db_session.commit()
|
continue
|
||||||
else:
|
|
||||||
session['user_settings'] = settings
|
|
||||||
|
|
||||||
user_logger.info(f"Benutzer {current_user.username} hat Datenschutzerklärung v{version} akzeptiert")
|
# Log-Zeile parsen
|
||||||
|
try:
|
||||||
|
# Format: 2025-06-01 00:34:08 - logger_name - [LEVEL] MESSAGE
|
||||||
|
parts = line.split(' - ', 3)
|
||||||
|
if len(parts) >= 4:
|
||||||
|
timestamp_str = parts[0]
|
||||||
|
logger_name = parts[1]
|
||||||
|
level_part = parts[2]
|
||||||
|
message = parts[3]
|
||||||
|
|
||||||
|
# Level extrahieren
|
||||||
|
if level_part.startswith('[') and ']' in level_part:
|
||||||
|
log_level = level_part.split(']')[0][1:]
|
||||||
|
else:
|
||||||
|
log_level = 'INFO'
|
||||||
|
|
||||||
|
# Timestamp parsen
|
||||||
|
try:
|
||||||
|
log_timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S')
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Filter anwenden
|
||||||
|
if level and log_level != level:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if start_dt and log_timestamp < start_dt:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if end_dt and log_timestamp > end_dt:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if search and search.lower() not in message.lower():
|
||||||
|
continue
|
||||||
|
|
||||||
|
log_entries.append({
|
||||||
|
'timestamp': log_timestamp.isoformat(),
|
||||||
|
'level': log_level,
|
||||||
|
'logger': logger_name,
|
||||||
|
'message': message,
|
||||||
|
'file': os.path.basename(log_file)
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as parse_error:
|
||||||
|
# Fehlerhafte Zeile überspringen
|
||||||
|
continue
|
||||||
|
|
||||||
|
except Exception as file_error:
|
||||||
|
app_logger.error(f"Fehler beim Lesen der Log-Datei {log_file}: {str(file_error)}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Sortieren nach Timestamp (neueste zuerst)
|
||||||
|
log_entries.sort(key=lambda x: x['timestamp'], reverse=True)
|
||||||
|
|
||||||
|
# Paginierung anwenden
|
||||||
|
total_count = len(log_entries)
|
||||||
|
paginated_entries = log_entries[offset:offset + limit]
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"success": True,
|
'success': True,
|
||||||
"message": "Datenschutzerklärung erfolgreich akzeptiert",
|
'logs': paginated_entries,
|
||||||
"version": version,
|
'pagination': {
|
||||||
"timestamp": datetime.now().isoformat()
|
'total': total_count,
|
||||||
})
|
'limit': limit,
|
||||||
|
'offset': offset,
|
||||||
except Exception as e:
|
'has_more': offset + limit < total_count
|
||||||
db_session.rollback()
|
},
|
||||||
app_logger.error(f"Fehler bei Privacy-Akzeptierung: {str(e)}")
|
'filters': {
|
||||||
return jsonify({"error": "Interner Serverfehler"}), 500
|
'level': level or None,
|
||||||
finally:
|
'search': search or None,
|
||||||
db_session.close()
|
'start_date': start_date,
|
||||||
|
'end_date': end_date
|
||||||
@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:
|
except Exception as e:
|
||||||
app_logger.error(f"Fehler bei Legal-Status-Abfrage: {str(e)}")
|
app_logger.error(f"Fehler beim Abrufen der Log-Daten: {str(e)}")
|
||||||
return jsonify({"error": "Interner Serverfehler"}), 500
|
return jsonify({
|
||||||
|
'error': f'Fehler beim Abrufen der Log-Daten: {str(e)}'
|
||||||
|
}), 500
|
||||||
|
|
||||||
|
# ===== LIVE ADMIN STATISTIKEN API =====
|
||||||
|
|
||||||
|
@app.route("/api/admin/stats/live", methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
@admin_required
|
||||||
|
def api_admin_stats_live():
|
||||||
|
"""
|
||||||
|
API-Endpunkt für Live-Statistiken im Admin-Dashboard
|
||||||
|
|
||||||
|
Liefert aktuelle System-Statistiken für Echtzeit-Updates
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
db_session = get_db_session()
|
||||||
|
|
||||||
|
# Basis-Statistiken sammeln
|
||||||
|
stats = {
|
||||||
|
'timestamp': datetime.now().isoformat(),
|
||||||
|
'users': {
|
||||||
|
'total': db_session.query(User).count(),
|
||||||
|
'active_today': db_session.query(User).filter(
|
||||||
|
User.last_login >= datetime.now() - timedelta(days=1)
|
||||||
|
).count() if hasattr(User, 'last_login') else 0,
|
||||||
|
'new_this_week': db_session.query(User).filter(
|
||||||
|
User.created_at >= datetime.now() - timedelta(days=7)
|
||||||
|
).count() if hasattr(User, 'created_at') else 0
|
||||||
|
},
|
||||||
|
'printers': {
|
||||||
|
'total': db_session.query(Printer).count(),
|
||||||
|
'online': db_session.query(Printer).filter(Printer.status == 'online').count(),
|
||||||
|
'offline': db_session.query(Printer).filter(Printer.status == 'offline').count(),
|
||||||
|
'maintenance': db_session.query(Printer).filter(Printer.status == 'maintenance').count()
|
||||||
|
},
|
||||||
|
'jobs': {
|
||||||
|
'total': db_session.query(Job).count(),
|
||||||
|
'running': db_session.query(Job).filter(Job.status == 'running').count(),
|
||||||
|
'queued': db_session.query(Job).filter(Job.status == 'queued').count(),
|
||||||
|
'completed_today': db_session.query(Job).filter(
|
||||||
|
Job.status == 'completed',
|
||||||
|
Job.updated_at >= datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
).count() if hasattr(Job, 'updated_at') else 0,
|
||||||
|
'failed_today': db_session.query(Job).filter(
|
||||||
|
Job.status == 'failed',
|
||||||
|
Job.updated_at >= datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
).count() if hasattr(Job, 'updated_at') else 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# System-Performance-Metriken
|
||||||
|
import psutil
|
||||||
|
import os
|
||||||
|
|
||||||
|
# CPU und Memory
|
||||||
|
stats['system'] = {
|
||||||
|
'cpu_percent': psutil.cpu_percent(interval=1),
|
||||||
|
'memory_percent': psutil.virtual_memory().percent,
|
||||||
|
'disk_percent': psutil.disk_usage('/').percent if os.name != 'nt' else psutil.disk_usage('C:\\').percent,
|
||||||
|
'uptime_seconds': int((datetime.now() - datetime.fromtimestamp(psutil.boot_time())).total_seconds())
|
||||||
|
}
|
||||||
|
|
||||||
|
# Erfolgsrate berechnen (letzte 24 Stunden)
|
||||||
|
try:
|
||||||
|
completed_jobs = db_session.query(Job).filter(
|
||||||
|
Job.status == 'completed',
|
||||||
|
Job.updated_at >= datetime.now() - timedelta(days=1)
|
||||||
|
).count() if hasattr(Job, 'updated_at') else 0
|
||||||
|
|
||||||
|
failed_jobs = db_session.query(Job).filter(
|
||||||
|
Job.status == 'failed',
|
||||||
|
Job.updated_at >= datetime.now() - timedelta(days=1)
|
||||||
|
).count() if hasattr(Job, 'updated_at') else 0
|
||||||
|
|
||||||
|
total_finished = completed_jobs + failed_jobs
|
||||||
|
success_rate = (completed_jobs / total_finished * 100) if total_finished > 0 else 100
|
||||||
|
|
||||||
|
stats['performance'] = {
|
||||||
|
'success_rate': round(success_rate, 1),
|
||||||
|
'completed_24h': completed_jobs,
|
||||||
|
'failed_24h': failed_jobs,
|
||||||
|
'total_finished_24h': total_finished
|
||||||
|
}
|
||||||
|
except Exception as perf_error:
|
||||||
|
app_logger.warning(f"Fehler bei Performance-Berechnung: {str(perf_error)}")
|
||||||
|
stats['performance'] = {
|
||||||
|
'success_rate': 0,
|
||||||
|
'completed_24h': 0,
|
||||||
|
'failed_24h': 0,
|
||||||
|
'total_finished_24h': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Queue-Status (falls Queue Manager läuft)
|
||||||
|
try:
|
||||||
|
from queue_manager import get_queue_status
|
||||||
|
queue_status = get_queue_status()
|
||||||
|
stats['queue'] = queue_status
|
||||||
|
except Exception as queue_error:
|
||||||
|
stats['queue'] = {
|
||||||
|
'status': 'unknown',
|
||||||
|
'pending_jobs': 0,
|
||||||
|
'active_workers': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Letzte Aktivitäten (Top 5)
|
||||||
|
try:
|
||||||
|
recent_jobs = db_session.query(Job).order_by(Job.id.desc()).limit(5).all()
|
||||||
|
stats['recent_activity'] = [
|
||||||
|
{
|
||||||
|
'id': job.id,
|
||||||
|
'filename': job.filename,
|
||||||
|
'status': job.status,
|
||||||
|
'user': job.user.username if job.user else 'Unbekannt',
|
||||||
|
'created_at': job.created_at.isoformat() if hasattr(job, 'created_at') and job.created_at else None
|
||||||
|
}
|
||||||
|
for job in recent_jobs
|
||||||
|
]
|
||||||
|
except Exception as activity_error:
|
||||||
|
app_logger.warning(f"Fehler bei Recent Activity: {str(activity_error)}")
|
||||||
|
stats['recent_activity'] = []
|
||||||
|
|
||||||
|
db_session.close()
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'success': True,
|
||||||
|
'stats': stats
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
app_logger.error(f"Fehler beim Abrufen der Live-Statistiken: {str(e)}")
|
||||||
|
return jsonify({
|
||||||
|
'error': f'Fehler beim Abrufen der Live-Statistiken: {str(e)}'
|
||||||
|
}), 500
|
||||||
|
|
||||||
|
|
||||||
# ===== STARTUP UND MAIN =====
|
# ===== STARTUP UND MAIN =====
|
||||||
|
Binary file not shown.
Binary file not shown.
1
backend/docs/README_Legal_Pages.md
Normal file
1
backend/docs/README_Legal_Pages.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -1714,3 +1714,17 @@ information about how to avoid this problem.
|
|||||||
2025-05-31 23:21:32 - myp.app - ERROR - Fehler beim System-Gesundheitscheck: argument 1 (impossible<bad format char>)
|
2025-05-31 23:21:32 - myp.app - ERROR - Fehler beim System-Gesundheitscheck: argument 1 (impossible<bad format char>)
|
||||||
2025-05-31 23:21:33 - myp.app - ERROR - Fehler beim Laden der Admin-Daten: 'charmap' codec can't decode byte 0x9d in position 2106: character maps to <undefined>
|
2025-05-31 23:21:33 - myp.app - ERROR - Fehler beim Laden der Admin-Daten: 'charmap' codec can't decode byte 0x9d in position 2106: character maps to <undefined>
|
||||||
2025-05-31 23:21:34 - myp.app - ERROR - Fehler beim System-Gesundheitscheck: argument 1 (impossible<bad format char>)
|
2025-05-31 23:21:34 - myp.app - ERROR - Fehler beim System-Gesundheitscheck: argument 1 (impossible<bad format char>)
|
||||||
|
2025-06-01 00:29:13 - myp.app - ERROR - ❌ Fehler beim Datenbank-Cleanup: (sqlite3.OperationalError) database is locked
|
||||||
|
[SQL: PRAGMA journal_mode=DELETE]
|
||||||
|
(Background on this error at: https://sqlalche.me/e/20/e3q8)
|
||||||
|
2025-06-01 00:30:54 - myp.app - ERROR - ❌ Fehler beim Datenbank-Cleanup: (sqlite3.OperationalError) database is locked
|
||||||
|
[SQL: PRAGMA journal_mode=DELETE]
|
||||||
|
(Background on this error at: https://sqlalche.me/e/20/e3q8)
|
||||||
|
2025-06-01 00:35:32 - myp.app - ERROR - ❌ Fehler beim Datenbank-Cleanup: (sqlite3.OperationalError) database is locked
|
||||||
|
[SQL: PRAGMA journal_mode=DELETE]
|
||||||
|
(Background on this error at: https://sqlalche.me/e/20/e3q8)
|
||||||
|
2025-06-01 00:35:56 - myp.app - ERROR - Fehler beim Abrufen der Live-Statistiken: argument 1 (impossible<bad format char>)
|
||||||
|
2025-06-01 00:36:06 - myp.app - ERROR - Fehler beim Abrufen der Live-Statistiken: argument 1 (impossible<bad format char>)
|
||||||
|
2025-06-01 00:36:38 - myp.app - ERROR - ❌ Fehler beim Datenbank-Cleanup: (sqlite3.OperationalError) database is locked
|
||||||
|
[SQL: PRAGMA journal_mode=DELETE]
|
||||||
|
(Background on this error at: https://sqlalche.me/e/20/e3q8)
|
||||||
|
@ -2521,3 +2521,50 @@
|
|||||||
2025-05-31 23:45:28 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
2025-05-31 23:45:28 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
2025-05-31 23:45:29 - myp.printers - INFO - Schnelles Laden abgeschlossen: 6 Drucker geladen (ohne Status-Check)
|
2025-05-31 23:45:29 - myp.printers - INFO - Schnelles Laden abgeschlossen: 6 Drucker geladen (ohne Status-Check)
|
||||||
2025-05-31 23:45:32 - myp.printers - INFO - Schnelles Laden abgeschlossen: 6 Drucker geladen (ohne Status-Check)
|
2025-05-31 23:45:32 - myp.printers - INFO - Schnelles Laden abgeschlossen: 6 Drucker geladen (ohne Status-Check)
|
||||||
|
2025-06-01 00:29:17 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:29:17 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:29:21 - myp.printers - INFO - Schnelles Laden abgeschlossen: 6 Drucker geladen (ohne Status-Check)
|
||||||
|
2025-06-01 00:29:21 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:29:21 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:29:21 - myp.printers - INFO - Schnelles Laden abgeschlossen: 6 Drucker geladen (ohne Status-Check)
|
||||||
|
2025-06-01 00:29:24 - myp.printers - INFO - Schnelles Laden abgeschlossen: 6 Drucker geladen (ohne Status-Check)
|
||||||
|
2025-06-01 00:30:10 - myp.printers - INFO - Schnelles Laden abgeschlossen: 6 Drucker geladen (ohne Status-Check)
|
||||||
|
2025-06-01 00:33:08 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:33:08 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:33:17 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:33:17 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:33:19 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:33:19 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:33:23 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:33:23 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:33:32 - myp.printers - INFO - Schnelles Laden abgeschlossen: 6 Drucker geladen (ohne Status-Check)
|
||||||
|
2025-06-01 00:33:32 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:33:32 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:33:32 - myp.printers - INFO - Schnelles Laden abgeschlossen: 6 Drucker geladen (ohne Status-Check)
|
||||||
|
2025-06-01 00:33:33 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:33:33 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:33:37 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:33:37 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:33:40 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:33:40 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:33:52 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:33:52 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:33:55 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:33:55 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:34:01 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:34:01 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:34:06 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:34:06 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:34:36 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:34:36 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:35:06 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:35:06 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:35:36 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:35:36 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:35:45 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:35:45 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:36:15 - myp.printers - INFO - Schnelles Laden abgeschlossen: 6 Drucker geladen (ohne Status-Check)
|
||||||
|
2025-06-01 00:36:15 - myp.printers - INFO - 🔄 Live-Status-Abfrage von Benutzer Administrator (ID: 1)
|
||||||
|
2025-06-01 00:36:15 - myp.printers - INFO - ✅ Live-Status-Abfrage erfolgreich: 0 Drucker
|
||||||
|
2025-06-01 00:36:15 - myp.printers - INFO - Schnelles Laden abgeschlossen: 6 Drucker geladen (ohne Status-Check)
|
||||||
|
2025-06-01 00:36:16 - myp.printers - INFO - Schnelles Laden abgeschlossen: 6 Drucker geladen (ohne Status-Check)
|
||||||
|
@ -2717,3 +2717,27 @@
|
|||||||
2025-06-01 00:20:28 - 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: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
|
2025-06-01 00:21:36 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:23:27 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:23:28 - myp.scheduler - INFO - Scheduler-Thread gestartet
|
||||||
|
2025-06-01 00:23:28 - myp.scheduler - INFO - Scheduler gestartet
|
||||||
|
2025-06-01 00:24:52 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:24:53 - myp.scheduler - INFO - Scheduler-Thread gestartet
|
||||||
|
2025-06-01 00:24:53 - myp.scheduler - INFO - Scheduler gestartet
|
||||||
|
2025-06-01 00:29:13 - myp.scheduler - INFO - Scheduler-Thread beendet
|
||||||
|
2025-06-01 00:29:13 - myp.scheduler - INFO - Scheduler gestoppt
|
||||||
|
2025-06-01 00:29:15 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:29:16 - myp.scheduler - INFO - Scheduler-Thread gestartet
|
||||||
|
2025-06-01 00:29:16 - myp.scheduler - INFO - Scheduler gestartet
|
||||||
|
2025-06-01 00:30:54 - myp.scheduler - INFO - Scheduler-Thread beendet
|
||||||
|
2025-06-01 00:30:54 - myp.scheduler - INFO - Scheduler gestoppt
|
||||||
|
2025-06-01 00:30:56 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:33:06 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:33:07 - myp.scheduler - INFO - Scheduler-Thread gestartet
|
||||||
|
2025-06-01 00:33:07 - myp.scheduler - INFO - Scheduler gestartet
|
||||||
|
2025-06-01 00:35:32 - myp.scheduler - INFO - Scheduler-Thread beendet
|
||||||
|
2025-06-01 00:35:32 - myp.scheduler - INFO - Scheduler gestoppt
|
||||||
|
2025-06-01 00:35:34 - myp.scheduler - INFO - Task check_jobs registriert: Intervall 30s, Enabled: True
|
||||||
|
2025-06-01 00:35:36 - myp.scheduler - INFO - Scheduler-Thread gestartet
|
||||||
|
2025-06-01 00:35:36 - myp.scheduler - INFO - Scheduler gestartet
|
||||||
|
2025-06-01 00:36:38 - myp.scheduler - INFO - Scheduler-Thread beendet
|
||||||
|
2025-06-01 00:36:38 - myp.scheduler - INFO - Scheduler gestoppt
|
||||||
|
203
backend/templates/imprint.html
Normal file
203
backend/templates/imprint.html
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ title }} - MYP Platform{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mx-auto px-4 py-8 max-w-4xl">
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-8 mb-8">
|
||||||
|
<div class="flex items-center mb-6">
|
||||||
|
<div class="w-12 h-12 bg-gradient-to-r from-blue-600 to-blue-700 rounded-lg flex items-center justify-center mr-4">
|
||||||
|
<i class="fas fa-info-circle text-white text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 class="text-3xl font-bold text-gray-900">Impressum</h1>
|
||||||
|
<p class="text-gray-600">Rechtliche Angaben gemäß § 5 TMG</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Unternehmensinformationen -->
|
||||||
|
<div class="space-y-8">
|
||||||
|
<section>
|
||||||
|
<h2 class="text-xl font-semibold text-gray-900 mb-4 flex items-center">
|
||||||
|
<i class="fas fa-building text-blue-600 mr-3"></i>
|
||||||
|
Anbieter
|
||||||
|
</h2>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-6">
|
||||||
|
<div class="grid md:grid-cols-2 gap-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="font-semibold text-gray-900 mb-2">Unternehmen</h3>
|
||||||
|
<p class="text-gray-700">Mercedes-Benz AG</p>
|
||||||
|
<p class="text-gray-700">Ausbildungsabteilung</p>
|
||||||
|
<p class="text-gray-700">3D-Druck & Digitale Fertigung</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="font-semibold text-gray-900 mb-2">Adresse</h3>
|
||||||
|
<p class="text-gray-700">Mercedes-Benz Platz 1</p>
|
||||||
|
<p class="text-gray-700">70546 Stuttgart</p>
|
||||||
|
<p class="text-gray-700">Deutschland</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Kontaktinformationen -->
|
||||||
|
<section>
|
||||||
|
<h2 class="text-xl font-semibold text-gray-900 mb-4 flex items-center">
|
||||||
|
<i class="fas fa-envelope text-blue-600 mr-3"></i>
|
||||||
|
Kontakt
|
||||||
|
</h2>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-6">
|
||||||
|
<div class="grid md:grid-cols-2 gap-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="font-semibold text-gray-900 mb-2">E-Mail</h3>
|
||||||
|
<p class="text-gray-700">
|
||||||
|
<a href="mailto:till.tomczak@mercedes-benz.com" class="text-blue-600 hover:text-blue-800">
|
||||||
|
till.tomczak@mercedes-benz.com
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="font-semibold text-gray-900 mb-2">Telefon</h3>
|
||||||
|
<p class="text-gray-700">+49 (0) 711 17-0</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Rechtliche Angaben -->
|
||||||
|
<section>
|
||||||
|
<h2 class="text-xl font-semibold text-gray-900 mb-4 flex items-center">
|
||||||
|
<i class="fas fa-gavel text-blue-600 mr-3"></i>
|
||||||
|
Rechtliche Angaben
|
||||||
|
</h2>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-6">
|
||||||
|
<div class="grid md:grid-cols-2 gap-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="font-semibold text-gray-900 mb-2">Registergericht</h3>
|
||||||
|
<p class="text-gray-700">Amtsgericht Stuttgart</p>
|
||||||
|
<p class="text-gray-700">HRB 19360</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="font-semibold text-gray-900 mb-2">Umsatzsteuer-ID</h3>
|
||||||
|
<p class="text-gray-700">DE811944017</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Verantwortlich für den Inhalt -->
|
||||||
|
<section>
|
||||||
|
<h2 class="text-xl font-semibold text-gray-900 mb-4 flex items-center">
|
||||||
|
<i class="fas fa-user-tie text-blue-600 mr-3"></i>
|
||||||
|
Verantwortlich für den Inhalt
|
||||||
|
</h2>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-6">
|
||||||
|
<p class="text-gray-700">Till Tomczak</p>
|
||||||
|
<p class="text-gray-700">Projektleiter MYP Platform</p>
|
||||||
|
<p class="text-gray-700">Mercedes-Benz AG</p>
|
||||||
|
<p class="text-gray-700">Ausbildungsabteilung</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Haftungsausschluss -->
|
||||||
|
<section>
|
||||||
|
<h2 class="text-xl font-semibold text-gray-900 mb-4 flex items-center">
|
||||||
|
<i class="fas fa-shield-alt text-blue-600 mr-3"></i>
|
||||||
|
Haftungsausschluss
|
||||||
|
</h2>
|
||||||
|
<div class="bg-amber-50 border border-amber-200 rounded-lg p-6">
|
||||||
|
<h3 class="font-semibold text-gray-900 mb-3">Haftung für Inhalte</h3>
|
||||||
|
<p class="text-gray-700 mb-4">
|
||||||
|
Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den
|
||||||
|
allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht
|
||||||
|
unter der Verpflichtung, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach
|
||||||
|
Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 class="font-semibold text-gray-900 mb-3">Haftung für Links</h3>
|
||||||
|
<p class="text-gray-700 mb-4">
|
||||||
|
Unser Angebot enthält Links zu externen Webseiten Dritter, auf deren Inhalte wir keinen Einfluss haben.
|
||||||
|
Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten
|
||||||
|
Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 class="font-semibold text-gray-900 mb-3">Urheberrecht</h3>
|
||||||
|
<p class="text-gray-700">
|
||||||
|
Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen
|
||||||
|
Urheberrecht. Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der
|
||||||
|
Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Streitschlichtung -->
|
||||||
|
<section>
|
||||||
|
<h2 class="text-xl font-semibold text-gray-900 mb-4 flex items-center">
|
||||||
|
<i class="fas fa-balance-scale text-blue-600 mr-3"></i>
|
||||||
|
Streitschlichtung
|
||||||
|
</h2>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-6">
|
||||||
|
<p class="text-gray-700">
|
||||||
|
Die Europäische Kommission stellt eine Plattform zur Online-Streitbeilegung (OS) bereit:
|
||||||
|
<a href="https://ec.europa.eu/consumers/odr/" target="_blank" class="text-blue-600 hover:text-blue-800 underline">
|
||||||
|
https://ec.europa.eu/consumers/odr/
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-700 mt-2">
|
||||||
|
Wir sind nicht bereit oder verpflichtet, an Streitbeilegungsverfahren vor einer
|
||||||
|
Verbraucherschlichtungsstelle teilzunehmen.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- System-Information -->
|
||||||
|
<section>
|
||||||
|
<h2 class="text-xl font-semibold text-gray-900 mb-4 flex items-center">
|
||||||
|
<i class="fas fa-cogs text-blue-600 mr-3"></i>
|
||||||
|
System-Information
|
||||||
|
</h2>
|
||||||
|
<div class="bg-blue-50 border border-blue-200 rounded-lg p-6">
|
||||||
|
<div class="grid md:grid-cols-2 gap-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="font-semibold text-gray-900 mb-2">MYP Platform</h3>
|
||||||
|
<p class="text-gray-700">Manage Your Printers</p>
|
||||||
|
<p class="text-gray-700">Version 2.0.0</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="font-semibold text-gray-900 mb-2">Entwicklung</h3>
|
||||||
|
<p class="text-gray-700">Mercedes-Benz AG</p>
|
||||||
|
<p class="text-gray-700">Interne Projektarbeit</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Navigation -->
|
||||||
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
||||||
|
<div class="flex flex-wrap gap-4 justify-center">
|
||||||
|
<a href="{{ url_for('index') }}" class="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors">
|
||||||
|
<i class="fas fa-home mr-2"></i>
|
||||||
|
Zur Startseite
|
||||||
|
</a>
|
||||||
|
<a href="{{ url_for('legal') }}" class="inline-flex items-center px-4 py-2 bg-gray-600 text-white rounded-md hover:bg-gray-700 transition-colors">
|
||||||
|
<i class="fas fa-file-contract mr-2"></i>
|
||||||
|
Rechtliche Hinweise
|
||||||
|
</a>
|
||||||
|
{% if current_user.is_authenticated %}
|
||||||
|
<a href="{{ url_for('dashboard') }}" class="inline-flex items-center px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 transition-colors">
|
||||||
|
<i class="fas fa-chart-line mr-2"></i>
|
||||||
|
Dashboard
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Letzte Aktualisierung -->
|
||||||
|
<div class="text-center text-sm text-gray-500 mt-8 pb-8">
|
||||||
|
<p>Letzte Aktualisierung: {{ moment().format('DD.MM.YYYY') }}</p>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
510
backend/templates/legal.html
Normal file
510
backend/templates/legal.html
Normal file
@ -0,0 +1,510 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ title }} - MYP Platform{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mx-auto px-4 py-8 max-w-6xl">
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-8 mb-8">
|
||||||
|
<div class="flex items-center mb-6">
|
||||||
|
<div class="w-12 h-12 bg-gradient-to-r from-purple-600 to-purple-700 rounded-lg flex items-center justify-center mr-4">
|
||||||
|
<i class="fas fa-file-contract text-white text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 class="text-3xl font-bold text-gray-900">Rechtliche Hinweise</h1>
|
||||||
|
<p class="text-gray-600">Datenschutz, Nutzungsbedingungen und weitere rechtliche Informationen</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Navigation Links -->
|
||||||
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mt-8">
|
||||||
|
<a href="#datenschutz" class="flex items-center p-4 bg-blue-50 rounded-lg hover:bg-blue-100 transition-colors">
|
||||||
|
<i class="fas fa-shield-alt text-blue-600 mr-3"></i>
|
||||||
|
<span class="font-medium text-blue-900">Datenschutz</span>
|
||||||
|
</a>
|
||||||
|
<a href="#nutzungsbedingungen" class="flex items-center p-4 bg-green-50 rounded-lg hover:bg-green-100 transition-colors">
|
||||||
|
<i class="fas fa-file-signature text-green-600 mr-3"></i>
|
||||||
|
<span class="font-medium text-green-900">AGB</span>
|
||||||
|
</a>
|
||||||
|
<a href="#cookies" class="flex items-center p-4 bg-amber-50 rounded-lg hover:bg-amber-100 transition-colors">
|
||||||
|
<i class="fas fa-cookie-bite text-amber-600 mr-3"></i>
|
||||||
|
<span class="font-medium text-amber-900">Cookies</span>
|
||||||
|
</a>
|
||||||
|
<a href="#sicherheit" class="flex items-center p-4 bg-red-50 rounded-lg hover:bg-red-100 transition-colors">
|
||||||
|
<i class="fas fa-lock text-red-600 mr-3"></i>
|
||||||
|
<span class="font-medium text-red-900">Sicherheit</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Datenschutzerklärung -->
|
||||||
|
<section id="datenschutz" class="bg-white rounded-lg shadow-sm border border-gray-200 p-8 mb-8">
|
||||||
|
<h2 class="text-2xl font-bold text-gray-900 mb-6 flex items-center">
|
||||||
|
<i class="fas fa-shield-alt text-blue-600 mr-3"></i>
|
||||||
|
Datenschutzerklärung
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
<!-- Grundsätzliches -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-3">1. Grundsätzliches zum Datenschutz</h3>
|
||||||
|
<div class="bg-blue-50 rounded-lg p-6">
|
||||||
|
<p class="text-gray-700 mb-4">
|
||||||
|
Der Schutz Ihrer persönlichen Daten ist uns wichtig. Diese Datenschutzerklärung informiert Sie über
|
||||||
|
die Art, den Umfang und Zweck der Verarbeitung personenbezogener Daten innerhalb des MYP-Systems
|
||||||
|
(Manage Your Printers) der Mercedes-Benz AG.
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-700">
|
||||||
|
Verantwortlicher im Sinne der Datenschutz-Grundverordnung (DSGVO) ist die Mercedes-Benz AG,
|
||||||
|
vertreten durch die Ausbildungsabteilung.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Datenerhebung -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-3">2. Erhebung und Verarbeitung personenbezogener Daten</h3>
|
||||||
|
<div class="grid md:grid-cols-2 gap-6">
|
||||||
|
<div class="bg-gray-50 rounded-lg p-6">
|
||||||
|
<h4 class="font-semibold text-gray-900 mb-3">Registrierungsdaten</h4>
|
||||||
|
<ul class="text-gray-700 space-y-2">
|
||||||
|
<li>• Benutzername</li>
|
||||||
|
<li>• E-Mail-Adresse (Mercedes-Benz)</li>
|
||||||
|
<li>• Name und Abteilung</li>
|
||||||
|
<li>• Rolle im System</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-6">
|
||||||
|
<h4 class="font-semibold text-gray-900 mb-3">Nutzungsdaten</h4>
|
||||||
|
<ul class="text-gray-700 space-y-2">
|
||||||
|
<li>• Druckaufträge und -verlauf</li>
|
||||||
|
<li>• Login-Zeiten und -Häufigkeit</li>
|
||||||
|
<li>• IP-Adresse und Browser-Info</li>
|
||||||
|
<li>• Systemaktivitäten</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Zweck der Datenverarbeitung -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-3">3. Zweck der Datenverarbeitung</h3>
|
||||||
|
<div class="bg-green-50 rounded-lg p-6">
|
||||||
|
<div class="grid md:grid-cols-2 gap-6">
|
||||||
|
<div>
|
||||||
|
<h4 class="font-semibold text-gray-900 mb-3">Primäre Zwecke</h4>
|
||||||
|
<ul class="text-gray-700 space-y-2">
|
||||||
|
<li>• Bereitstellung der 3D-Druck-Services</li>
|
||||||
|
<li>• Verwaltung von Druckaufträgen</li>
|
||||||
|
<li>• Benutzerauthentifizierung</li>
|
||||||
|
<li>• Ressourcenplanung</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4 class="font-semibold text-gray-900 mb-3">Sekundäre Zwecke</h4>
|
||||||
|
<ul class="text-gray-700 space-y-2">
|
||||||
|
<li>• Systemoptimierung</li>
|
||||||
|
<li>• Qualitätssicherung</li>
|
||||||
|
<li>• Ausbildungszwecke</li>
|
||||||
|
<li>• Sicherheitsüberwachung</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Rechtsgrundlage -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-3">4. Rechtsgrundlage</h3>
|
||||||
|
<div class="bg-amber-50 border border-amber-200 rounded-lg p-6">
|
||||||
|
<p class="text-gray-700 mb-4">
|
||||||
|
Die Verarbeitung erfolgt auf Grundlage von:
|
||||||
|
</p>
|
||||||
|
<ul class="text-gray-700 space-y-2">
|
||||||
|
<li>• <strong>Art. 6 Abs. 1 lit. b DSGVO:</strong> Vertragserfüllung (Nutzung der Druckdienste)</li>
|
||||||
|
<li>• <strong>Art. 6 Abs. 1 lit. f DSGVO:</strong> Berechtigte Interessen (Systemsicherheit, Optimierung)</li>
|
||||||
|
<li>• <strong>Art. 6 Abs. 1 lit. c DSGVO:</strong> Rechtliche Verpflichtung (Dokumentation, Compliance)</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Ihre Rechte -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-3">5. Ihre Rechte</h3>
|
||||||
|
<div class="grid md:grid-cols-3 gap-4">
|
||||||
|
<div class="bg-blue-50 rounded-lg p-4">
|
||||||
|
<h4 class="font-semibold text-blue-900 mb-2">Auskunftsrecht</h4>
|
||||||
|
<p class="text-blue-800 text-sm">Art. 15 DSGVO</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-green-50 rounded-lg p-4">
|
||||||
|
<h4 class="font-semibold text-green-900 mb-2">Berichtigungsrecht</h4>
|
||||||
|
<p class="text-green-800 text-sm">Art. 16 DSGVO</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-red-50 rounded-lg p-4">
|
||||||
|
<h4 class="font-semibold text-red-900 mb-2">Löschungsrecht</h4>
|
||||||
|
<p class="text-red-800 text-sm">Art. 17 DSGVO</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-purple-50 rounded-lg p-4">
|
||||||
|
<h4 class="font-semibold text-purple-900 mb-2">Einschränkungsrecht</h4>
|
||||||
|
<p class="text-purple-800 text-sm">Art. 18 DSGVO</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-amber-50 rounded-lg p-4">
|
||||||
|
<h4 class="font-semibold text-amber-900 mb-2">Datenübertragbarkeit</h4>
|
||||||
|
<p class="text-amber-800 text-sm">Art. 20 DSGVO</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
|
<h4 class="font-semibold text-gray-900 mb-2">Widerspruchsrecht</h4>
|
||||||
|
<p class="text-gray-700 text-sm">Art. 21 DSGVO</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Nutzungsbedingungen -->
|
||||||
|
<section id="nutzungsbedingungen" class="bg-white rounded-lg shadow-sm border border-gray-200 p-8 mb-8">
|
||||||
|
<h2 class="text-2xl font-bold text-gray-900 mb-6 flex items-center">
|
||||||
|
<i class="fas fa-file-signature text-green-600 mr-3"></i>
|
||||||
|
Allgemeine Nutzungsbedingungen
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
<!-- Geltungsbereich -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-3">1. Geltungsbereich</h3>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-6">
|
||||||
|
<p class="text-gray-700">
|
||||||
|
Diese Nutzungsbedingungen gelten für die Nutzung des MYP-Systems (Manage Your Printers)
|
||||||
|
durch Mitarbeiter und Auszubildende der Mercedes-Benz AG. Mit der Registrierung und
|
||||||
|
Nutzung des Systems erkennen Sie diese Bedingungen an.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Nutzungsrechte -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-3">2. Nutzungsrechte und -pflichten</h3>
|
||||||
|
<div class="grid md:grid-cols-2 gap-6">
|
||||||
|
<div class="bg-green-50 rounded-lg p-6">
|
||||||
|
<h4 class="font-semibold text-green-900 mb-3">Erlaubte Nutzung</h4>
|
||||||
|
<ul class="text-green-800 space-y-2">
|
||||||
|
<li>• Druckaufträge für Ausbildungszwecke</li>
|
||||||
|
<li>• Prototyping und Projektarbeit</li>
|
||||||
|
<li>• Lernmaterialien und Demonstrationen</li>
|
||||||
|
<li>• Interne Mercedes-Benz Projekte</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="bg-red-50 rounded-lg p-6">
|
||||||
|
<h4 class="font-semibold text-red-900 mb-3">Verbotene Nutzung</h4>
|
||||||
|
<ul class="text-red-800 space-y-2">
|
||||||
|
<li>• Kommerzielle Zwecke ohne Genehmigung</li>
|
||||||
|
<li>• Urheberrechtsverletzungen</li>
|
||||||
|
<li>• Gefährliche oder illegale Objekte</li>
|
||||||
|
<li>• Systemmanipulation oder -missbrauch</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Verantwortlichkeiten -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-3">3. Verantwortlichkeiten</h3>
|
||||||
|
<div class="bg-amber-50 border border-amber-200 rounded-lg p-6">
|
||||||
|
<div class="grid md:grid-cols-2 gap-6">
|
||||||
|
<div>
|
||||||
|
<h4 class="font-semibold text-gray-900 mb-3">Nutzer-Verantwortung</h4>
|
||||||
|
<ul class="text-gray-700 space-y-2">
|
||||||
|
<li>• Sichere Aufbewahrung der Zugangsdaten</li>
|
||||||
|
<li>• Einhaltung der Sicherheitsrichtlinien</li>
|
||||||
|
<li>• Ordnungsgemäße Nutzung der Geräte</li>
|
||||||
|
<li>• Meldung von Problemen</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4 class="font-semibold text-gray-900 mb-3">System-Verantwortung</h4>
|
||||||
|
<ul class="text-gray-700 space-y-2">
|
||||||
|
<li>• Bereitstellung der Infrastruktur</li>
|
||||||
|
<li>• Wartung und Support</li>
|
||||||
|
<li>• Datenschutz und Sicherheit</li>
|
||||||
|
<li>• Kontinuierliche Verbesserung</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Cookie-Policy -->
|
||||||
|
<section id="cookies" class="bg-white rounded-lg shadow-sm border border-gray-200 p-8 mb-8">
|
||||||
|
<h2 class="text-2xl font-bold text-gray-900 mb-6 flex items-center">
|
||||||
|
<i class="fas fa-cookie-bite text-amber-600 mr-3"></i>
|
||||||
|
Cookie-Richtlinie
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
<!-- Was sind Cookies -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-3">Was sind Cookies?</h3>
|
||||||
|
<div class="bg-amber-50 rounded-lg p-6">
|
||||||
|
<p class="text-gray-700">
|
||||||
|
Cookies sind kleine Textdateien, die beim Besuch einer Website auf Ihrem Computer gespeichert werden.
|
||||||
|
Sie helfen dabei, Ihre Präferenzen zu speichern und die Funktionalität der Website zu verbessern.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Cookie-Kategorien -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-3">Verwendete Cookie-Kategorien</h3>
|
||||||
|
<div class="grid md:grid-cols-2 gap-6">
|
||||||
|
<div class="bg-blue-50 rounded-lg p-6">
|
||||||
|
<h4 class="font-semibold text-blue-900 mb-3">Technisch notwendige Cookies</h4>
|
||||||
|
<ul class="text-blue-800 space-y-2">
|
||||||
|
<li>• Session-Management</li>
|
||||||
|
<li>• Anmeldestatus</li>
|
||||||
|
<li>• CSRF-Schutz</li>
|
||||||
|
<li>• Spracheinstellungen</li>
|
||||||
|
</ul>
|
||||||
|
<p class="text-blue-700 text-sm mt-3">Diese Cookies sind für die Funktionalität der Website erforderlich.</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-green-50 rounded-lg p-6">
|
||||||
|
<h4 class="font-semibold text-green-900 mb-3">Funktionale Cookies</h4>
|
||||||
|
<ul class="text-green-800 space-y-2">
|
||||||
|
<li>• Benutzereinstellungen</li>
|
||||||
|
<li>• Dashboard-Konfiguration</li>
|
||||||
|
<li>• Theme-Präferenzen</li>
|
||||||
|
<li>• Accessibility-Optionen</li>
|
||||||
|
</ul>
|
||||||
|
<p class="text-green-700 text-sm mt-3">Diese Cookies verbessern die Benutzererfahrung.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Cookie-Kontrolle -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-3">Cookie-Kontrolle</h3>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-6">
|
||||||
|
<p class="text-gray-700 mb-4">
|
||||||
|
Sie können Cookies in Ihren Browser-Einstellungen verwalten. Beachten Sie jedoch, dass das
|
||||||
|
Deaktivieren bestimmter Cookies die Funktionalität der Website beeinträchtigen kann.
|
||||||
|
</p>
|
||||||
|
<div class="grid md:grid-cols-3 gap-4">
|
||||||
|
<div class="bg-white rounded-lg p-4 border">
|
||||||
|
<h5 class="font-semibold text-gray-900 mb-2">Chrome</h5>
|
||||||
|
<p class="text-gray-600 text-sm">Einstellungen → Datenschutz und Sicherheit → Cookies</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white rounded-lg p-4 border">
|
||||||
|
<h5 class="font-semibold text-gray-900 mb-2">Firefox</h5>
|
||||||
|
<p class="text-gray-600 text-sm">Einstellungen → Datenschutz & Sicherheit</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white rounded-lg p-4 border">
|
||||||
|
<h5 class="font-semibold text-gray-900 mb-2">Edge</h5>
|
||||||
|
<p class="text-gray-600 text-sm">Einstellungen → Cookies und Websiteberechtigungen</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Sicherheitsrichtlinien -->
|
||||||
|
<section id="sicherheit" class="bg-white rounded-lg shadow-sm border border-gray-200 p-8 mb-8">
|
||||||
|
<h2 class="text-2xl font-bold text-gray-900 mb-6 flex items-center">
|
||||||
|
<i class="fas fa-lock text-red-600 mr-3"></i>
|
||||||
|
Sicherheitsrichtlinien
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
<!-- Technische Sicherheit -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-3">Technische Sicherheitsmaßnahmen</h3>
|
||||||
|
<div class="grid md:grid-cols-2 gap-6">
|
||||||
|
<div class="bg-red-50 rounded-lg p-6">
|
||||||
|
<h4 class="font-semibold text-red-900 mb-3">Infrastruktursicherheit</h4>
|
||||||
|
<ul class="text-red-800 space-y-2">
|
||||||
|
<li>• HTTPS-Verschlüsselung</li>
|
||||||
|
<li>• Sichere Datenübertragung</li>
|
||||||
|
<li>• Regelmäßige Security-Updates</li>
|
||||||
|
<li>• Firewalls und Intrusion Detection</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="bg-blue-50 rounded-lg p-6">
|
||||||
|
<h4 class="font-semibold text-blue-900 mb-3">Anwendungssicherheit</h4>
|
||||||
|
<ul class="text-blue-800 space-y-2">
|
||||||
|
<li>• Sichere Authentifizierung</li>
|
||||||
|
<li>• Rollenbasierte Zugriffskontrolle</li>
|
||||||
|
<li>• Input-Validierung</li>
|
||||||
|
<li>• Session-Management</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Benutzer-Sicherheit -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-3">Empfehlungen für Benutzer</h3>
|
||||||
|
<div class="bg-green-50 rounded-lg p-6">
|
||||||
|
<div class="grid md:grid-cols-2 gap-6">
|
||||||
|
<div>
|
||||||
|
<h4 class="font-semibold text-green-900 mb-3">Passwort-Sicherheit</h4>
|
||||||
|
<ul class="text-green-800 space-y-2">
|
||||||
|
<li>• Verwenden Sie starke Passwörter</li>
|
||||||
|
<li>• Teilen Sie keine Zugangsdaten</li>
|
||||||
|
<li>• Melden Sie sich nach der Nutzung ab</li>
|
||||||
|
<li>• Verwenden Sie nicht öffentliche Computer</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4 class="font-semibold text-green-900 mb-3">Allgemeine Sicherheit</h4>
|
||||||
|
<ul class="text-green-800 space-y-2">
|
||||||
|
<li>• Halten Sie Ihren Browser aktuell</li>
|
||||||
|
<li>• Verwenden Sie Antivirus-Software</li>
|
||||||
|
<li>• Seien Sie vorsichtig bei Downloads</li>
|
||||||
|
<li>• Melden Sie verdächtige Aktivitäten</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Incident Response -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-3">Sicherheitsvorfälle melden</h3>
|
||||||
|
<div class="bg-amber-50 border border-amber-200 rounded-lg p-6">
|
||||||
|
<p class="text-gray-700 mb-4">
|
||||||
|
Falls Sie einen Sicherheitsvorfall bemerken oder vermuten, wenden Sie sich umgehend an:
|
||||||
|
</p>
|
||||||
|
<div class="grid md:grid-cols-2 gap-6">
|
||||||
|
<div>
|
||||||
|
<h4 class="font-semibold text-gray-900 mb-2">Technischer Support</h4>
|
||||||
|
<p class="text-gray-700">
|
||||||
|
E-Mail: <a href="mailto:till.tomczak@mercedes-benz.com" class="text-blue-600 hover:text-blue-800">
|
||||||
|
till.tomczak@mercedes-benz.com
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4 class="font-semibold text-gray-900 mb-2">IT-Sicherheit</h4>
|
||||||
|
<p class="text-gray-700">
|
||||||
|
Interne IT-Security-Hotline
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Kontakt und Weitere Informationen -->
|
||||||
|
<section class="bg-white rounded-lg shadow-sm border border-gray-200 p-8 mb-8">
|
||||||
|
<h2 class="text-2xl font-bold text-gray-900 mb-6 flex items-center">
|
||||||
|
<i class="fas fa-info-circle text-blue-600 mr-3"></i>
|
||||||
|
Weitere Informationen
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="grid md:grid-cols-2 gap-8">
|
||||||
|
<!-- Kontakt -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">Bei Fragen wenden Sie sich an:</h3>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="flex items-start">
|
||||||
|
<i class="fas fa-envelope text-blue-600 mt-1 mr-3"></i>
|
||||||
|
<div>
|
||||||
|
<p class="font-medium text-gray-900">E-Mail</p>
|
||||||
|
<a href="mailto:till.tomczak@mercedes-benz.com" class="text-blue-600 hover:text-blue-800">
|
||||||
|
till.tomczak@mercedes-benz.com
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-start">
|
||||||
|
<i class="fas fa-building text-blue-600 mt-1 mr-3"></i>
|
||||||
|
<div>
|
||||||
|
<p class="font-medium text-gray-900">Abteilung</p>
|
||||||
|
<p class="text-gray-700">Ausbildungsabteilung - 3D-Druck</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Updates -->
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">Aktualisierungen</h3>
|
||||||
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
|
<p class="text-gray-700 mb-2">
|
||||||
|
Diese rechtlichen Hinweise können bei Bedarf aktualisiert werden.
|
||||||
|
Über wesentliche Änderungen werden Sie informiert.
|
||||||
|
</p>
|
||||||
|
<p class="text-sm text-gray-600">
|
||||||
|
Stand: {{ moment().format('DD.MM.YYYY') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Navigation -->
|
||||||
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
||||||
|
<div class="flex flex-wrap gap-4 justify-center">
|
||||||
|
<a href="{{ url_for('index') }}" class="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors">
|
||||||
|
<i class="fas fa-home mr-2"></i>
|
||||||
|
Zur Startseite
|
||||||
|
</a>
|
||||||
|
<a href="{{ url_for('imprint') }}" class="inline-flex items-center px-4 py-2 bg-gray-600 text-white rounded-md hover:bg-gray-700 transition-colors">
|
||||||
|
<i class="fas fa-info-circle mr-2"></i>
|
||||||
|
Impressum
|
||||||
|
</a>
|
||||||
|
{% if current_user.is_authenticated %}
|
||||||
|
<a href="{{ url_for('dashboard') }}" class="inline-flex items-center px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 transition-colors">
|
||||||
|
<i class="fas fa-chart-line mr-2"></i>
|
||||||
|
Dashboard
|
||||||
|
</a>
|
||||||
|
<a href="{{ url_for('user_settings') }}" class="inline-flex items-center px-4 py-2 bg-purple-600 text-white rounded-md hover:bg-purple-700 transition-colors">
|
||||||
|
<i class="fas fa-cog mr-2"></i>
|
||||||
|
Einstellungen
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scroll-to-Top Button -->
|
||||||
|
<button id="scrollToTop" class="fixed bottom-6 right-6 bg-blue-600 text-white p-3 rounded-full shadow-lg hover:bg-blue-700 transition-all duration-300 opacity-0 pointer-events-none">
|
||||||
|
<i class="fas fa-chevron-up"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Smooth scrolling for anchor links
|
||||||
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||||
|
anchor.addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const target = document.querySelector(this.getAttribute('href'));
|
||||||
|
if (target) {
|
||||||
|
target.scrollIntoView({
|
||||||
|
behavior: 'smooth',
|
||||||
|
block: 'start'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Scroll-to-top functionality
|
||||||
|
const scrollToTopBtn = document.getElementById('scrollToTop');
|
||||||
|
window.addEventListener('scroll', () => {
|
||||||
|
if (window.pageYOffset > 300) {
|
||||||
|
scrollToTopBtn.classList.remove('opacity-0', 'pointer-events-none');
|
||||||
|
scrollToTopBtn.classList.add('opacity-100');
|
||||||
|
} else {
|
||||||
|
scrollToTopBtn.classList.add('opacity-0', 'pointer-events-none');
|
||||||
|
scrollToTopBtn.classList.remove('opacity-100');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
scrollToTopBtn.addEventListener('click', () => {
|
||||||
|
window.scrollTo({
|
||||||
|
top: 0,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
Loading…
x
Reference in New Issue
Block a user