ForcePilot/backend/package/yuxi/channels/contract/dtos/directory.py
Kris 00092c818e chore: 批量代码优化与规范完善
本次提交包含多项代码优化与规范修正:
1. 文档与注释优化:修正注释术语、补充注解与FR编号
2. 代码格式调整:统一空格、换行与缩进规范
3. 类型与接口完善:补充__all__导出、修正返回类型注解
4. 错误处理增强:新增领域错误类与校验逻辑
5. 依赖与导入调整:修复路径引用、统一时区导入
6. 协议与契约更新:完善接口文档与一致性注解
2026-07-03 19:18:13 +08:00

225 lines
6.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""目录查询 DTO。
定义渠道通讯录目录查询相关的不可变值对象,包括目录条目类型枚举、
渠道用户、渠道群组、群组成员、目录条目、目录查询与目录搜索结果。所有 DTO
均为 ``dataclass(frozen=True)``,仅依赖标准库,用于渠道通讯录
查询与用户 / 群组检索FR-14。集合字段使用 tuple 以保证
frozen dataclass 的不可变语义。
"""
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from enum import StrEnum
from typing import Any, Literal
from yuxi.channels.contract.dtos.channel import ChannelType
from yuxi.channels.contract.dtos.common import Operator
from yuxi.channels.contract.errors import ValidationError
class DirectoryEntryType(StrEnum):
"""目录条目类型。
标识目录条目的类型,用于区分用户与群组。继承 ``str, Enum`` 以
支持 JSON 序列化与字符串比较。
取值:
USER: 用户。
GROUP: 群组。
"""
USER = "user"
GROUP = "group"
@dataclass(frozen=True)
class ChannelUser:
"""渠道用户。
描述渠道侧用户信息,包括对端 ID、名称与可选的头像、邮箱、电话
用于目录查询结果展示与身份关联。
字段:
peer_id: 对端 ID。
name: 名称。
avatar_url: 头像 URL可选
email: 邮箱(可选)。
phone: 电话(可选)。
"""
peer_id: str
name: str
avatar_url: str | None = None
email: str | None = None
phone: str | None = None
@dataclass(frozen=True)
class ChannelGroup:
"""渠道群组。
描述渠道侧群组信息,包括群组 ID、名称与成员数用于目录查询
结果展示。
字段:
group_id: 群组 ID。
name: 名称。
member_count: 成员数(默认 0
"""
group_id: str
name: str
member_count: int = 0
@dataclass(frozen=True)
class DirectoryEntry:
"""目录条目。
描述目录查询的统一条目包括类型、ID、名称与可选元数据用于
目录搜索结果的统一展示。
字段:
type: 条目类型user | group
id: 条目 ID。
name: 名称。
metadata: 渠道侧元数据(可选)。
"""
type: DirectoryEntryType
id: str
name: str
metadata: dict[str, Any] | None = None
@dataclass(frozen=True)
class DirectoryQuery:
"""目录查询。
描述目录查询请求,包括关键词、游标与分页限制,用于 FR-14 目录
查询的分页检索。
字段:
keyword: 关键词(可选)。
cursor: 游标(可选)。
limit: 分页限制(默认 20
"""
keyword: str | None = None
cursor: str | None = None
limit: int = 20
def __post_init__(self) -> None:
"""校验 limit 为正整数。
``limit`` 必须为正整数,在构造时即抛出 ``ValidationError``
adapter 不再做该校验INV-8
"""
if self.limit <= 0:
raise ValidationError("limit", "must be a positive integer")
@dataclass(frozen=True)
class DirectorySearchResult:
"""目录搜索结果。
描述目录查询的结果,包括条目列表与可选的下一页游标,用于 FR-14
目录查询的分页返回。集合字段使用 tuple 以保证不可变。
字段:
entries: 条目列表。
next_cursor: 下一页游标(可选)。
"""
entries: tuple[DirectoryEntry, ...]
next_cursor: str | None = None
@dataclass(frozen=True)
class GroupMember:
"""群组成员。
描述渠道群组中的单个成员信息,包括用户 ID、群组 ID、角色与加入时间
用于 ``DirectoryAdapter.getGroupMembers`` 方法的返回元素FR-14
字段:
user_id: 用户 ID。
group_id: 群组 ID。
role: 成员角色(可选,如 "owner" / "admin" / "member")。
joined_at: 加入时间(可选)。
"""
user_id: str
group_id: str
role: Literal["owner", "admin", "member"] | None = None
joined_at: datetime | None = None
@dataclass(frozen=True)
class GroupMemberResult:
"""群组成员查询结果。
描述群组成员查询的分页结果,包括成员列表与可选的下一页游标,用于
``DirectoryAdapter.getGroupMembers`` 方法的返回值FR-14。集合字段
使用 tuple 以保证不可变。
字段:
members: 成员列表。
next_cursor: 下一页游标(可选)。
"""
members: tuple[GroupMember, ...]
next_cursor: str | None = None
@dataclass(frozen=True)
class ClearDirectoryCacheCmd:
"""清理目录缓存命令DIR-CACHE-CLEAR
由 ``DirectoryPort.clearDirectoryCache`` 引用,清理指定范围的目录缓存,
需记录操作人以满足审计要求。
字段:
channel_type: 渠道类型。
account_id: 渠道账户 ID。
operator: 操作人(审计用)。
scope: 清理范围(``users`` / ``groups`` / ``all``)。
"""
channel_type: ChannelType
account_id: str
operator: Operator
scope: Literal["users", "groups", "all"]
def __post_init__(self) -> None:
"""校验必填字段非空与 scope 取值DIR-CACHE-CLEAR
``account_id`` 与 ``scope`` 必须非空,``scope`` 必须为 ``users`` /
``groups`` / ``all`` 之一,在构造时即抛出 ``ValidationError``
adapter 不再做该校验INV-8
"""
if not self.account_id:
raise ValidationError("account_id", "must not be empty")
if not self.scope:
raise ValidationError("scope", "must not be empty")
if self.scope not in ("users", "groups", "all"):
raise ValidationError(
"scope",
"must be one of: users, groups, all",
)
@dataclass(frozen=True)
class ClearDirectoryCacheResult:
"""清理目录缓存结果DIR-CACHE-CLEAR
字段:
cleared_keys: 清理的缓存 key 数量。
cleared_at: 清理时间戳。
"""
cleared_keys: int
cleared_at: datetime