""" Pydantic 数据校验模型(Schemas)。 职责: - 定义前后端 JSON 通信所需的数据结构 - 统一定义全局响应格式 {success, data, message} """ from datetime import datetime from typing import Any, Optional from pydantic import BaseModel, ConfigDict, Field class UnifiedResponse(BaseModel): """全局统一响应格式:所有接口返回该结构。""" success: bool = True data: Optional[Any] = None message: str = "" class UserCreate(BaseModel): """创建用户(注册)请求体:需携带邮箱验证码;角色固定为 visitor(后端强制)。""" email: str = Field(max_length=255) username: str = Field(min_length=2, max_length=50) password: str = Field(max_length=128) code: str = Field(default="", max_length=10, description="邮箱验证码(注册前通过 /api/email/send-code 获取)") class UserOut(BaseModel): """用户信息输出(不含密码哈希)。""" model_config = ConfigDict(from_attributes=True) id: int email: str username: str role: str created_time: datetime class LoginRequest(BaseModel): """登录请求体。""" email: str password: str class TokenOut(BaseModel): """登录成功返回的 JWT 令牌与用户基础信息。""" token: str user_id: int username: str role: str class UserLevelOut(BaseModel): """用户权限级别(角色)输出。""" user_id: int role: str class ProfileOut(BaseModel): """个人资料输出(头像、简介等)。""" model_config = ConfigDict(from_attributes=True) id: int email: str username: str role: str avatar: Optional[str] = None bio: Optional[str] = None created_time: datetime class BloggerProfileOut(BaseModel): """博主公开资料输出(我的简介页面使用)。""" username: str avatar: Optional[str] = None bio: Optional[str] = None role: str class ProfileUpdate(BaseModel): """更新个人资料请求体(头像 / 简介,均可选)。""" avatar: Optional[str] = Field(default=None, max_length=500) bio: Optional[str] = Field(default=None, max_length=2000) class SendCodeRequest(BaseModel): """发送邮箱验证码请求体。""" email: str purpose: str class VerifyCodeRequest(BaseModel): """校验邮箱验证码请求体。""" email: str code: str purpose: str class ForgotPasswordRequest(BaseModel): """忘记密码请求体。""" email: str class ResetPasswordRequest(BaseModel): """重置密码请求体。""" email: str code: str new_password: str = Field(max_length=128) class ArticleCreate(BaseModel): """创建文章请求体。""" title: str = Field(min_length=1, max_length=200) content: str = Field(min_length=1, max_length=200000) cover: Optional[str] = Field(default=None, max_length=500) visibility: str = "public" category: str = Field(default="life", description="分区:life 生活 / study 学习(取值由路由校验,统一 400 提示)") class ArticleUpdate(BaseModel): """更新文章请求体(字段均可选,仅更新传入的字段)。""" title: Optional[str] = Field(default=None, min_length=1, max_length=200) content: Optional[str] = Field(default=None, min_length=1, max_length=200000) cover: Optional[str] = Field(default=None, max_length=500) visibility: Optional[str] = None category: Optional[str] = None class ArticleOut(BaseModel): """文章信息输出。""" model_config = ConfigDict(from_attributes=True) id: int title: str content: str cover: Optional[str] = None visibility: str author_id: int created_time: datetime class CommentCreate(BaseModel): """发表评论请求体(parent_id 用于回复,顶层评论不填)。""" article_id: int content: str = Field(min_length=1, max_length=5000) parent_id: Optional[int] = None class CommentOut(BaseModel): """评论信息输出。""" model_config = ConfigDict(from_attributes=True) id: int article_id: int user_id: int parent_id: Optional[int] = None content: str created_time: datetime class ProjectOut(BaseModel): """项目信息输出(在线演示 / GitHub 外链)。""" model_config = ConfigDict(from_attributes=True) id: int name: str description: Optional[str] = None tech: Optional[str] = None project_type: str visibility: str demo_url: Optional[str] = None download_url: Optional[str] = None github_url: Optional[str] = None created_time: datetime updated_time: datetime class LikeCreate(BaseModel): """点赞请求体。""" article_id: int class LikeOut(BaseModel): """点赞信息输出。""" model_config = ConfigDict(from_attributes=True) id: int article_id: int user_id: int class FriendOut(BaseModel): """好友申请信息输出。""" model_config = ConfigDict(from_attributes=True) id: int user_id: int status: str