- 新增多个业务域的__init__.py模块文件,规范包导出结构 - 调整多个DTO文件的导入路径,统一模块组织方式 - 移除测试文件中多余的空行与导入语句 - 优化部分业务模块的包层级划分
135 lines
4.2 KiB
Python
135 lines
4.2 KiB
Python
"""媒体资源 DTO。
|
||
|
||
定义媒体上传/下载/元数据查询的数据传输对象,覆盖图片/文件/音频/视频
|
||
媒体资源的通用契约。所有渠道插件共享统一媒体 DTO,渠道插件实现
|
||
``InboundAdapter.downloadAttachment`` 或 ``OutboundAdapter.sendMessage``
|
||
时可使用这些 DTO 作为内部类型。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass
|
||
from datetime import datetime
|
||
from enum import StrEnum
|
||
|
||
from yuxi.channels.contract.errors import ValidationError
|
||
|
||
|
||
class MediaType(StrEnum):
|
||
"""媒体类型枚举。"""
|
||
|
||
IMAGE = "image"
|
||
FILE = "file"
|
||
AUDIO = "audio"
|
||
VIDEO = "video"
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class MediaUploadResult:
|
||
"""媒体上传结果。
|
||
|
||
字段:
|
||
media_id: 渠道侧媒体 ID(如飞书 image_key / file_key)。
|
||
url: 可访问的媒体 URL(部分渠道返回,可为 None)。
|
||
expires_at: 媒体资源过期时间(UTC),不过期时为 None。
|
||
"""
|
||
|
||
media_id: str
|
||
url: str | None = None
|
||
expires_at: datetime | None = None
|
||
|
||
def __post_init__(self) -> None:
|
||
"""校验 media_id 非空。
|
||
|
||
``media_id`` 必须非空,在构造时即抛出 ``ValidationError``,避免
|
||
空媒体 ID 导致后续上传结果无法定位(INV-8)。
|
||
"""
|
||
if not self.media_id:
|
||
raise ValidationError("media_id", "must not be empty")
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class MediaDownloadResult:
|
||
"""媒体下载结果。
|
||
|
||
字段:
|
||
content: 媒体二进制内容。
|
||
filename: 文件名(含扩展名),渠道未返回时为 None。
|
||
mime_type: MIME 类型(如 image/png),渠道未返回时为 None。
|
||
size: 内容字节数。
|
||
"""
|
||
|
||
content: bytes
|
||
size: int
|
||
filename: str | None = None
|
||
mime_type: str | None = None
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class MediaMetadata:
|
||
"""媒体元数据。
|
||
|
||
字段:
|
||
media_id: 渠道侧媒体 ID。
|
||
media_type: 媒体类型。
|
||
size: 内容字节数。
|
||
mime_type: MIME 类型,渠道未返回时为 None。
|
||
created_at: 媒体创建时间(UTC),渠道未返回时为 None。
|
||
"""
|
||
|
||
media_id: str
|
||
media_type: MediaType
|
||
size: int
|
||
mime_type: str | None = None
|
||
created_at: datetime | None = None
|
||
|
||
def __post_init__(self) -> None:
|
||
"""校验 media_id 非空与 size 非负。
|
||
|
||
``media_id`` 必须非空,``size`` 必须非负,在构造时即抛出
|
||
``ValidationError``,避免空媒体 ID 或负字节数导致元数据失效(INV-8)。
|
||
"""
|
||
if not self.media_id:
|
||
raise ValidationError("media_id", "must not be empty")
|
||
if self.size < 0:
|
||
raise ValidationError("size", "must not be negative")
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class AttachmentUploadResult:
|
||
"""附件上传结果(MSG-ATTACH-UPLOAD)。
|
||
|
||
描述通过插件 ``AttachmentUploadAdapter`` 适配器上传附件后的返回结果,包括
|
||
渠道侧附件 ID、可访问 URL、MIME 类型与字节数,由
|
||
``MessageManagementPort.uploadAttachment`` 引用(FR-12)。
|
||
|
||
字段:
|
||
attachment_id: 渠道侧附件 ID。
|
||
url: 可访问的附件 URL。
|
||
mime_type: MIME 类型(如 image/png)。
|
||
size_bytes: 内容字节数。
|
||
expires_at: 附件资源过期时间(UTC),不过期时为 None。
|
||
"""
|
||
|
||
attachment_id: str
|
||
url: str
|
||
mime_type: str
|
||
size_bytes: int
|
||
expires_at: datetime | None = None
|
||
|
||
def __post_init__(self) -> None:
|
||
"""校验 attachment_id / url / mime_type 非空与 size_bytes 为正整数。
|
||
|
||
必填字符串字段必须非空,``size_bytes`` 必须为正整数,在构造时即
|
||
抛出 ``ValidationError``,避免空附件 ID / URL 或非正字节数导致上传
|
||
结果失效(INV-8)。
|
||
"""
|
||
if not self.attachment_id:
|
||
raise ValidationError("attachment_id", "must not be empty")
|
||
if not self.url:
|
||
raise ValidationError("url", "must not be empty")
|
||
if not self.mime_type:
|
||
raise ValidationError("mime_type", "must not be empty")
|
||
if self.size_bytes <= 0:
|
||
raise ValidationError("size_bytes", "must be a positive integer")
|