本次提交包含多项核心更新: 1. 新增微信4.0浅色主题UI模板资源与说明文档,补充了联系人图标、新的朋友入口等四个UI元素的图像匹配模板 2. 重构UI驱动层,将原2375行的单文件拆分为5个职责清晰的子驱动类,提升代码可维护性 3. 新增批量群发消息与聊天记录导出的完整数据模型、路由与后台协程,支持幂等校验与风控配置 4. 为所有业务接口新增post_verify校验逻辑,补充了verified字段返回操作结果 5. 优化媒体文件解密逻辑,修复了导出功能中的数据库错误处理与分辨率硬编码问题 6. 更新版本配置,将媒体发送功能标记为已落地,调整了能力列表与配置项
174 lines
6.6 KiB
Python
174 lines
6.6 KiB
Python
"""朋友圈域模型:发表朋友圈 / 分享公众号文章到朋友圈。"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Optional
|
||
|
||
from pydantic import BaseModel, Field
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# 朋友圈接口(POST /api/moments/publish)
|
||
# ---------------------------------------------------------------------------
|
||
class MomentPublishRequest(BaseModel):
|
||
"""发表朋友圈请求(纯文字)。
|
||
|
||
MVP 仅支持纯文字朋友圈。图片朋友圈涉及文件选择器交互,留给后续。
|
||
"""
|
||
|
||
content: str = Field(description="朋友圈文字内容")
|
||
|
||
|
||
class MomentPublishResponse(BaseModel):
|
||
"""发表朋友圈响应。
|
||
|
||
字段说明:
|
||
- local_moment_id:bridge 本地生成的朋友圈发表 ID,格式
|
||
moment_<unix秒>_<随机>。仅用于客户端幂等去重,不对应微信原生
|
||
朋友圈 ID。
|
||
- placeholder:恒为 false(真实执行 UI 发表操作,非占位)。
|
||
"""
|
||
|
||
success: bool = Field(default=False)
|
||
local_moment_id: str = Field(default="", description="本地生成的朋友圈发表 ID")
|
||
placeholder: bool = Field(default=False, description="是否为占位实现(恒为 false)")
|
||
error: Optional[str] = Field(default=None, description="失败时的错误描述")
|
||
|
||
|
||
class MomentShareArticleRequest(BaseModel):
|
||
"""分享公众号文章到朋友圈请求。
|
||
|
||
通过搜索公众号名称进入会话,点击第 N 篇推送文章卡片打开文章页,
|
||
再经「分享到朋友圈」UI 路径生成带卡片预览的朋友圈。
|
||
"""
|
||
|
||
public_account: str = Field(
|
||
description="公众号名称或 wxid,用于搜索定位公众号会话"
|
||
)
|
||
article_index: int = Field(
|
||
default=1,
|
||
description="从会话顶部往下的第几篇推送文章卡片,默认 1(最新一篇)",
|
||
)
|
||
comment: Optional[str] = Field(
|
||
default=None,
|
||
description="可选:分享时附带的「说点什么」评论文字,不传则跳过",
|
||
)
|
||
|
||
|
||
class MomentShareArticleResponse(BaseModel):
|
||
"""分享公众号文章到朋友圈响应。
|
||
|
||
字段说明:
|
||
- local_moment_id:bridge 本地生成的分享 ID,格式
|
||
share_<unix秒>_<随机>。仅用于客户端幂等去重。
|
||
- placeholder:恒为 false(真实执行 UI 分享操作,非占位)。
|
||
"""
|
||
|
||
success: bool = Field(default=False)
|
||
local_moment_id: str = Field(default="", description="本地生成的分享 ID")
|
||
placeholder: bool = Field(default=False, description="是否为占位实现(恒为 false)")
|
||
error: Optional[str] = Field(default=None, description="失败时的错误描述")
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# 朋友圈时间线(GET /api/moments/timeline)
|
||
# ---------------------------------------------------------------------------
|
||
class MomentItem(BaseModel):
|
||
"""单条朋友圈。"""
|
||
|
||
moment_id: str = Field(description="朋友圈 ID")
|
||
content: str = Field(default="", description="文字内容")
|
||
create_time: int = Field(description="发布时间戳(Unix 秒)")
|
||
author_wxid: str = Field(default="", description="发布者 wxid")
|
||
|
||
|
||
class MomentsTimelineResponse(BaseModel):
|
||
"""朋友圈时间线响应。
|
||
|
||
status 字段说明(因 WeChat 4.x 朋友圈 schema 未公开,需容错探测):
|
||
- ok:正常读取
|
||
- db_not_found:未找到朋友圈 DB 文件
|
||
- table_not_found:DB 存在但无朋友圈表
|
||
- db_encrypted:DB 加密且无法解密
|
||
- no_time_column / no_columns / query_error:探测/查询失败
|
||
"""
|
||
|
||
moments: list[MomentItem] = Field(default_factory=list)
|
||
next_cursor: int = Field(description="下次拉取应使用的 cursor")
|
||
has_more: bool = Field(default=False, description="是否可能还有更多")
|
||
status: str = Field(default="", description="探测/查询状态码")
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# 朋友圈互动(experimental)
|
||
# ---------------------------------------------------------------------------
|
||
class MomentLikeRequest(BaseModel):
|
||
"""朋友圈点赞请求(experimental)。"""
|
||
|
||
moment_index: int = Field(default=1, description="朋友圈序号,1=最新")
|
||
|
||
|
||
class MomentLikeResponse(BaseModel):
|
||
"""朋友圈点赞响应。"""
|
||
|
||
success: bool = Field(default=False)
|
||
error: Optional[str] = Field(default=None, description="失败时的错误描述")
|
||
verified: Optional[bool] = Field(
|
||
default=None,
|
||
description="post_verify 校验结果:True=截图 absdiff 检测到点赞位置像素变化,"
|
||
"False=未检测到变化,None=未执行校验",
|
||
)
|
||
|
||
|
||
class MomentCommentRequest(BaseModel):
|
||
"""朋友圈评论请求(experimental)。"""
|
||
|
||
comment: str = Field(description="评论文字内容")
|
||
moment_index: int = Field(default=1, description="朋友圈序号,1=最新")
|
||
|
||
|
||
class MomentCommentResponse(BaseModel):
|
||
"""朋友圈评论响应。"""
|
||
|
||
success: bool = Field(default=False)
|
||
error: Optional[str] = Field(default=None, description="失败时的错误描述")
|
||
verified: Optional[bool] = Field(
|
||
default=None,
|
||
description="post_verify 校验结果:True=MomentsComment 表出现新评论或截图检测到变化,"
|
||
"False=未检测到,None=未执行校验",
|
||
)
|
||
|
||
|
||
class MomentDeleteRequest(BaseModel):
|
||
"""删除朋友圈请求(experimental)。"""
|
||
|
||
moment_index: int = Field(default=1, description="朋友圈序号,1=最新")
|
||
|
||
|
||
class MomentDeleteResponse(BaseModel):
|
||
"""删除朋友圈响应。"""
|
||
|
||
success: bool = Field(default=False)
|
||
error: Optional[str] = Field(default=None, description="失败时的错误描述")
|
||
verified: Optional[bool] = Field(
|
||
default=None,
|
||
description="post_verify 校验结果:True=MomentsPost 表对应记录已删除,"
|
||
"False=记录仍存在,None=未执行校验",
|
||
)
|
||
|
||
|
||
class MomentPublishImageRequest(BaseModel):
|
||
"""发表图片朋友圈请求(experimental)。"""
|
||
|
||
image_path: str = Field(description="图片文件容器内绝对路径")
|
||
content: str = Field(default="", description="可选文字内容")
|
||
|
||
|
||
class MomentPublishImageResponse(BaseModel):
|
||
"""发表图片朋友圈响应。"""
|
||
|
||
success: bool = Field(default=False)
|
||
local_moment_id: str = Field(default="", description="本地生成的朋友圈 ID")
|
||
placeholder: bool = Field(default=False, description="是否为占位实现(恒为 false)")
|
||
error: Optional[str] = Field(default=None, description="失败时的错误描述")
|