Download apps/message_hub/api/inbox_api.py from jun2024/fc: direct link, hf CLI and curl.
- Browser
- Download file 3.9 kB
-
https://huggingface.co/spaces/jun2024/fc/resolve/main/apps/message_hub/api/inbox_api.py
- Command line
-
hf download hf://spaces/jun2024/fc/apps/message_hub/api/inbox_api.py
-
curl -L -o inbox_api.py https://huggingface.co/spaces/jun2024/fc/resolve/main/apps/message_hub/api/inbox_api.py
3.9 kB
| """收件箱 API 端点。""" | |
| from __future__ import annotations | |
| import logging | |
| from typing import Any | |
| from django.http import FileResponse, HttpRequest | |
| from ninja import Query, Router | |
| from apps.core.exceptions import NotFoundError | |
| from apps.message_hub.models import InboxMessage | |
| from apps.message_hub.schemas import InboxMessageDetailOut, InboxMessageOut | |
| logger = logging.getLogger("apps.message_hub") | |
| router = Router() | |
| # --------------------------------------------------------------------------- | |
| # Helpers | |
| # --------------------------------------------------------------------------- | |
| def _get_base_queryset() -> Any: | |
| return InboxMessage.objects.select_related("source", "source__credential").order_by("-received_at") | |
| def _get_message_or_404(pk: int) -> InboxMessage: | |
| try: | |
| return _get_base_queryset().get(pk=pk) | |
| except InboxMessage.DoesNotExist: | |
| raise NotFoundError(f"消息 {pk} 不存在") | |
| # --------------------------------------------------------------------------- | |
| # Endpoints | |
| # --------------------------------------------------------------------------- | |
| def list_messages( | |
| request: HttpRequest, | |
| source_id: int | None = None, | |
| has_attachments: bool | None = None, | |
| search: str | None = None, | |
| ) -> Any: | |
| """收件箱消息列表。""" | |
| qs = _get_base_queryset() | |
| if source_id is not None: | |
| qs = qs.filter(source_id=source_id) | |
| if has_attachments is not None: | |
| qs = qs.filter(has_attachments=has_attachments) | |
| if search: | |
| from django.db.models import Q | |
| qs = qs.filter(Q(subject__icontains=search) | Q(sender__icontains=search) | Q(body_text__icontains=search)) | |
| return qs | |
| def get_message(request: HttpRequest, message_id: int) -> Any: | |
| """收件箱消息详情。""" | |
| return _get_message_or_404(message_id) | |
| def download_attachment( | |
| request: HttpRequest, | |
| message_id: int, | |
| part_index: int, | |
| ) -> FileResponse: | |
| """下载附件。""" | |
| msg = _get_message_or_404(message_id) | |
| return _serve_attachment(msg, part_index, inline=False) | |
| def preview_attachment( | |
| request: HttpRequest, | |
| message_id: int, | |
| part_index: int, | |
| ) -> FileResponse: | |
| """预览附件(inline)。""" | |
| msg = _get_message_or_404(message_id) | |
| return _serve_attachment(msg, part_index, inline=True) | |
| def _resolve_download_filename(msg: InboxMessage, part_index: int, fallback: str) -> str: | |
| for att in msg.attachments_meta or []: | |
| if int(att.get("part_index", -1)) != part_index: | |
| continue | |
| custom_name = str(att.get("custom_filename", "")).strip() | |
| if custom_name: | |
| return custom_name | |
| original_name = str(att.get("original_filename") or att.get("filename") or "").strip() | |
| if original_name: | |
| return original_name | |
| return fallback | |
| def _serve_attachment(msg: InboxMessage, part_index: int, *, inline: bool) -> FileResponse: | |
| """通过 fetcher 按需下载并返回附件。""" | |
| from apps.message_hub.services import get_fetcher | |
| fetcher = get_fetcher(msg.source.source_type) | |
| content, filename, content_type = fetcher.download_attachment( | |
| msg.source, | |
| msg.message_id, | |
| part_index, | |
| ) | |
| download_filename = _resolve_download_filename(msg, part_index, filename) | |
| disposition = "inline" if inline else "attachment" | |
| response = FileResponse( | |
| iter([content]), | |
| content_type=content_type, | |
| as_attachment=not inline, | |
| filename=download_filename, | |
| ) | |
| response["Content-Disposition"] = f'{disposition}; filename="{download_filename}"' | |
| return response | |