"Refactor job scheduler and printer monitor for improved performance (feat)"
This commit is contained in:
@@ -3498,8 +3498,40 @@ def toggle_printer_power(printer_id):
|
||||
return jsonify({"error": "Administratorrechte erforderlich"}), 403
|
||||
|
||||
try:
|
||||
data = request.get_json()
|
||||
state = data.get("state", True) # Standard: einschalten
|
||||
# Robuste JSON-Datenverarbeitung
|
||||
data = {}
|
||||
try:
|
||||
if request.is_json and request.get_json():
|
||||
data = request.get_json()
|
||||
elif request.form:
|
||||
# Fallback für Form-Daten
|
||||
data = request.form.to_dict()
|
||||
except Exception as json_error:
|
||||
printers_logger.warning(f"Fehler beim Parsen der JSON-Daten für Drucker {printer_id}: {str(json_error)}")
|
||||
# Verwende Standard-Werte wenn JSON-Parsing fehlschlägt
|
||||
data = {}
|
||||
|
||||
# Standard-Zustand ermitteln (Toggle-Verhalten)
|
||||
db_session = get_db_session()
|
||||
printer = db_session.query(Printer).get(printer_id)
|
||||
|
||||
if not printer:
|
||||
db_session.close()
|
||||
return jsonify({"error": "Drucker nicht gefunden"}), 404
|
||||
|
||||
# Aktuellen Status ermitteln für Toggle-Verhalten
|
||||
current_status = getattr(printer, 'status', 'offline')
|
||||
current_active = getattr(printer, 'active', False)
|
||||
|
||||
# Zielzustand bestimmen
|
||||
if 'state' in data:
|
||||
# Expliziter Zustand angegeben
|
||||
state = bool(data.get("state", True))
|
||||
else:
|
||||
# Toggle-Verhalten: Umschalten basierend auf aktuellem Status
|
||||
state = not (current_status == "available" and current_active)
|
||||
|
||||
db_session.close()
|
||||
|
||||
# Steckdose schalten
|
||||
from utils.job_scheduler import toggle_plug
|
||||
@@ -3507,20 +3539,31 @@ def toggle_printer_power(printer_id):
|
||||
|
||||
if success:
|
||||
action = "eingeschaltet" if state else "ausgeschaltet"
|
||||
printers_logger.info(f"Drucker {printer.name} (ID: {printer_id}) erfolgreich {action} von Admin {current_user.name}")
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": f"Drucker erfolgreich {action}",
|
||||
"printer_id": printer_id,
|
||||
"state": state
|
||||
"printer_name": printer.name,
|
||||
"state": state,
|
||||
"action": action
|
||||
})
|
||||
else:
|
||||
printers_logger.error(f"Fehler beim Schalten der Steckdose für Drucker {printer_id}")
|
||||
return jsonify({
|
||||
"error": "Fehler beim Schalten der Steckdose"
|
||||
"success": False,
|
||||
"error": "Fehler beim Schalten der Steckdose",
|
||||
"printer_id": printer_id
|
||||
}), 500
|
||||
|
||||
except Exception as e:
|
||||
printers_logger.error(f"Fehler beim Schalten von Drucker {printer_id}: {str(e)}")
|
||||
return jsonify({"error": "Interner Serverfehler"}), 500
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"error": "Interner Serverfehler",
|
||||
"details": str(e)
|
||||
}), 500
|
||||
|
||||
@app.route("/api/admin/printers/<int:printer_id>/test-tapo", methods=["POST"])
|
||||
@login_required
|
||||
@@ -6293,6 +6336,7 @@ if __name__ == "__main__":
|
||||
app_logger.error(f"❌ Fehler beim Shutdown: {str(e)}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# Signal-Handler registrieren (Windows-kompatibel)
|
||||
if os.name == 'nt': # Windows
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
@@ -6696,3 +6740,270 @@ def cleanup_temp_files():
|
||||
except Exception as e:
|
||||
app_logger.error(f"Fehler beim Aufräumen temporärer Dateien: {str(e)}")
|
||||
return jsonify({'error': f'Fehler beim Aufräumen: {str(e)}'}), 500
|
||||
|
||||
# ===== FEHLENDE DRUCKER-SPEZIFISCHE API-ENDPOINTS =====
|
||||
|
||||
@app.route("/api/printers/<int:printer_id>/jobs", methods=["GET"])
|
||||
@login_required
|
||||
def get_printer_jobs(printer_id):
|
||||
"""Gibt alle Jobs für einen spezifischen Drucker zurück."""
|
||||
try:
|
||||
db_session = get_db_session()
|
||||
|
||||
# Prüfen ob Drucker existiert
|
||||
printer = db_session.query(Printer).get(printer_id)
|
||||
if not printer:
|
||||
db_session.close()
|
||||
return jsonify({"error": "Drucker nicht gefunden"}), 404
|
||||
|
||||
# Jobs für diesen Drucker abrufen
|
||||
jobs = db_session.query(Job).filter(Job.printer_id == printer_id).order_by(Job.created_at.desc()).all()
|
||||
|
||||
jobs_data = []
|
||||
for job in jobs:
|
||||
job_data = {
|
||||
"id": job.id,
|
||||
"title": job.title,
|
||||
"status": job.status,
|
||||
"priority": job.priority,
|
||||
"created_at": job.created_at.isoformat() if job.created_at else None,
|
||||
"scheduled_time": job.scheduled_time.isoformat() if job.scheduled_time else None,
|
||||
"started_at": job.started_at.isoformat() if job.started_at else None,
|
||||
"finished_at": job.finished_at.isoformat() if job.finished_at else None,
|
||||
"estimated_duration": job.estimated_duration,
|
||||
"user_id": job.user_id,
|
||||
"printer_id": job.printer_id,
|
||||
"printer_name": printer.name
|
||||
}
|
||||
jobs_data.append(job_data)
|
||||
|
||||
db_session.close()
|
||||
|
||||
return jsonify({
|
||||
"jobs": jobs_data,
|
||||
"total": len(jobs_data),
|
||||
"printer": {
|
||||
"id": printer.id,
|
||||
"name": printer.name,
|
||||
"status": printer.status
|
||||
}
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
printers_logger.error(f"Fehler beim Abrufen der Jobs für Drucker {printer_id}: {str(e)}")
|
||||
return jsonify({"error": "Interner Serverfehler"}), 500
|
||||
|
||||
@app.route("/api/printers/<int:printer_id>/stats", methods=["GET"])
|
||||
@login_required
|
||||
def get_printer_stats(printer_id):
|
||||
"""Gibt Statistiken für einen spezifischen Drucker zurück."""
|
||||
try:
|
||||
db_session = get_db_session()
|
||||
|
||||
# Prüfen ob Drucker existiert
|
||||
printer = db_session.query(Printer).get(printer_id)
|
||||
if not printer:
|
||||
db_session.close()
|
||||
return jsonify({"error": "Drucker nicht gefunden"}), 404
|
||||
|
||||
# Statistiken berechnen
|
||||
total_jobs = db_session.query(Job).filter(Job.printer_id == printer_id).count()
|
||||
completed_jobs = db_session.query(Job).filter(
|
||||
Job.printer_id == printer_id,
|
||||
Job.status == "completed"
|
||||
).count()
|
||||
failed_jobs = db_session.query(Job).filter(
|
||||
Job.printer_id == printer_id,
|
||||
Job.status == "failed"
|
||||
).count()
|
||||
active_jobs = db_session.query(Job).filter(
|
||||
Job.printer_id == printer_id,
|
||||
Job.status.in_(["scheduled", "running"])
|
||||
).count()
|
||||
|
||||
# Durchschnittliche Job-Dauer berechnen
|
||||
avg_duration_result = db_session.query(func.avg(Job.estimated_duration)).filter(
|
||||
Job.printer_id == printer_id,
|
||||
Job.status == "completed",
|
||||
Job.estimated_duration.isnot(None)
|
||||
).scalar()
|
||||
|
||||
avg_duration = round(avg_duration_result, 2) if avg_duration_result else 0
|
||||
|
||||
# Erfolgsrate berechnen
|
||||
success_rate = round((completed_jobs / total_jobs * 100), 2) if total_jobs > 0 else 0
|
||||
|
||||
# Letzte Aktivität
|
||||
last_job = db_session.query(Job).filter(Job.printer_id == printer_id).order_by(Job.created_at.desc()).first()
|
||||
last_activity = last_job.created_at.isoformat() if last_job and last_job.created_at else None
|
||||
|
||||
db_session.close()
|
||||
|
||||
stats_data = {
|
||||
"printer": {
|
||||
"id": printer.id,
|
||||
"name": printer.name,
|
||||
"status": printer.status,
|
||||
"location": printer.location
|
||||
},
|
||||
"jobs": {
|
||||
"total": total_jobs,
|
||||
"completed": completed_jobs,
|
||||
"failed": failed_jobs,
|
||||
"active": active_jobs,
|
||||
"success_rate": success_rate
|
||||
},
|
||||
"performance": {
|
||||
"average_duration": avg_duration,
|
||||
"last_activity": last_activity
|
||||
},
|
||||
"generated_at": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
return jsonify(stats_data)
|
||||
|
||||
except Exception as e:
|
||||
printers_logger.error(f"Fehler beim Abrufen der Statistiken für Drucker {printer_id}: {str(e)}")
|
||||
return jsonify({"error": "Interner Serverfehler"}), 500
|
||||
|
||||
@app.route("/api/printers/<int:printer_id>/test", methods=["POST"])
|
||||
@login_required
|
||||
def test_printer_connection(printer_id):
|
||||
"""Testet die Verbindung zu einem spezifischen Drucker."""
|
||||
try:
|
||||
db_session = get_db_session()
|
||||
|
||||
# Prüfen ob Drucker existiert
|
||||
printer = db_session.query(Printer).get(printer_id)
|
||||
if not printer:
|
||||
db_session.close()
|
||||
return jsonify({"error": "Drucker nicht gefunden"}), 404
|
||||
|
||||
# IP-Adresse für Test ermitteln
|
||||
ip_to_test = printer.plug_ip if printer.plug_ip else getattr(printer, 'ip_address', None)
|
||||
|
||||
if not ip_to_test:
|
||||
db_session.close()
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"error": "Keine IP-Adresse für Drucker konfiguriert",
|
||||
"printer": {
|
||||
"id": printer.id,
|
||||
"name": printer.name
|
||||
}
|
||||
}), 400
|
||||
|
||||
# Verbindungstest durchführen
|
||||
printers_logger.info(f"Teste Verbindung zu Drucker {printer.name} (ID: {printer_id}) auf IP {ip_to_test}")
|
||||
|
||||
status, active = check_printer_status(ip_to_test, timeout=10)
|
||||
|
||||
# Status in Datenbank aktualisieren
|
||||
printer.status = "available" if status == "online" else "offline"
|
||||
if hasattr(printer, 'active'):
|
||||
printer.active = active
|
||||
db_session.commit()
|
||||
|
||||
test_result = {
|
||||
"success": status == "online",
|
||||
"status": status,
|
||||
"active": active,
|
||||
"ip_address": ip_to_test,
|
||||
"printer": {
|
||||
"id": printer.id,
|
||||
"name": printer.name,
|
||||
"location": printer.location,
|
||||
"model": printer.model
|
||||
},
|
||||
"test_time": datetime.now().isoformat(),
|
||||
"message": f"Drucker ist {'online und erreichbar' if status == 'online' else 'offline oder nicht erreichbar'}"
|
||||
}
|
||||
|
||||
db_session.close()
|
||||
|
||||
printers_logger.info(f"Verbindungstest für Drucker {printer.name}: {status}")
|
||||
|
||||
return jsonify(test_result)
|
||||
|
||||
except Exception as e:
|
||||
printers_logger.error(f"Fehler beim Testen der Verbindung zu Drucker {printer_id}: {str(e)}")
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"error": "Interner Serverfehler beim Verbindungstest",
|
||||
"details": str(e)
|
||||
}), 500
|
||||
|
||||
# ===== ADMIN-SPEZIFISCHE DRUCKER-ENDPOINTS =====
|
||||
|
||||
@app.route("/api/admin/printers/create", methods=["POST"])
|
||||
@login_required
|
||||
@admin_required
|
||||
def admin_create_printer_api():
|
||||
"""Admin-Endpoint zum Erstellen neuer Drucker."""
|
||||
try:
|
||||
data = request.get_json()
|
||||
|
||||
if not data:
|
||||
return jsonify({"error": "Keine Daten empfangen"}), 400
|
||||
|
||||
# Pflichtfelder prüfen
|
||||
required_fields = ["name", "plug_ip"]
|
||||
for field in required_fields:
|
||||
if field not in data or not data[field]:
|
||||
return jsonify({"error": f"Feld '{field}' ist erforderlich"}), 400
|
||||
|
||||
db_session = get_db_session()
|
||||
|
||||
# Prüfen, ob bereits ein Drucker mit diesem Namen existiert
|
||||
existing_printer = db_session.query(Printer).filter(Printer.name == data["name"]).first()
|
||||
if existing_printer:
|
||||
db_session.close()
|
||||
return jsonify({"error": "Ein Drucker mit diesem Namen existiert bereits"}), 400
|
||||
|
||||
# Neuen Drucker erstellen
|
||||
new_printer = Printer(
|
||||
name=data["name"],
|
||||
model=data.get("model", ""),
|
||||
location=data.get("location", ""),
|
||||
mac_address=data.get("mac_address", ""),
|
||||
plug_ip=data["plug_ip"],
|
||||
status="offline",
|
||||
active=True,
|
||||
created_at=datetime.now()
|
||||
)
|
||||
|
||||
db_session.add(new_printer)
|
||||
db_session.commit()
|
||||
|
||||
# Sofortiger Status-Check
|
||||
if new_printer.plug_ip:
|
||||
status, active = check_printer_status(new_printer.plug_ip)
|
||||
new_printer.status = "available" if status == "online" else "offline"
|
||||
new_printer.active = active
|
||||
db_session.commit()
|
||||
|
||||
printer_data = {
|
||||
"id": new_printer.id,
|
||||
"name": new_printer.name,
|
||||
"model": new_printer.model,
|
||||
"location": new_printer.location,
|
||||
"mac_address": new_printer.mac_address,
|
||||
"plug_ip": new_printer.plug_ip,
|
||||
"status": new_printer.status,
|
||||
"active": new_printer.active,
|
||||
"created_at": new_printer.created_at.isoformat()
|
||||
}
|
||||
|
||||
db_session.close()
|
||||
|
||||
printers_logger.info(f"Admin {current_user.name} hat Drucker '{new_printer.name}' erstellt")
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": "Drucker erfolgreich erstellt",
|
||||
"printer": printer_data
|
||||
}), 201
|
||||
|
||||
except Exception as e:
|
||||
printers_logger.error(f"Fehler beim Erstellen eines Druckers durch Admin: {str(e)}")
|
||||
return jsonify({"error": "Interner Serverfehler"}), 500
|
||||
|
Reference in New Issue
Block a user