Spaces:
Sleeping
Sleeping
| import base64 | |
| import logging | |
| from pathlib import Path | |
| import aiosqlite | |
| from app.config import settings | |
| from app.database import update_notification_status | |
| from app.lib.graph.client import GraphClient | |
| from app.lib.utils.storage import write_email | |
| logger = logging.getLogger(__name__) | |
| _LARGE_ATTACHMENT_THRESHOLD = 3 * 1024 * 1024 # 3 MB | |
| async def fetch_and_store( | |
| client: GraphClient, | |
| message_id: str, | |
| notif_db_id: int, | |
| storage_path: Path, | |
| conn: aiosqlite.Connection, | |
| ) -> Path: | |
| email_data = await client.get( | |
| f"/users/{settings.mailbox_user}/messages/{message_id}", | |
| params={"$expand": "attachments", "$select": ( | |
| "id,subject,from,toRecipients,ccRecipients,receivedDateTime," | |
| "body,uniqueBody,hasAttachments,attachments,webLink" | |
| )}, | |
| ) | |
| attachment_bytes: list[tuple[str, str, bytes]] = [] | |
| for att in email_data.get("attachments", []): | |
| if att.get("@odata.type") != "#microsoft.graph.fileAttachment": | |
| continue | |
| filename = att.get("name", "attachment") | |
| content_type = att.get("contentType", "application/octet-stream") | |
| size = att.get("size", 0) | |
| if size > _LARGE_ATTACHMENT_THRESHOLD or not att.get("contentBytes"): | |
| raw = await _fetch_large_attachment(client, message_id, att["id"]) | |
| else: | |
| raw = base64.b64decode(att["contentBytes"]) | |
| attachment_bytes.append((filename, content_type, raw)) | |
| dest = await write_email(email_data, attachment_bytes, storage_path) | |
| await update_notification_status( | |
| conn, notif_db_id, "fetched", storage_path=str(dest) | |
| ) | |
| logger.info("Stored email %s at %s", message_id, dest) | |
| return dest | |
| async def _fetch_large_attachment( | |
| client: GraphClient, message_id: str, attachment_id: str | |
| ) -> bytes: | |
| return await client.get_raw( | |
| f"/users/{settings.mailbox_user}/messages/{message_id}/attachments/{attachment_id}/$value" | |
| ) | |