style(backend): apply ruff format

This commit is contained in:
2026-05-03 18:14:23 +08:00
parent 738217d9c9
commit ab68f019c5
41 changed files with 960 additions and 970 deletions
+7
View File
@@ -4,17 +4,20 @@ from pydantic import BaseModel, Field
class QRCodeRequest(BaseModel):
"""请求二维码 Schema"""
alias: str = Field(..., description="用户别名")
class QRCodeResponse(BaseModel):
"""二维码响应 Schema"""
session_id: str = Field(..., description="会话 ID")
qrcode_image: str = Field(..., description="二维码 Base64 图片")
class QRCodeStatusResponse(BaseModel):
"""二维码状态响应 Schema"""
status: str = Field(..., description="状态: pending/waiting_scan/success/error")
message: Optional[str] = Field(None, description="状态消息")
user_id: Optional[int] = Field(None, description="用户 ID (扫码成功时返回)")
@@ -24,11 +27,13 @@ class QRCodeStatusResponse(BaseModel):
class TokenVerifyRequest(BaseModel):
"""Token 验证请求 Schema"""
authorization: str = Field(..., description="Token")
class TokenVerifyResponse(BaseModel):
"""Token 验证响应 Schema"""
is_valid: bool = Field(..., description="Token 是否有效")
message: str = Field(..., description="验证消息")
user_id: Optional[int] = Field(None, description="用户 ID")
@@ -36,12 +41,14 @@ class TokenVerifyResponse(BaseModel):
class AliasLoginRequest(BaseModel):
"""别名+密码登录请求 Schema"""
alias: str = Field(..., min_length=2, max_length=50, description="用户别名")
password: str = Field(..., min_length=6, description="密码")
class AliasLoginResponse(BaseModel):
"""别名+密码登录响应 Schema"""
success: bool = Field(..., description="登录是否成功")
message: str = Field(..., description="登录消息")
user_id: Optional[int] = Field(None, description="用户 ID")
+7 -1
View File
@@ -2,21 +2,24 @@ from datetime import datetime
from typing import Optional, List, Generic, TypeVar
from pydantic import BaseModel, Field, ConfigDict
T = TypeVar('T')
T = TypeVar("T")
class ManualCheckInRequest(BaseModel):
"""手动打卡请求 Schema(已废弃,现在使用路径参数 task_id)"""
task_id: Optional[int] = Field(None, description="任务 ID")
class BatchCheckInRequest(BaseModel):
"""批量打卡请求 Schema"""
task_ids: list[int] = Field(..., description="任务 ID 列表")
class CheckInRecordResponse(BaseModel):
"""打卡记录响应 Schema"""
model_config = ConfigDict(from_attributes=True)
id: int
@@ -37,6 +40,7 @@ class CheckInRecordResponse(BaseModel):
class CheckInRecordWithTaskInfo(CheckInRecordResponse):
"""带任务信息的打卡记录响应 Schema"""
task_name: str
task_signature: str
user_alias: str
@@ -44,6 +48,7 @@ class CheckInRecordWithTaskInfo(CheckInRecordResponse):
class CheckInResultResponse(BaseModel):
"""打卡结果响应 Schema"""
success: bool
message: str
record_id: Optional[int] = None
@@ -52,6 +57,7 @@ class CheckInResultResponse(BaseModel):
class PaginatedResponse(BaseModel, Generic[T]):
"""分页响应 Schema"""
records: List[T] = Field(..., description="记录列表")
total: int = Field(..., description="总记录数")
skip: int = Field(..., description="跳过的记录数")
+5 -1
View File
@@ -1,15 +1,17 @@
"""
统一的 API 响应 Schema
"""
from typing import Generic, TypeVar, Optional
from pydantic import BaseModel
T = TypeVar('T')
T = TypeVar("T")
class ApiResponse(BaseModel, Generic[T]):
"""统一成功响应"""
success: bool = True
data: Optional[T] = None
message: Optional[str] = None
@@ -17,6 +19,7 @@ class ApiResponse(BaseModel, Generic[T]):
class ErrorDetail(BaseModel):
"""错误详情"""
code: str
message: str
field: Optional[str] = None # 字段验证错误时使用
@@ -24,5 +27,6 @@ class ErrorDetail(BaseModel):
class ErrorResponse(BaseModel):
"""统一错误响应"""
success: bool = False
error: ErrorDetail
+17 -15
View File
@@ -5,11 +5,14 @@ from pydantic import BaseModel, Field, field_validator
class TaskBase(BaseModel):
"""打卡任务基础 Schema"""
payload_config: str = Field(..., description="完整的 payload 配置 JSON(包含 ThreadId 和所有字段)")
payload_config: str = Field(
..., description="完整的 payload 配置 JSON(包含 ThreadId 和所有字段)"
)
name: Optional[str] = Field("", max_length=100, description="任务名称(用户自定义)")
is_active: Optional[bool] = Field(True, description="是否启用自动打卡")
@field_validator('payload_config')
@field_validator("payload_config")
@classmethod
def validate_payload_config(cls, v: str) -> str:
"""
@@ -38,13 +41,14 @@ class TaskBase(BaseModel):
class TaskCreate(TaskBase):
"""创建打卡任务 Schema"""
cron_expression: Optional[str] = Field(
None,
max_length=100,
description="Crontab 表达式(例如 '0 20 * * *' 表示每天 20:00)。NULL 表示禁用定时打卡"
description="Crontab 表达式(例如 '0 20 * * *' 表示每天 20:00)。NULL 表示禁用定时打卡",
)
@field_validator('cron_expression')
@field_validator("cron_expression")
@classmethod
def validate_cron_expression(cls, v: Optional[str]) -> Optional[str]:
"""验证 Crontab 表达式格式"""
@@ -56,6 +60,7 @@ class TaskCreate(TaskBase):
try:
from croniter import croniter
if not croniter.is_valid(v):
raise ValueError(f"无效的 Crontab 表达式: '{v}'")
except Exception as e:
@@ -66,16 +71,15 @@ class TaskCreate(TaskBase):
class TaskUpdate(BaseModel):
"""更新打卡任务 Schema"""
payload_config: Optional[str] = None
name: Optional[str] = None
is_active: Optional[bool] = None
cron_expression: Optional[str] = Field(
None,
max_length=100,
description="Crontab 表达式。NULL 表示禁用定时打卡"
None, max_length=100, description="Crontab 表达式。NULL 表示禁用定时打卡"
)
@field_validator('payload_config')
@field_validator("payload_config")
@classmethod
def validate_payload_config(cls, v: Optional[str]) -> Optional[str]:
"""
@@ -104,7 +108,7 @@ class TaskUpdate(BaseModel):
return v
@field_validator('cron_expression')
@field_validator("cron_expression")
@classmethod
def validate_cron_expression(cls, v: Optional[str]) -> Optional[str]:
"""验证 Crontab 表达式(与 TaskCreate 相同)"""
@@ -116,6 +120,7 @@ class TaskUpdate(BaseModel):
try:
from croniter import croniter
if not croniter.is_valid(v):
raise ValueError(f"无效的 Crontab 表达式: '{v}'")
except Exception as e:
@@ -126,18 +131,15 @@ class TaskUpdate(BaseModel):
class TaskResponse(TaskBase):
"""打卡任务响应 Schema"""
id: int
user_id: int
created_at: datetime
updated_at: Optional[datetime] = None
cron_expression: Optional[str] = Field(
None,
description="当前 Crontab 表达式(NULL = 禁用定时打卡)"
)
is_scheduled_enabled: Optional[bool] = Field(
None,
description="是否启用了定时打卡"
None, description="当前 Crontab 表达式(NULL = 禁用定时打卡)"
)
is_scheduled_enabled: Optional[bool] = Field(None, description="是否启用了定时打卡")
# 新增字段:最后一次打卡信息
last_check_in_time: Optional[datetime] = Field(None, description="最后一次打卡时间")
+29 -15
View File
@@ -6,12 +6,14 @@ import json
class FieldOption(BaseModel):
"""字段选项(用于 select 类型)"""
label: str = Field(..., description="选项显示文本")
value: str = Field(..., description="选项值")
class FieldConfigItem(BaseModel):
"""单个字段配置项"""
display_name: str = Field(..., description="字段显示名称")
field_type: str = Field(..., description="字段输入类型:text, textarea, number, select")
default_value: str = Field(default="", description="默认值")
@@ -21,33 +23,35 @@ class FieldConfigItem(BaseModel):
value_type: str = Field(default="string", description="值类型:string, int, double")
options: Optional[List[FieldOption]] = Field(None, description="选项列表(仅 select 类型)")
@field_validator('field_type')
@field_validator("field_type")
@classmethod
def validate_field_type(cls, v):
allowed_types = ['text', 'textarea', 'number', 'select']
allowed_types = ["text", "textarea", "number", "select"]
if v not in allowed_types:
raise ValueError(f'field_type must be one of {allowed_types}')
raise ValueError(f"field_type must be one of {allowed_types}")
return v
@field_validator('value_type')
@field_validator("value_type")
@classmethod
def validate_value_type(cls, v):
allowed_types = ['string', 'int', 'double']
allowed_types = ["string", "int", "double"]
if v not in allowed_types:
raise ValueError(f'value_type must be one of {allowed_types}')
raise ValueError(f"value_type must be one of {allowed_types}")
return v
class FieldConfigValues(BaseModel):
"""Values 字段的嵌套配置(如 location, temperature 等)"""
pass
class Config:
extra = 'allow' # 允许任意字段
extra = "allow" # 允许任意字段
class FieldConfig(BaseModel):
"""完整的字段配置"""
signature: Optional[FieldConfigItem] = None
texts: Optional[FieldConfigItem] = None
values: Optional[Dict[str, FieldConfigItem]] = Field(None, description="Values 字段的嵌套配置")
@@ -55,13 +59,14 @@ class FieldConfig(BaseModel):
class TemplateBase(BaseModel):
"""模板基础 Schema"""
name: str = Field(..., min_length=1, max_length=100, description="模板名称")
description: Optional[str] = Field(None, description="模板描述")
parent_id: Optional[int] = Field(None, description="父模板 ID(用于继承)")
field_config: Union[str, FieldConfig] = Field(..., description="字段配置(JSON 字符串或对象)")
is_active: bool = Field(default=True, description="是否启用")
@field_validator('field_config')
@field_validator("field_config")
@classmethod
def validate_field_config(cls, v):
"""验证并转换 field_config"""
@@ -71,7 +76,7 @@ class TemplateBase(BaseModel):
config_dict = json.loads(v)
return json.dumps(config_dict) # 返回格式化的 JSON 字符串
except json.JSONDecodeError:
raise ValueError('field_config must be valid JSON string')
raise ValueError("field_config must be valid JSON string")
elif isinstance(v, dict):
# 如果是字典,转换为 JSON 字符串
return json.dumps(v)
@@ -79,23 +84,27 @@ class TemplateBase(BaseModel):
# 如果是 FieldConfig 对象,转换为 JSON 字符串
return v.model_dump_json(exclude_none=True)
else:
raise ValueError('field_config must be JSON string, dict, or FieldConfig object')
raise ValueError("field_config must be JSON string, dict, or FieldConfig object")
class TemplateCreate(TemplateBase):
"""创建模板 Schema"""
pass
class TemplateUpdate(BaseModel):
"""更新模板 Schema"""
name: Optional[str] = Field(None, min_length=1, max_length=100, description="模板名称")
description: Optional[str] = Field(None, description="模板描述")
parent_id: Optional[int] = Field(None, description="父模板 ID(用于继承)")
field_config: Optional[Union[str, FieldConfig]] = Field(None, description="字段配置(JSON 字符串或对象)")
field_config: Optional[Union[str, FieldConfig]] = Field(
None, description="字段配置(JSON 字符串或对象)"
)
is_active: Optional[bool] = Field(None, description="是否启用")
@field_validator('field_config')
@field_validator("field_config")
@classmethod
def validate_field_config(cls, v):
"""验证并转换 field_config"""
@@ -107,17 +116,18 @@ class TemplateUpdate(BaseModel):
config_dict = json.loads(v)
return json.dumps(config_dict)
except json.JSONDecodeError:
raise ValueError('field_config must be valid JSON string')
raise ValueError("field_config must be valid JSON string")
elif isinstance(v, dict):
return json.dumps(v)
elif isinstance(v, FieldConfig):
return v.model_dump_json(exclude_none=True)
else:
raise ValueError('field_config must be JSON string, dict, or FieldConfig object')
raise ValueError("field_config must be JSON string, dict, or FieldConfig object")
class TemplateResponse(BaseModel):
"""模板响应 Schema"""
id: int
name: str
description: Optional[str]
@@ -133,15 +143,19 @@ class TemplateResponse(BaseModel):
class TaskFromTemplateRequest(BaseModel):
"""从模板创建任务的请求 Schema"""
template_id: int = Field(..., description="模板 ID")
thread_id: str = Field(..., min_length=1, description="接龙项目 ID")
field_values: Dict[str, Any] = Field(default_factory=dict, description="用户填写的字段值")
task_name: Optional[str] = Field(None, max_length=100, description="任务名称(可选)")
cron_expression: Optional[str] = Field("0 20 * * *", description="Cron 表达式(可选,默认每天 20:00)")
cron_expression: Optional[str] = Field(
"0 20 * * *", description="Cron 表达式(可选,默认每天 20:00)"
)
class TemplatePreviewResponse(BaseModel):
"""模板预览响应 Schema"""
template_id: int
template_name: str
preview_payload: Dict[str, Any] = Field(..., description="预览生成的 payload(使用默认值)")
+13 -2
View File
@@ -5,11 +5,13 @@ from pydantic import BaseModel, Field, EmailStr
class UserBase(BaseModel):
"""用户基础 Schema"""
alias: str = Field(..., min_length=2, max_length=50, description="用户别名(用于登录)")
class UserCreate(UserBase):
"""创建用户 Schema(管理员手动创建,只需要别名)"""
role: Optional[str] = Field("user", description="角色: user/admin")
email: Optional[EmailStr] = Field(None, description="邮箱地址")
password: Optional[str] = Field(None, min_length=6, description="初始密码(可选)")
@@ -18,24 +20,31 @@ class UserCreate(UserBase):
class UserUpdate(BaseModel):
"""更新用户 Schema(管理员编辑用户)"""
alias: Optional[str] = Field(None, min_length=2, max_length=50, description="用户别名")
role: Optional[str] = None
is_approved: Optional[bool] = None
email: Optional[EmailStr] = None
password: Optional[str] = Field(None, min_length=6, description="新密码(可选,留空表示不修改)")
password: Optional[str] = Field(
None, min_length=6, description="新密码(可选,留空表示不修改)"
)
reset_password: Optional[bool] = Field(False, description="是否清空密码")
class UserUpdateProfile(BaseModel):
"""用户更新个人信息 Schema"""
alias: Optional[str] = Field(None, min_length=2, max_length=50, description="新别名")
email: Optional[EmailStr] = Field(None, description="邮箱地址")
current_password: Optional[str] = Field(None, min_length=6, description="当前密码(修改密码时必填)")
current_password: Optional[str] = Field(
None, min_length=6, description="当前密码(修改密码时必填)"
)
new_password: Optional[str] = Field(None, min_length=6, description="新密码")
class UserResponse(BaseModel):
"""用户响应 Schema"""
id: int
alias: str
role: str
@@ -52,11 +61,13 @@ class UserResponse(BaseModel):
class UserWithToken(UserResponse):
"""带 Token 的用户响应 Schema"""
authorization: Optional[str] = None
class TokenStatus(BaseModel):
"""Token 状态 Schema"""
is_valid: bool
jwt_exp: str
expires_at: Optional[int] = None # Unix 时间戳(秒)