222 lines
5.0 KiB
Python
222 lines
5.0 KiB
Python
"""
|
|||
|
|
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
|