📝 "Refactor backend
This commit is contained in:
310
backend/app.py
310
backend/app.py
@ -4828,34 +4828,32 @@ def session_status():
|
||||
@app.route('/api/session/extend', methods=['POST'])
|
||||
@login_required
|
||||
def extend_session():
|
||||
"""
|
||||
Verlängert die aktuelle Session um weitere Zeit.
|
||||
"""
|
||||
"""Verlängert die aktuelle Session um die Standard-Lebensdauer"""
|
||||
try:
|
||||
data = request.get_json() or {}
|
||||
extend_minutes = data.get('extend_minutes', 30)
|
||||
# Session-Lebensdauer zurücksetzen
|
||||
session.permanent = True
|
||||
|
||||
# Begrenzen der Verlängerung (max 2 Stunden)
|
||||
extend_minutes = min(extend_minutes, 120)
|
||||
# Aktivität für Rate Limiting aktualisieren
|
||||
current_user.update_last_activity()
|
||||
|
||||
now = datetime.now()
|
||||
session['last_activity'] = now.isoformat()
|
||||
session['session_extended'] = now.isoformat()
|
||||
session['extended_by_minutes'] = extend_minutes
|
||||
# Optional: Session-Statistiken für Admin
|
||||
user_agent = request.headers.get('User-Agent', 'Unknown')
|
||||
ip_address = request.environ.get('HTTP_X_FORWARDED_FOR', request.remote_addr)
|
||||
|
||||
auth_logger.info(f"🕒 Session verlängert für Benutzer {current_user.email} um {extend_minutes} Minuten")
|
||||
app_logger.info(f"Session verlängert für User {current_user.id} (IP: {ip_address})")
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": f"Session um {extend_minutes} Minuten verlängert",
|
||||
"extended_until": (now + timedelta(minutes=extend_minutes)).isoformat(),
|
||||
"extended_minutes": extend_minutes
|
||||
'success': True,
|
||||
'message': 'Session erfolgreich verlängert',
|
||||
'expires_at': (datetime.now() + SESSION_LIFETIME).isoformat()
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
auth_logger.error(f"Fehler beim Verlängern der Session: {str(e)}")
|
||||
return jsonify({"error": "Session-Verlängerung fehlgeschlagen"}), 500
|
||||
|
||||
|
||||
app_logger.error(f"Fehler beim Verlängern der Session: {str(e)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': 'Fehler beim Verlängern der Session'
|
||||
}), 500
|
||||
|
||||
# ===== GASTANTRÄGE API-ROUTEN =====
|
||||
|
||||
@ -5668,4 +5666,274 @@ if __name__ == "__main__":
|
||||
stop_queue_manager()
|
||||
except:
|
||||
pass
|
||||
sys.exit(1)
|
||||
sys.exit(1)
|
||||
|
||||
# ===== AUTO-OPTIMIERUNG-API-ENDPUNKTE =====
|
||||
|
||||
@app.route('/api/optimization/auto-optimize', methods=['POST'])
|
||||
@login_required
|
||||
def auto_optimize_jobs():
|
||||
"""
|
||||
Automatische Optimierung der Druckaufträge durchführen
|
||||
Implementiert intelligente Job-Verteilung basierend auf verschiedenen Algorithmen
|
||||
"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
settings = data.get('settings', {})
|
||||
enabled = data.get('enabled', False)
|
||||
|
||||
db_session = get_db_session()
|
||||
|
||||
# Aktuelle Jobs in der Warteschlange abrufen
|
||||
pending_jobs = db_session.query(Job).filter(
|
||||
Job.status.in_(['queued', 'pending'])
|
||||
).all()
|
||||
|
||||
if not pending_jobs:
|
||||
db_session.close()
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': 'Keine Jobs zur Optimierung verfügbar',
|
||||
'optimized_jobs': 0
|
||||
})
|
||||
|
||||
# Verfügbare Drucker abrufen
|
||||
available_printers = db_session.query(Printer).filter(Printer.active == True).all()
|
||||
|
||||
if not available_printers:
|
||||
db_session.close()
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': 'Keine verfügbaren Drucker für Optimierung'
|
||||
})
|
||||
|
||||
# Optimierungs-Algorithmus anwenden
|
||||
algorithm = settings.get('algorithm', 'round_robin')
|
||||
optimized_count = 0
|
||||
|
||||
if algorithm == 'round_robin':
|
||||
optimized_count = apply_round_robin_optimization(pending_jobs, available_printers, db_session)
|
||||
elif algorithm == 'load_balance':
|
||||
optimized_count = apply_load_balance_optimization(pending_jobs, available_printers, db_session)
|
||||
elif algorithm == 'priority_based':
|
||||
optimized_count = apply_priority_optimization(pending_jobs, available_printers, db_session)
|
||||
|
||||
db_session.commit()
|
||||
jobs_logger.info(f"Auto-Optimierung durchgeführt: {optimized_count} Jobs optimiert mit Algorithmus {algorithm}")
|
||||
|
||||
# System-Log erstellen
|
||||
log_entry = SystemLog(
|
||||
level='INFO',
|
||||
component='optimization',
|
||||
message=f'Auto-Optimierung durchgeführt: {optimized_count} Jobs optimiert',
|
||||
user_id=current_user.id if current_user.is_authenticated else None,
|
||||
details=json.dumps({
|
||||
'algorithm': algorithm,
|
||||
'optimized_jobs': optimized_count,
|
||||
'settings': settings
|
||||
})
|
||||
)
|
||||
db_session.add(log_entry)
|
||||
db_session.commit()
|
||||
db_session.close()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'optimized_jobs': optimized_count,
|
||||
'algorithm': algorithm,
|
||||
'message': f'Optimierung erfolgreich: {optimized_count} Jobs wurden optimiert'
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"Fehler bei der Auto-Optimierung: {str(e)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': f'Optimierung fehlgeschlagen: {str(e)}'
|
||||
}), 500
|
||||
|
||||
@app.route('/api/optimization/settings', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def optimization_settings():
|
||||
"""Optimierungs-Einstellungen abrufen und speichern"""
|
||||
db_session = get_db_session()
|
||||
|
||||
if request.method == 'GET':
|
||||
try:
|
||||
# Standard-Einstellungen oder benutzerdefinierte laden
|
||||
default_settings = {
|
||||
'algorithm': 'round_robin',
|
||||
'consider_distance': True,
|
||||
'minimize_changeover': True,
|
||||
'max_batch_size': 10,
|
||||
'time_window': 24,
|
||||
'auto_optimization_enabled': False
|
||||
}
|
||||
|
||||
# Benutzereinstellungen aus der Session laden oder Standardwerte verwenden
|
||||
user_settings = session.get('user_settings', {})
|
||||
optimization_settings = user_settings.get('optimization', default_settings)
|
||||
|
||||
# Sicherstellen, dass alle erforderlichen Schlüssel vorhanden sind
|
||||
for key, value in default_settings.items():
|
||||
if key not in optimization_settings:
|
||||
optimization_settings[key] = value
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'settings': optimization_settings
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app_logger.error(f"Fehler beim Abrufen der Optimierungs-Einstellungen: {str(e)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': 'Fehler beim Laden der Einstellungen'
|
||||
}), 500
|
||||
|
||||
elif request.method == 'POST':
|
||||
try:
|
||||
settings = request.get_json()
|
||||
|
||||
# Validierung der Einstellungen
|
||||
if not validate_optimization_settings(settings):
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': 'Ungültige Optimierungs-Einstellungen'
|
||||
}), 400
|
||||
|
||||
# Einstellungen in der Session speichern
|
||||
user_settings = session.get('user_settings', {})
|
||||
if 'optimization' not in user_settings:
|
||||
user_settings['optimization'] = {}
|
||||
|
||||
# Aktualisiere die Optimierungseinstellungen
|
||||
user_settings['optimization'].update(settings)
|
||||
session['user_settings'] = user_settings
|
||||
|
||||
# Einstellungen in der Datenbank speichern, wenn möglich
|
||||
if hasattr(current_user, 'settings'):
|
||||
import json
|
||||
current_user.settings = json.dumps(user_settings)
|
||||
current_user.updated_at = datetime.now()
|
||||
db_session.commit()
|
||||
|
||||
app_logger.info(f"Optimierungs-Einstellungen für Benutzer {current_user.id} aktualisiert")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': 'Optimierungs-Einstellungen erfolgreich gespeichert'
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
db_session.rollback()
|
||||
app_logger.error(f"Fehler beim Speichern der Optimierungs-Einstellungen: {str(e)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': f'Fehler beim Speichern der Einstellungen: {str(e)}'
|
||||
}), 500
|
||||
finally:
|
||||
db_session.close()
|
||||
|
||||
# ===== OPTIMIERUNGS-ALGORITHMUS-FUNKTIONEN =====
|
||||
|
||||
def apply_round_robin_optimization(jobs, printers, db_session):
|
||||
"""
|
||||
Round-Robin-Optimierung: Gleichmäßige Verteilung der Jobs auf Drucker
|
||||
Verteilt Jobs nacheinander auf verfügbare Drucker für optimale Balance
|
||||
"""
|
||||
optimized_count = 0
|
||||
printer_index = 0
|
||||
|
||||
for job in jobs:
|
||||
if printer_index >= len(printers):
|
||||
printer_index = 0
|
||||
|
||||
# Job dem nächsten Drucker zuweisen
|
||||
job.printer_id = printers[printer_index].id
|
||||
job.assigned_at = datetime.now()
|
||||
optimized_count += 1
|
||||
printer_index += 1
|
||||
|
||||
return optimized_count
|
||||
|
||||
def apply_load_balance_optimization(jobs, printers, db_session):
|
||||
"""
|
||||
Load-Balancing-Optimierung: Jobs basierend auf aktueller Auslastung verteilen
|
||||
Berücksichtigt die aktuelle Drucker-Auslastung für optimale Verteilung
|
||||
"""
|
||||
optimized_count = 0
|
||||
|
||||
# Aktuelle Drucker-Auslastung berechnen
|
||||
printer_loads = {}
|
||||
for printer in printers:
|
||||
current_jobs = db_session.query(Job).filter(
|
||||
Job.printer_id == printer.id,
|
||||
Job.status.in_(['running', 'queued'])
|
||||
).count()
|
||||
printer_loads[printer.id] = current_jobs
|
||||
|
||||
for job in jobs:
|
||||
# Drucker mit geringster Auslastung finden
|
||||
min_load_printer_id = min(printer_loads, key=printer_loads.get)
|
||||
|
||||
job.printer_id = min_load_printer_id
|
||||
job.assigned_at = datetime.now()
|
||||
|
||||
# Auslastung für nächste Iteration aktualisieren
|
||||
printer_loads[min_load_printer_id] += 1
|
||||
optimized_count += 1
|
||||
|
||||
return optimized_count
|
||||
|
||||
def apply_priority_optimization(jobs, printers, db_session):
|
||||
"""
|
||||
Prioritätsbasierte Optimierung: Jobs nach Priorität und verfügbaren Druckern verteilen
|
||||
Hochpriorisierte Jobs erhalten bevorzugte Druckerzuweisung
|
||||
"""
|
||||
optimized_count = 0
|
||||
|
||||
# Jobs nach Priorität sortieren
|
||||
priority_order = {'urgent': 1, 'high': 2, 'normal': 3, 'low': 4}
|
||||
sorted_jobs = sorted(jobs, key=lambda j: priority_order.get(getattr(j, 'priority', 'normal'), 3))
|
||||
|
||||
# Hochpriorisierte Jobs den besten verfügbaren Druckern zuweisen
|
||||
printer_assignments = {printer.id: 0 for printer in printers}
|
||||
|
||||
for job in sorted_jobs:
|
||||
# Drucker mit geringster Anzahl zugewiesener Jobs finden
|
||||
best_printer_id = min(printer_assignments, key=printer_assignments.get)
|
||||
|
||||
job.printer_id = best_printer_id
|
||||
job.assigned_at = datetime.now()
|
||||
|
||||
printer_assignments[best_printer_id] += 1
|
||||
optimized_count += 1
|
||||
|
||||
return optimized_count
|
||||
|
||||
def validate_optimization_settings(settings):
|
||||
"""
|
||||
Validiert die Optimierungs-Einstellungen auf Korrektheit und Sicherheit
|
||||
Verhindert ungültige Parameter die das System beeinträchtigen könnten
|
||||
"""
|
||||
try:
|
||||
# Algorithmus validieren
|
||||
valid_algorithms = ['round_robin', 'load_balance', 'priority_based']
|
||||
if settings.get('algorithm') not in valid_algorithms:
|
||||
return False
|
||||
|
||||
# Numerische Werte validieren
|
||||
max_batch_size = settings.get('max_batch_size', 10)
|
||||
if not isinstance(max_batch_size, int) or max_batch_size < 1 or max_batch_size > 50:
|
||||
return False
|
||||
|
||||
time_window = settings.get('time_window', 24)
|
||||
if not isinstance(time_window, int) or time_window < 1 or time_window > 168:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
# ===== GASTANTRÄGE API-ROUTEN =====
|
Reference in New Issue
Block a user