| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- """Independent file and comment results for the existing comment POST."""
- import json
- import logging
- import re
- from datetime import datetime
- from fastapi import HTTPException
- from starlette.concurrency import run_in_threadpool
- from starlette.datastructures import UploadFile
- from .comments import save_comment
- from .config import settings
- from .file_storage import UploadError, get_files, save_upload
- from .forderung_history import history_context
- from .jinja_templates import templates
- from .permissions import current_principal
- logger = logging.getLogger(__name__)
- def _rollback(db):
- try:
- db.rollback()
- except Exception:
- logger.exception("Rollback nach fehlgeschlagenem Kommentar nicht möglich")
- async def submit_comment(request, pkey, db, scope):
- results, messages = [], []
- comment_saved = False
- async with request.form() as form:
- uploads = form.getlist("attachments")
- comment = form.get("Kommentar", "")
- try:
- ids = json.loads(form.get("attachment_ids", "[]"))
- except (ValueError, TypeError):
- raise HTTPException(400, "Die Dateiauswahl ist ungültig.")
- if (
- not isinstance(comment, str)
- or not isinstance(ids, list)
- or len(ids) != len(uploads)
- or any(not isinstance(item, UploadFile) for item in uploads)
- or any(not isinstance(item, str) or not re.fullmatch(r"[A-Za-z0-9_-]{1,80}", item) for item in ids)
- or len(set(ids)) != len(ids)
- ):
- raise HTTPException(400, "Die Dateiauswahl ist ungültig.")
- for identity, upload in zip(ids, uploads):
- result = {"id": identity, "name": upload.filename or "", "success": False}
- try:
- await run_in_threadpool(
- save_upload,
- pkey,
- upload.filename or "",
- upload.file,
- settings.UPLOAD_MAX_FILE_SIZE_MB * 1024 * 1024,
- )
- result["success"] = True
- except UploadError as error:
- result["error"] = str(error)
- except OSError:
- logger.exception("Datei konnte für %s nicht gespeichert werden", pkey)
- result["error"] = (
- "Speichern fehlgeschlagen. Bitte Speicherplatz, Dateisperren und Zugriffsrechte prüfen."
- )
- results.append(result)
- if comment.strip():
- try:
- save_comment(
- db, pkey, username=current_principal(request).username,
- timestamp=datetime.now().strftime("%Y-%m-%dT%H:%M:%S"), comment=comment,
- )
- db.commit()
- comment_saved = True
- except Exception:
- _rollback(db)
- logger.exception("Kommentar konnte für %s nicht gespeichert werden", pkey)
- messages.append("Der Kommentar konnte nicht gespeichert werden. Der Text bleibt im Eingabefeld.")
- elif not uploads:
- messages.append("Bitte einen Kommentar oder Dateien hinzufügen.")
- context = {}
- history_available = True
- try:
- context.update(history_context(db, pkey, "kommentare", scope))
- except Exception:
- history_available = False
- _rollback(db)
- logger.exception("Kommentarhistorie konnte nicht aktualisiert werden")
- messages.append(
- "Die Kommentare konnten nicht aktualisiert werden. Bereits gespeicherte Ergebnisse bleiben erhalten."
- )
- files_available = True
- try:
- context["files"] = get_files(pkey)
- except OSError:
- files_available = False
- logger.exception("Dateiliste konnte nicht aktualisiert werden")
- messages.append(
- "Die Dateiliste konnte nicht aktualisiert werden. Bereits gespeicherte Dateien bleiben erhalten."
- )
- context.setdefault("forderungen_details", [pkey])
- context.update(
- history_available=history_available,
- files_available=files_available,
- files_oob=True,
- send_result={"files": results, "comment_saved": comment_saved, "messages": messages},
- )
- return templates.TemplateResponse(
- request,
- "forderungen/details/comment_submission.html",
- context,
- headers={} if history_available else {"HX-Reswap": "none"},
- )
|