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

258 lines
9.4 KiB
Python

"""
API-Blueprint für das 3D-Druck-Management-System
Dieses Modul enthält allgemeine API-Endpunkte und WebSocket-Fallback-Funktionalität.
"""
import logging
from datetime import datetime
from flask import Blueprint, jsonify, request, session
from flask_login import login_required, current_user
from models import get_db_session, User, Notification
from utils.logging_config import get_logger
# Blueprint erstellen
api_blueprint = Blueprint('api', __name__, url_prefix='/api')
# Logger initialisieren
api_logger = get_logger("api")
@api_blueprint.route('/ws-fallback', methods=['GET'])
@login_required
def ws_fallback():
"""WebSocket-Fallback für Browser ohne WebSocket-Unterstützung"""
try:
# Einfache Polling-Antwort für Clients ohne WebSocket
return jsonify({
'success': True,
'timestamp': datetime.now().isoformat(),
'user_id': current_user.id,
'message': 'WebSocket-Fallback aktiv'
})
except Exception as e:
api_logger.error(f"Fehler im WebSocket-Fallback: {str(e)}")
return jsonify({'error': 'WebSocket-Fallback-Fehler'}), 500
@api_blueprint.route('/notifications', methods=['GET'])
@login_required
def get_notifications():
"""Abrufen der Benutzer-Benachrichtigungen"""
try:
db_session = get_db_session()
# Benutzer-spezifische Benachrichtigungen
notifications = db_session.query(Notification).filter(
Notification.user_id == current_user.id,
Notification.is_read == False
).order_by(Notification.created_at.desc()).limit(20).all()
notification_list = []
for notification in notifications:
notification_list.append({
'id': notification.id,
'title': notification.title,
'message': notification.message,
'type': notification.type,
'created_at': notification.created_at.isoformat(),
'is_read': notification.is_read
})
db_session.close()
return jsonify({
'success': True,
'notifications': notification_list,
'count': len(notification_list)
})
except Exception as e:
api_logger.error(f"Fehler beim Abrufen der Benachrichtigungen: {str(e)}")
return jsonify({'error': 'Fehler beim Laden der Benachrichtigungen'}), 500
@api_blueprint.route('/notifications/<int:notification_id>/read', methods=['POST'])
@login_required
def mark_notification_read(notification_id):
"""Markiert eine Benachrichtigung als gelesen"""
try:
db_session = get_db_session()
notification = db_session.query(Notification).filter(
Notification.id == notification_id,
Notification.user_id == current_user.id
).first()
if not notification:
db_session.close()
return jsonify({'error': 'Benachrichtigung nicht gefunden'}), 404
notification.is_read = True
notification.read_at = datetime.now()
db_session.commit()
db_session.close()
api_logger.info(f"Benachrichtigung {notification_id} als gelesen markiert")
return jsonify({
'success': True,
'message': 'Benachrichtigung als gelesen markiert'
})
except Exception as e:
api_logger.error(f"Fehler beim Markieren der Benachrichtigung: {str(e)}")
return jsonify({'error': 'Fehler beim Markieren der Benachrichtigung'}), 500
@api_blueprint.route('/system/status', methods=['GET'])
@login_required
def system_status():
"""Gibt den System-Status zurück"""
try:
return jsonify({
'success': True,
'status': 'online',
'timestamp': datetime.now().isoformat(),
'user': {
'id': current_user.id,
'username': current_user.username,
'is_admin': current_user.is_admin
}
})
except Exception as e:
api_logger.error(f"Fehler beim Abrufen des System-Status: {str(e)}")
return jsonify({'error': 'System-Status nicht verfügbar'}), 500
@api_blueprint.route('/heartbeat', methods=['POST'])
@login_required
def heartbeat():
"""Heartbeat-Endpunkt für Frontend-Verbindungsmonitoring"""
try:
# Session-Aktivität NICHT in Cookie speichern
# session['last_heartbeat'] = datetime.now().strftime('%H:%M:%S') # ENTFERNT
session.permanent = True
return jsonify({
'success': True,
'timestamp': datetime.now().isoformat(),
'user_id': current_user.id
})
except Exception as e:
api_logger.error(f"Fehler im Heartbeat: {str(e)}")
return jsonify({'error': 'Heartbeat-Fehler'}), 500
@api_blueprint.route('/session/status', methods=['GET'])
def session_status():
"""Gibt den aktuellen Session-Status zurück"""
try:
# Prüfe ob Benutzer über Flask-Login authentifiziert ist
if hasattr(current_user, 'is_authenticated') and current_user.is_authenticated:
# Benutzer ist angemeldet
from datetime import timedelta
from backend.config.settings import SESSION_LIFETIME
# Session-Informationen sammeln
session_start = session.get('session_start', datetime.now().isoformat())
# Standard Session-Lifetime verwenden
max_inactive_minutes = int(SESSION_LIFETIME.total_seconds() / 60)
# Verbleibende Zeit berechnen (volle Session-Zeit wenn angemeldet)
time_left_seconds = int(SESSION_LIFETIME.total_seconds())
return jsonify({
'success': True,
'user': {
'id': current_user.id,
'username': current_user.username,
'email': current_user.email,
'is_admin': current_user.is_admin if hasattr(current_user, 'is_admin') else False
},
'session': {
'is_authenticated': True,
'max_inactive_minutes': max_inactive_minutes,
'time_left_seconds': time_left_seconds,
'last_activity': datetime.now().isoformat(),
'session_start': session_start
},
'timestamp': datetime.now().isoformat()
})
else:
# Benutzer ist nicht angemeldet
return jsonify({
'success': True,
'user': None,
'session': {
'is_authenticated': False,
'max_inactive_minutes': 0,
'time_left_seconds': 0,
'last_activity': None,
'session_start': None
},
'timestamp': datetime.now().isoformat()
})
except Exception as e:
api_logger.error(f"Fehler beim Abrufen des Session-Status: {str(e)}")
return jsonify({
'success': False,
'error': 'Session-Status nicht verfügbar',
'message': str(e)
}), 500
@api_blueprint.route('/session/heartbeat', methods=['POST'])
@login_required
def session_heartbeat():
"""Session-Heartbeat für automatische Verlängerung"""
try:
# Letzte Aktivität NICHT in Cookie speichern (Cookie-Größe reduzieren)
# session['last_activity'] = datetime.now().isoformat() # ENTFERNT
# Session als permanent markieren für Verlängerung
session.permanent = True
# Verbleibende Session-Zeit berechnen
from backend.config.settings import SESSION_LIFETIME
time_left_seconds = int(SESSION_LIFETIME.total_seconds())
api_logger.debug(f"Session-Heartbeat von Benutzer {current_user.username}")
return jsonify({
'success': True,
'message': 'Session aktualisiert',
'time_left_seconds': time_left_seconds,
'timestamp': datetime.now().isoformat()
})
except Exception as e:
api_logger.error(f"Fehler beim Session-Heartbeat: {str(e)}")
return jsonify({
'success': False,
'error': 'Session-Heartbeat fehlgeschlagen',
'message': str(e)
}), 500
@api_blueprint.route('/session/extend', methods=['POST'])
@login_required
def extend_session():
"""Verlängert die aktuelle Session"""
try:
data = request.get_json() or {}
extend_minutes = data.get('extend_minutes', 30)
# Session verlängern durch Markierung als permanent
session.permanent = True
# Neue Aktivitätszeit NICHT in Cookie speichern
# session['last_activity'] = datetime.now().isoformat() # ENTFERNT
api_logger.info(f"Session für Benutzer {current_user.username} um {extend_minutes} Minuten verlängert")
return jsonify({
'success': True,
'message': f'Session um {extend_minutes} Minuten verlängert',
'extended_minutes': extend_minutes,
'timestamp': datetime.now().isoformat()
})
except Exception as e:
api_logger.error(f"Fehler beim Verlängern der Session: {str(e)}")
return jsonify({
'success': False,
'error': 'Session-Verlängerung fehlgeschlagen',
'message': str(e)
}), 500