"feat: Introduce test suite for printer functionality in backend"

This commit is contained in:
2025-05-29 17:07:42 +02:00
parent 6e8755775c
commit 2177975513
3 changed files with 1701 additions and 159 deletions

View File

@@ -4226,7 +4226,301 @@ def force_update_all_printer_status():
@app.route('/api/admin/cache/clear', methods=['POST'])
@admin_required
def clear_admin_cache():
logger.error(f"Fehler beim Ablehnen der Gastanfrage {request_id}: {str(e)}")
"""Löscht den Admin-Cache."""
try:
# Session-Cache für Admin löschen
admin_cache_keys = [
'admin_users_cache',
'admin_printers_cache',
'admin_stats_cache',
'admin_guest_requests_cache'
]
cleared = 0
for key in admin_cache_keys:
if key in session:
del session[key]
cleared += 1
return jsonify({
"success": True,
"message": f"Admin-Cache geleert ({cleared} Einträge)"
})
except Exception as e:
return jsonify({"error": f"Fehler beim Löschen des Admin-Cache: {str(e)}"}), 500
# ===== ADMIN GUEST REQUEST MANAGEMENT APIs =====
@app.route("/api/admin/requests", methods=["GET"])
@admin_required
def admin_get_guest_requests():
"""
Gibt alle Gastanfragen für Admin-Verwaltung zurück.
Unterstützt Filterung und Paginierung.
"""
try:
page = request.args.get('page', 1, type=int)
per_page = min(request.args.get('per_page', 20, type=int), 100)
status_filter = request.args.get('status', 'all')
db_session = get_db_session()
# Basis-Query für Gastanfragen
query = db_session.query(GuestRequest)
# Status-Filter anwenden
if status_filter == 'pending':
query = query.filter(GuestRequest.processed_at.is_(None))
elif status_filter == 'approved':
query = query.filter(
GuestRequest.processed_at.isnot(None),
GuestRequest.rejection_reason.is_(None)
)
elif status_filter == 'denied':
query = query.filter(GuestRequest.rejection_reason.isnot(None))
# Sortierung nach neuesten zuerst
query = query.order_by(desc(GuestRequest.created_at))
# Paginierung
paginated_requests = query.paginate(
page=page,
per_page=per_page,
error_out=False
)
requests_data = []
for req in paginated_requests.items:
request_data = {
"id": req.id,
"guest_name": req.guest_name,
"guest_email": req.guest_email,
"company": req.company,
"visit_purpose": req.visit_purpose,
"requested_printer_id": req.requested_printer_id,
"printer_name": req.printer.name if req.printer else "Beliebiger Drucker",
"urgency": req.urgency,
"additional_notes": req.additional_notes,
"created_at": req.created_at.isoformat(),
"processed_at": req.processed_at.isoformat() if req.processed_at else None,
"processed_by": req.processed_by,
"approval_notes": req.approval_notes,
"rejection_reason": req.rejection_reason,
"status": "approved" if req.processed_at and not req.rejection_reason else "denied" if req.rejection_reason else "pending",
"otp_code": req.otp_code,
"otp_used_at": req.otp_used_at.isoformat() if req.otp_used_at else None
}
requests_data.append(request_data)
db_session.close()
return jsonify({
"requests": requests_data,
"pagination": {
"page": page,
"per_page": per_page,
"total": paginated_requests.total,
"pages": paginated_requests.pages,
"has_next": paginated_requests.has_next,
"has_prev": paginated_requests.has_prev
},
"filters": {
"status": status_filter
}
})
except Exception as e:
app_logger.error(f"Fehler beim Abrufen der Gastanfragen: {str(e)}")
return jsonify({"error": "Interner Serverfehler"}), 500
# ===== ADMIN API-ROUTEN FÜR BENUTZER UND DRUCKER =====
@app.route("/api/admin/requests/<int:request_id>", methods=["GET"])
@admin_required
def admin_get_guest_request_details(request_id):
"""Gibt detaillierte Informationen zu einer spezifischen Gastanfrage zurück."""
try:
db_session = get_db_session()
guest_request = db_session.query(GuestRequest).get(request_id)
if not guest_request:
db_session.close()
return jsonify({"error": "Gastanfrage nicht gefunden"}), 404
# Detaillierte Daten zusammenstellen
request_data = {
"id": guest_request.id,
"guest_name": guest_request.guest_name,
"guest_email": guest_request.guest_email,
"company": guest_request.company,
"visit_purpose": guest_request.visit_purpose,
"requested_printer_id": guest_request.requested_printer_id,
"printer": {
"id": guest_request.printer.id,
"name": guest_request.printer.name,
"location": guest_request.printer.location,
"model": guest_request.printer.model
} if guest_request.printer else None,
"urgency": guest_request.urgency,
"additional_notes": guest_request.additional_notes,
"created_at": guest_request.created_at.isoformat(),
"processed_at": guest_request.processed_at.isoformat() if guest_request.processed_at else None,
"processed_by": guest_request.processed_by,
"approval_notes": guest_request.approval_notes,
"rejection_reason": guest_request.rejection_reason,
"status": "approved" if guest_request.processed_at and not guest_request.rejection_reason else "denied" if guest_request.rejection_reason else "pending",
"otp_code": guest_request.otp_code,
"otp_used_at": guest_request.otp_used_at.isoformat() if guest_request.otp_used_at else None
}
db_session.close()
return jsonify({"request": request_data})
except Exception as e:
app_logger.error(f"Fehler beim Abrufen der Gastanfrage {request_id}: {str(e)}")
return jsonify({"error": "Interner Serverfehler"}), 500
@app.route("/api/requests/<int:request_id>/approve", methods=["POST"])
@admin_required
def admin_approve_guest_request(request_id):
"""Genehmigt eine Gastanfrage und weist optional einen Drucker zu."""
try:
data = request.json or {}
approval_notes = data.get('approval_notes', '')
assigned_printer_id = data.get('assigned_printer_id')
db_session = get_db_session()
guest_request = db_session.query(GuestRequest).get(request_id)
if not guest_request:
db_session.close()
return jsonify({"error": "Gastanfrage nicht gefunden"}), 404
if guest_request.processed_at:
db_session.close()
return jsonify({"error": "Gastanfrage wurde bereits bearbeitet"}), 400
# Drucker validieren (falls angegeben)
if assigned_printer_id:
printer = db_session.query(Printer).get(assigned_printer_id)
if not printer:
db_session.close()
return jsonify({"error": "Angegebener Drucker nicht gefunden"}), 400
guest_request.requested_printer_id = assigned_printer_id
# OTP-Code generieren
import random
import string
otp_code = ''.join(random.choices(string.digits, k=6))
# Gastanfrage genehmigen
guest_request.processed_at = datetime.now()
guest_request.processed_by = current_user.id
guest_request.approval_notes = approval_notes
guest_request.otp_code = otp_code
guest_request.rejection_reason = None # Sicherstellen, dass es nicht abgelehnt ist
db_session.commit()
# Benachrichtigung erstellen
notification = Notification(
user_id=current_user.id,
title="Gastanfrage genehmigt",
message=f"Gastanfrage von {guest_request.guest_name} wurde genehmigt. OTP: {otp_code}",
type="success",
created_at=datetime.now()
)
db_session.add(notification)
db_session.commit()
# E-Mail an Gast senden (falls implementiert)
try:
from utils.email_service import send_approval_email
send_approval_email(guest_request.guest_email, guest_request.guest_name, otp_code)
except ImportError:
app_logger.warning("E-Mail-Service nicht verfügbar")
except Exception as email_error:
app_logger.error(f"Fehler beim Senden der Genehmigungs-E-Mail: {str(email_error)}")
db_session.close()
app_logger.info(f"Gastanfrage {request_id} von Admin {current_user.id} genehmigt")
return jsonify({
"success": True,
"message": "Gastanfrage erfolgreich genehmigt",
"otp_code": otp_code,
"request_id": request_id
})
except Exception as e:
app_logger.error(f"Fehler beim Genehmigen der Gastanfrage {request_id}: {str(e)}")
return jsonify({"error": "Interner Serverfehler"}), 500
@app.route("/api/requests/<int:request_id>/deny", methods=["POST"])
@admin_required
def admin_deny_guest_request(request_id):
"""Lehnt eine Gastanfrage ab."""
try:
data = request.json or {}
rejection_reason = data.get('rejection_reason', '').strip()
if not rejection_reason:
return jsonify({"error": "Ablehnungsgrund ist erforderlich"}), 400
db_session = get_db_session()
guest_request = db_session.query(GuestRequest).get(request_id)
if not guest_request:
db_session.close()
return jsonify({"error": "Gastanfrage nicht gefunden"}), 404
if guest_request.processed_at:
db_session.close()
return jsonify({"error": "Gastanfrage wurde bereits bearbeitet"}), 400
# Gastanfrage ablehnen
guest_request.processed_at = datetime.now()
guest_request.processed_by = current_user.id
guest_request.rejection_reason = rejection_reason
guest_request.approval_notes = None
guest_request.otp_code = None
db_session.commit()
# Benachrichtigung erstellen
notification = Notification(
user_id=current_user.id,
title="Gastanfrage abgelehnt",
message=f"Gastanfrage von {guest_request.guest_name} wurde abgelehnt: {rejection_reason}",
type="warning",
created_at=datetime.now()
)
db_session.add(notification)
db_session.commit()
# E-Mail an Gast senden (falls implementiert)
try:
from utils.email_service import send_rejection_email
send_rejection_email(guest_request.guest_email, guest_request.guest_name, rejection_reason)
except ImportError:
app_logger.warning("E-Mail-Service nicht verfügbar")
except Exception as email_error:
app_logger.error(f"Fehler beim Senden der Ablehnungs-E-Mail: {str(email_error)}")
db_session.close()
app_logger.info(f"Gastanfrage {request_id} von Admin {current_user.id} abgelehnt")
return jsonify({
"success": True,
"message": "Gastanfrage erfolgreich abgelehnt",
"request_id": request_id
})
except Exception as e:
app_logger.error(f"Fehler beim Ablehnen der Gastanfrage {request_id}: {str(e)}")
return jsonify({"error": "Interner Serverfehler"}), 500
# ===== ENDE ADMIN GUEST REQUEST MANAGEMENT =====
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=5000, ssl_context=get_ssl_context())