diff --git a/backend/app/DETACHED_INSTANCE_FIX_DOCUMENTATION.md b/backend/app/DETACHED_INSTANCE_FIX_DOCUMENTATION.md new file mode 100644 index 000000000..0519ecba6 --- /dev/null +++ b/backend/app/DETACHED_INSTANCE_FIX_DOCUMENTATION.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backend/app/blueprints/guest.py b/backend/app/blueprints/guest.py index cbefce7f5..5222f36c0 100644 --- a/backend/app/blueprints/guest.py +++ b/backend/app/blueprints/guest.py @@ -36,7 +36,9 @@ def approver_required(f): def guest_request_form(): """Formular für Gastanfragen anzeigen.""" with get_cached_session() as db_session: - printers = db_session.query(Printer).filter_by(active=True) + printers = db_session.query(Printer).filter_by(active=True).all() + # Drucker-Liste von der Session trennen für Template-Verwendung + db_session.expunge_all() return render_template('guest_request.html', printers=printers) @guest_blueprint.route('/requests/overview', methods=['GET']) @@ -44,8 +46,10 @@ def guest_requests_overview(): """Öffentliche Übersicht aller Druckanträge mit zensierten persönlichen Daten.""" try: with get_cached_session() as db_session: - # Alle Gastanfragen laden, sortiert nach Erstellungsdatum (neueste zuerst) - guest_requests = db_session.query(GuestRequest).order_by(desc(GuestRequest.created_at)).all() + # Alle Gastanfragen mit eager loading des printer-Relationships laden + guest_requests = db_session.query(GuestRequest).options( + joinedload(GuestRequest.printer) + ).order_by(desc(GuestRequest.created_at)).all() # Daten für Gäste aufbereiten (persönliche Daten zensieren) public_requests = [] @@ -77,7 +81,7 @@ def guest_requests_overview(): else: censored_reason = req.reason[:10] + "***" if len(req.reason) > 10 else "***" - # Drucker-Info laden + # Drucker-Info laden (jetzt durch eager loading verfügbar) printer_name = "Unbekannt" if req.printer: printer_name = req.printer.name diff --git a/backend/app/database/myp.db-wal b/backend/app/database/myp.db-wal index f0d2f4a94..40f73abb4 100644 Binary files a/backend/app/database/myp.db-wal and b/backend/app/database/myp.db-wal differ diff --git a/backend/app/migrate_admin_features.py b/backend/app/migrate_admin_features.py new file mode 100644 index 000000000..0519ecba6 --- /dev/null +++ b/backend/app/migrate_admin_features.py @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backend/app/models.py b/backend/app/models.py index bcabec3fc..997aaec6e 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -764,8 +764,15 @@ class GuestRequest(Base): author_ip = Column(String(50)) otp_used_at = Column(DateTime, nullable=True) # Zeitpunkt der OTP-Verwendung + # Neue Felder für Admin-Verwaltung + processed_by = Column(Integer, ForeignKey("users.id"), nullable=True) # Admin der die Anfrage bearbeitet hat + processed_at = Column(DateTime, nullable=True) # Zeitpunkt der Bearbeitung + approval_notes = Column(Text, nullable=True) # Notizen bei Genehmigung + rejection_reason = Column(Text, nullable=True) # Grund bei Ablehnung + printer = relationship("Printer") job = relationship("Job") + processed_by_user = relationship("User", foreign_keys=[processed_by]) # Admin der bearbeitet hat def to_dict(self) -> dict: """ @@ -781,8 +788,13 @@ class GuestRequest(Base): "status": self.status, "printer_id": self.printer_id, "job_id": self.job_id, + "processed_by": self.processed_by, + "processed_at": self.processed_at.isoformat() if self.processed_at else None, + "approval_notes": self.approval_notes, + "rejection_reason": self.rejection_reason, "printer": self.printer.to_dict() if self.printer else None, - "job": self.job.to_dict() if self.job else None + "job": self.job.to_dict() if self.job else None, + "processed_by_user": self.processed_by_user.to_dict() if self.processed_by_user else None } def generate_otp(self) -> str: