🎉 Backend: Aktualisierung der API-Routen und Verbesserung der Fehlerprotokollierung für Job-Erstellung. URL-Präfix für Jobs-Blueprint geändert, um Konflikte zu vermeiden. Erweiterte Fehlerbehandlung und Protokollierung für kritische Systemfehler hinzugefügt. 🛠️
This commit is contained in:
@@ -12,8 +12,8 @@ from sqlalchemy.orm import joinedload
|
||||
from models import get_db_session, Job, Printer
|
||||
from utils.logging_config import get_logger
|
||||
|
||||
# Blueprint initialisieren
|
||||
jobs_blueprint = Blueprint('jobs', __name__, url_prefix='/api/jobs')
|
||||
# Blueprint initialisieren - URL-Präfix geändert um Konflikte zu vermeiden
|
||||
jobs_blueprint = Blueprint('jobs', __name__, url_prefix='/api/jobs-bp')
|
||||
|
||||
# Logger für Jobs
|
||||
jobs_logger = get_logger("jobs")
|
||||
@@ -54,21 +54,27 @@ def get_jobs():
|
||||
db_session = get_db_session()
|
||||
|
||||
try:
|
||||
jobs_logger.info(f"📋 Jobs-Abfrage gestartet von Benutzer {current_user.id} (Admin: {current_user.is_admin})")
|
||||
|
||||
# Paginierung unterstützen
|
||||
page = request.args.get('page', 1, type=int)
|
||||
per_page = request.args.get('per_page', 50, type=int)
|
||||
status_filter = request.args.get('status')
|
||||
|
||||
jobs_logger.debug(f"📋 Parameter: page={page}, per_page={per_page}, status_filter={status_filter}")
|
||||
|
||||
# Query aufbauen
|
||||
query = db_session.query(Job).options(joinedload(Job.user), joinedload(Job.printer))
|
||||
|
||||
# Admin sieht alle Jobs, User nur eigene
|
||||
if not current_user.is_admin:
|
||||
query = query.filter(Job.user_id == int(current_user.id))
|
||||
jobs_logger.debug(f"🔒 Benutzerfilter angewendet für User {current_user.id}")
|
||||
|
||||
# Status-Filter anwenden
|
||||
if status_filter:
|
||||
query = query.filter(Job.status == status_filter)
|
||||
jobs_logger.debug(f"🏷️ Status-Filter angewendet: {status_filter}")
|
||||
|
||||
# Sortierung: neueste zuerst
|
||||
query = query.order_by(Job.created_at.desc())
|
||||
@@ -85,7 +91,7 @@ def get_jobs():
|
||||
|
||||
db_session.close()
|
||||
|
||||
jobs_logger.info(f"Jobs abgerufen: {len(job_dicts)} von {total_count} (Seite {page})")
|
||||
jobs_logger.info(f"✅ Jobs erfolgreich abgerufen: {len(job_dicts)} von {total_count} (Seite {page})")
|
||||
|
||||
return jsonify({
|
||||
"jobs": job_dicts,
|
||||
@@ -97,9 +103,12 @@ def get_jobs():
|
||||
}
|
||||
})
|
||||
except Exception as e:
|
||||
jobs_logger.error(f"Fehler beim Abrufen von Jobs: {str(e)}")
|
||||
db_session.close()
|
||||
return jsonify({"error": "Interner Serverfehler"}), 500
|
||||
jobs_logger.error(f"❌ Fehler beim Abrufen von Jobs: {str(e)}", exc_info=True)
|
||||
try:
|
||||
db_session.close()
|
||||
except:
|
||||
pass
|
||||
return jsonify({"error": "Interner Serverfehler", "details": str(e)}), 500
|
||||
|
||||
@jobs_blueprint.route('/<int:job_id>', methods=['GET'])
|
||||
@login_required
|
||||
@@ -109,10 +118,13 @@ def get_job(job_id):
|
||||
db_session = get_db_session()
|
||||
|
||||
try:
|
||||
jobs_logger.info(f"🔍 Job-Detail-Abfrage für Job {job_id} von Benutzer {current_user.id}")
|
||||
|
||||
# Eagerly load the user and printer relationships
|
||||
job = db_session.query(Job).options(joinedload(Job.user), joinedload(Job.printer)).filter(Job.id == job_id).first()
|
||||
|
||||
if not job:
|
||||
jobs_logger.warning(f"⚠️ Job {job_id} nicht gefunden")
|
||||
db_session.close()
|
||||
return jsonify({"error": "Job nicht gefunden"}), 404
|
||||
|
||||
@@ -120,11 +132,15 @@ def get_job(job_id):
|
||||
job_dict = job.to_dict()
|
||||
db_session.close()
|
||||
|
||||
jobs_logger.info(f"✅ Job-Details erfolgreich abgerufen für Job {job_id}")
|
||||
return jsonify(job_dict)
|
||||
except Exception as e:
|
||||
jobs_logger.error(f"Fehler beim Abrufen des Jobs {job_id}: {str(e)}")
|
||||
db_session.close()
|
||||
return jsonify({"error": "Interner Serverfehler"}), 500
|
||||
jobs_logger.error(f"❌ Fehler beim Abrufen des Jobs {job_id}: {str(e)}", exc_info=True)
|
||||
try:
|
||||
db_session.close()
|
||||
except:
|
||||
pass
|
||||
return jsonify({"error": "Interner Serverfehler", "details": str(e)}), 500
|
||||
|
||||
@jobs_blueprint.route('', methods=['POST'])
|
||||
@login_required
|
||||
@@ -142,18 +158,31 @@ def create_job():
|
||||
}
|
||||
"""
|
||||
try:
|
||||
jobs_logger.info(f"🚀 Neue Job-Erstellung gestartet von Benutzer {current_user.id}")
|
||||
|
||||
data = request.json
|
||||
if not data:
|
||||
jobs_logger.error("❌ Keine JSON-Daten empfangen")
|
||||
return jsonify({"error": "Keine JSON-Daten empfangen"}), 400
|
||||
|
||||
jobs_logger.debug(f"📋 Empfangene Daten: {data}")
|
||||
|
||||
# Pflichtfelder prüfen
|
||||
required_fields = ["printer_id", "start_iso", "duration_minutes"]
|
||||
for field in required_fields:
|
||||
if field not in data:
|
||||
jobs_logger.error(f"❌ Pflichtfeld '{field}' fehlt in den Daten")
|
||||
return jsonify({"error": f"Feld '{field}' fehlt"}), 400
|
||||
|
||||
# Daten extrahieren und validieren
|
||||
printer_id = int(data["printer_id"])
|
||||
start_iso = data["start_iso"]
|
||||
duration_minutes = int(data["duration_minutes"])
|
||||
try:
|
||||
printer_id = int(data["printer_id"])
|
||||
start_iso = data["start_iso"]
|
||||
duration_minutes = int(data["duration_minutes"])
|
||||
jobs_logger.debug(f"✅ Grunddaten validiert: printer_id={printer_id}, duration={duration_minutes}")
|
||||
except (ValueError, TypeError) as e:
|
||||
jobs_logger.error(f"❌ Fehler bei Datenvalidierung: {str(e)}")
|
||||
return jsonify({"error": f"Ungültige Datenformate: {str(e)}"}), 400
|
||||
|
||||
# Optional: Jobtitel, Beschreibung und Dateipfad
|
||||
name = data.get("name", f"Druckjob vom {datetime.now().strftime('%d.%m.%Y %H:%M')}")
|
||||
@@ -163,11 +192,14 @@ def create_job():
|
||||
# Start-Zeit parsen
|
||||
try:
|
||||
start_at = datetime.fromisoformat(start_iso.replace('Z', '+00:00'))
|
||||
except ValueError:
|
||||
return jsonify({"error": "Ungültiges Startdatum"}), 400
|
||||
jobs_logger.debug(f"✅ Startzeit geparst: {start_at}")
|
||||
except ValueError as e:
|
||||
jobs_logger.error(f"❌ Ungültiges Startdatum '{start_iso}': {str(e)}")
|
||||
return jsonify({"error": f"Ungültiges Startdatum: {str(e)}"}), 400
|
||||
|
||||
# Dauer validieren
|
||||
if duration_minutes <= 0:
|
||||
jobs_logger.error(f"❌ Ungültige Dauer: {duration_minutes} Minuten")
|
||||
return jsonify({"error": "Dauer muss größer als 0 sein"}), 400
|
||||
|
||||
# End-Zeit berechnen
|
||||
@@ -175,47 +207,63 @@ def create_job():
|
||||
|
||||
db_session = get_db_session()
|
||||
|
||||
# Prüfen, ob der Drucker existiert
|
||||
printer = db_session.query(Printer).get(printer_id)
|
||||
if not printer:
|
||||
try:
|
||||
# Prüfen, ob der Drucker existiert
|
||||
printer = db_session.query(Printer).get(printer_id)
|
||||
if not printer:
|
||||
jobs_logger.error(f"❌ Drucker mit ID {printer_id} nicht gefunden")
|
||||
db_session.close()
|
||||
return jsonify({"error": "Drucker nicht gefunden"}), 404
|
||||
|
||||
jobs_logger.debug(f"✅ Drucker gefunden: {printer.name} (ID: {printer_id})")
|
||||
|
||||
# Prüfen, ob der Drucker online ist
|
||||
printer_status, printer_active = check_printer_status(printer.plug_ip if printer.plug_ip else "")
|
||||
jobs_logger.debug(f"🖨️ Drucker-Status: {printer_status}, aktiv: {printer_active}")
|
||||
|
||||
# Status basierend auf Drucker-Verfügbarkeit setzen
|
||||
if printer_status == "online" and printer_active:
|
||||
job_status = "scheduled"
|
||||
else:
|
||||
job_status = "waiting_for_printer"
|
||||
|
||||
jobs_logger.info(f"📋 Job-Status festgelegt: {job_status}")
|
||||
|
||||
# Neuen Job erstellen
|
||||
new_job = Job(
|
||||
name=name,
|
||||
description=description,
|
||||
printer_id=printer_id,
|
||||
user_id=current_user.id,
|
||||
owner_id=current_user.id,
|
||||
start_at=start_at,
|
||||
end_at=end_at,
|
||||
status=job_status,
|
||||
file_path=file_path,
|
||||
duration_minutes=duration_minutes
|
||||
)
|
||||
|
||||
db_session.add(new_job)
|
||||
db_session.commit()
|
||||
|
||||
# Job-Objekt für die Antwort serialisieren
|
||||
job_dict = new_job.to_dict()
|
||||
db_session.close()
|
||||
return jsonify({"error": "Drucker nicht gefunden"}), 404
|
||||
|
||||
# Prüfen, ob der Drucker online ist
|
||||
printer_status, printer_active = check_printer_status(printer.plug_ip if printer.plug_ip else "")
|
||||
|
||||
# Status basierend auf Drucker-Verfügbarkeit setzen
|
||||
if printer_status == "online" and printer_active:
|
||||
job_status = "scheduled"
|
||||
else:
|
||||
job_status = "waiting_for_printer"
|
||||
|
||||
# Neuen Job erstellen
|
||||
new_job = Job(
|
||||
name=name,
|
||||
description=description,
|
||||
printer_id=printer_id,
|
||||
user_id=current_user.id,
|
||||
owner_id=current_user.id,
|
||||
start_at=start_at,
|
||||
end_at=end_at,
|
||||
status=job_status,
|
||||
file_path=file_path,
|
||||
duration_minutes=duration_minutes
|
||||
)
|
||||
|
||||
db_session.add(new_job)
|
||||
db_session.commit()
|
||||
|
||||
# Job-Objekt für die Antwort serialisieren
|
||||
job_dict = new_job.to_dict()
|
||||
db_session.close()
|
||||
|
||||
jobs_logger.info(f"Neuer Job {new_job.id} erstellt für Drucker {printer_id}, Start: {start_at}, Dauer: {duration_minutes} Minuten")
|
||||
return jsonify({"job": job_dict}), 201
|
||||
|
||||
jobs_logger.info(f"✅ Neuer Job {new_job.id} erfolgreich erstellt für Drucker {printer_id}, Start: {start_at}, Dauer: {duration_minutes} Minuten")
|
||||
return jsonify({"job": job_dict}), 201
|
||||
|
||||
except Exception as db_error:
|
||||
jobs_logger.error(f"❌ Datenbankfehler beim Job-Erstellen: {str(db_error)}")
|
||||
try:
|
||||
db_session.rollback()
|
||||
db_session.close()
|
||||
except:
|
||||
pass
|
||||
return jsonify({"error": "Datenbankfehler beim Erstellen des Jobs", "details": str(db_error)}), 500
|
||||
|
||||
except Exception as e:
|
||||
jobs_logger.error(f"Fehler beim Erstellen eines Jobs: {str(e)}")
|
||||
jobs_logger.error(f"❌ Kritischer Fehler beim Erstellen eines Jobs: {str(e)}", exc_info=True)
|
||||
return jsonify({"error": "Interner Serverfehler", "details": str(e)}), 500
|
||||
|
||||
@jobs_blueprint.route('/<int:job_id>', methods=['PUT'])
|
||||
|
Reference in New Issue
Block a user