mirror of
https://github.com/idrainformatica/PecFlow.git
synced 2026-06-16 12:45:42 +02:00
Visualizzazione ricevute
This commit is contained in:
@@ -526,6 +526,139 @@ async def download_attachment(
|
||||
raise NotFoundError("File non disponibile al momento")
|
||||
|
||||
|
||||
@router.get("/{message_id}/download-package")
|
||||
async def download_package(
|
||||
message_id: uuid.UUID,
|
||||
current_user: CurrentUser,
|
||||
db: DB,
|
||||
) -> StreamingResponse:
|
||||
"""
|
||||
Scarica un archivio ZIP con tutti i file originali della PEC.
|
||||
|
||||
Per messaggi inbound: allegati del messaggio (postacert.eml, daticert.xml, ecc.)
|
||||
e il raw EML originale.
|
||||
|
||||
Per messaggi outbound: allegati del messaggio + raw EML di ogni ricevuta collegata
|
||||
(accettazione, consegna, ecc.).
|
||||
"""
|
||||
import io
|
||||
import zipfile as _zipfile
|
||||
|
||||
from miniopy_async import Minio
|
||||
|
||||
# Verifica accesso
|
||||
message = await _resolve_message(message_id, current_user, db)
|
||||
|
||||
client = Minio(
|
||||
endpoint=settings.minio_endpoint,
|
||||
access_key=settings.minio_access_key,
|
||||
secret_key=settings.minio_secret_key,
|
||||
secure=settings.minio_use_ssl,
|
||||
)
|
||||
|
||||
buf = io.BytesIO()
|
||||
|
||||
async def _read_minio(path: str) -> bytes:
|
||||
try:
|
||||
resp = await client.get_object(settings.minio_bucket, path)
|
||||
data = await resp.content.read()
|
||||
resp.close()
|
||||
return data
|
||||
except Exception:
|
||||
return b""
|
||||
|
||||
with _zipfile.ZipFile(buf, mode="w", compression=_zipfile.ZIP_DEFLATED) as zf:
|
||||
# ── Allegati del messaggio principale ──────────────────────────────
|
||||
att_result = await db.execute(
|
||||
select(Attachment)
|
||||
.where(Attachment.message_id == message.id)
|
||||
.order_by(Attachment.created_at)
|
||||
)
|
||||
main_attachments = list(att_result.scalars().all())
|
||||
|
||||
for att in main_attachments:
|
||||
data = await _read_minio(att.storage_path)
|
||||
if data:
|
||||
zf.writestr(att.filename, data)
|
||||
|
||||
# ── Raw EML del messaggio principale ──────────────────────────────
|
||||
if message.raw_eml_path:
|
||||
data = await _read_minio(message.raw_eml_path)
|
||||
if data:
|
||||
# Nome file: messaggio_originale.eml oppure il basename del path
|
||||
eml_name = message.raw_eml_path.rsplit("/", 1)[-1]
|
||||
if not eml_name.endswith(".eml"):
|
||||
eml_name = "messaggio_originale.eml"
|
||||
# Evita duplicati con gli allegati gia' inseriti
|
||||
existing = {info.filename for info in zf.infolist()}
|
||||
if eml_name not in existing:
|
||||
zf.writestr(eml_name, data)
|
||||
|
||||
# ── Ricevute (solo per outbound) ───────────────────────────────────
|
||||
if message.direction == "outbound":
|
||||
receipts_result = await db.execute(
|
||||
select(Message)
|
||||
.where(Message.parent_message_id == message.id)
|
||||
.order_by(Message.received_at.asc().nullslast(), Message.created_at.asc())
|
||||
)
|
||||
receipts = list(receipts_result.scalars().all())
|
||||
|
||||
for receipt in receipts:
|
||||
# Tipo ricevuta come prefisso cartella
|
||||
pec_type = receipt.pec_type or "ricevuta"
|
||||
folder = f"ricevute/{pec_type}"
|
||||
|
||||
# Allegati della ricevuta
|
||||
r_att_result = await db.execute(
|
||||
select(Attachment)
|
||||
.where(Attachment.message_id == receipt.id)
|
||||
.order_by(Attachment.created_at)
|
||||
)
|
||||
r_attachments = list(r_att_result.scalars().all())
|
||||
|
||||
for att in r_attachments:
|
||||
data = await _read_minio(att.storage_path)
|
||||
if data:
|
||||
zip_path = f"{folder}/{att.filename}"
|
||||
# Gestisce duplicati aggiungendo un contatore
|
||||
existing = {info.filename for info in zf.infolist()}
|
||||
final_path = zip_path
|
||||
counter = 1
|
||||
while final_path in existing:
|
||||
name, _, ext = att.filename.rpartition(".")
|
||||
final_path = f"{folder}/{name}_{counter}.{ext}" if ext else f"{folder}/{att.filename}_{counter}"
|
||||
counter += 1
|
||||
zf.writestr(final_path, data)
|
||||
|
||||
# Raw EML della ricevuta
|
||||
if receipt.raw_eml_path:
|
||||
data = await _read_minio(receipt.raw_eml_path)
|
||||
if data:
|
||||
eml_name = receipt.raw_eml_path.rsplit("/", 1)[-1]
|
||||
if not eml_name.endswith(".eml"):
|
||||
eml_name = f"{pec_type}.eml"
|
||||
zip_path = f"{folder}/{eml_name}"
|
||||
existing = {info.filename for info in zf.infolist()}
|
||||
if zip_path not in existing:
|
||||
zf.writestr(zip_path, data)
|
||||
|
||||
buf.seek(0)
|
||||
zip_bytes = buf.getvalue()
|
||||
|
||||
# Nome del file ZIP basato sull'oggetto della mail
|
||||
safe_subject = (message.subject or "pec").replace("/", "_").replace("\\", "_")[:50]
|
||||
zip_filename = f"pec_{safe_subject}.zip"
|
||||
|
||||
return StreamingResponse(
|
||||
iter([zip_bytes]),
|
||||
media_type="application/zip",
|
||||
headers={
|
||||
"Content-Disposition": f'attachment; filename="{zip_filename}"',
|
||||
"Content-Length": str(len(zip_bytes)),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{message_id}/receipts", response_model=list[MessageResponse])
|
||||
async def list_receipts(
|
||||
message_id: uuid.UUID,
|
||||
|
||||
Reference in New Issue
Block a user