Files
Projektarbeit-MYP/backend/blueprints/sessions.py

160 lines
6.3 KiB
Python

"""
Session-Blueprint für das 3D-Druck-Management-System
Dieses Modul enthält alle Routen und Funktionen für Session-Management.
"""
from flask import Blueprint, jsonify, request, session
from flask_login import login_required, current_user
from datetime import datetime, timedelta
from models import User, get_db_session, SystemLog
from utils.logging_config import get_logger
# Blueprint erstellen
sessions_blueprint = Blueprint('sessions', __name__, url_prefix='/api/session')
# Logger initialisieren
sessions_logger = get_logger("sessions")
# Session-Lifetime sicher importieren und validieren
def get_session_lifetime_td():
"""Sichere SESSION_LIFETIME Konvertierung zu timedelta"""
try:
from utils.utilities_collection import SESSION_LIFETIME
# Sicherstellen, dass es ein timedelta ist
if isinstance(SESSION_LIFETIME, (int, float)):
return timedelta(seconds=SESSION_LIFETIME)
elif isinstance(SESSION_LIFETIME, timedelta):
return SESSION_LIFETIME
elif hasattr(SESSION_LIFETIME, 'total_seconds'):
# Bereits ein timedelta-artiges Objekt
return SESSION_LIFETIME
else:
sessions_logger.warning(f"SESSION_LIFETIME hat unerwarteten Typ: {type(SESSION_LIFETIME)}, verwende Fallback")
return timedelta(hours=1)
except ImportError:
sessions_logger.warning("SESSION_LIFETIME konnte nicht importiert werden, verwende Fallback (1h)")
return timedelta(hours=1)
except Exception as e:
sessions_logger.error(f"Fehler beim Importieren von SESSION_LIFETIME: {e}, verwende Fallback")
return timedelta(hours=1)
SESSION_LIFETIME_TD = get_session_lifetime_td()
@sessions_blueprint.route('/heartbeat', methods=['POST'])
@login_required
def heartbeat():
"""
Session-Heartbeat zum Aktualisieren der letzten Aktivität.
Verhindert automatischen Logout bei aktiven Benutzern.
"""
try:
# Session-Aktivität NICHT in Cookie speichern - verwende externen Store
# session['last_activity'] = datetime.now().isoformat() # ENTFERNT
session.permanent = True
# Benutzer-Aktivität in Datenbank aktualisieren
with get_db_session() as db_session:
user = db_session.query(User).filter_by(id=current_user.id).first()
if user:
user.last_activity = datetime.now()
db_session.commit()
# Verbleibende Session-Zeit berechnen
session_start = session.get('session_start')
if session_start:
elapsed = (datetime.now() - datetime.fromisoformat(session_start)).total_seconds()
remaining = max(0, SESSION_LIFETIME_TD.total_seconds() - elapsed)
else:
remaining = SESSION_LIFETIME_TD.total_seconds()
return jsonify({
'success': True,
'remaining_seconds': int(remaining),
'session_lifetime': int(SESSION_LIFETIME_TD.total_seconds())
})
except Exception as e:
sessions_logger.error(f"Fehler beim Session-Heartbeat: {str(e)}")
return jsonify({'error': 'Fehler beim Aktualisieren der Session'}), 500
@sessions_blueprint.route('/status', methods=['GET'])
@login_required
def status():
"""Gibt den aktuellen Session-Status zurück"""
try:
# Session-Informationen sammeln
session_start = session.get('session_start')
last_activity = session.get('last_activity')
# Verbleibende Zeit berechnen
if session_start:
elapsed = (datetime.now() - datetime.fromisoformat(session_start)).total_seconds()
remaining = max(0, SESSION_LIFETIME_TD.total_seconds() - elapsed)
else:
remaining = SESSION_LIFETIME_TD.total_seconds()
# Inaktivitätszeit berechnen
if last_activity:
inactive_seconds = (datetime.now() - datetime.fromisoformat(last_activity)).total_seconds()
else:
inactive_seconds = 0
return jsonify({
'success': True,
'user': {
'id': current_user.id,
'username': current_user.username,
'email': current_user.email,
'name': current_user.name,
'is_admin': current_user.is_admin
},
'session': {
'start_time': session_start,
'last_activity': last_activity,
'remaining_seconds': int(remaining),
'inactive_seconds': int(inactive_seconds),
'lifetime_seconds': int(SESSION_LIFETIME_TD.total_seconds()),
'is_permanent': session.permanent
}
})
except Exception as e:
sessions_logger.error(f"Fehler beim Abrufen des Session-Status: {str(e)}")
return jsonify({'error': 'Fehler beim Abrufen des Session-Status'}), 500
@sessions_blueprint.route('/extend', methods=['POST'])
@login_required
def extend():
"""Verlängert die aktuelle Session"""
try:
# Nur Admins können Sessions verlängern
if not current_user.is_admin:
return jsonify({'error': 'Keine Berechtigung zum Verlängern der Session'}), 403
# Session-Daten NICHT in Cookie speichern - verwende externen Store
# session['session_start'] = datetime.now().isoformat() # ENTFERNT
# session['last_activity'] = datetime.now().isoformat() # ENTFERNT
session.permanent = True
# SystemLog erstellen
with get_db_session() as db_session:
SystemLog.log_system_event(
level="INFO",
message=f"Session verlängert für Benutzer {current_user.username}",
module="sessions",
user_id=current_user.id
)
db_session.commit()
sessions_logger.info(f"Session verlängert für Benutzer {current_user.id}")
return jsonify({
'success': True,
'message': 'Session wurde verlängert',
'new_lifetime_seconds': int(SESSION_LIFETIME_TD.total_seconds())
})
except Exception as e:
sessions_logger.error(f"Fehler beim Verlängern der Session: {str(e)}")
return jsonify({'error': 'Fehler beim Verlängern der Session'}), 500