from pydantic import BaseModel, Field, validator from typing import Optional, List from datetime import datetime import re class FileUploadRequest(BaseModel): """文件上传请求""" description: Optional[str] = Field(None, max_length=500, description="文件描述") tags: Optional[str] = Field(None, max_length=200, description="文件标签,用逗号分隔") is_public: bool = Field(False, description="是否公开分享") @validator('tags') def validate_tags(cls, v): if v: # 验证标签格式,只允许字母、数字、中文、下划线、中划线 tags = v.split(',') for tag in tags: tag = tag.strip() if not re.match(r'^[\w\u4e00-\u9fa5-]+$', tag): raise ValueError(f"标签 '{tag}' 格式不正确,只允许字母、数字、中文、下划线、中划线") if len(tag) > 20: raise ValueError(f"标签 '{tag}' 长度不能超过20个字符") return v class FileResponse(BaseModel): """文件响应""" id: int user_id: int filename: str original_filename: str file_size: int mime_type: str file_hash: str is_public: bool download_count: int description: Optional[str] = None tags: Optional[str] = None created_at: datetime updated_at: datetime last_accessed_at: Optional[datetime] = None class Config: from_attributes = True class FileListResponse(BaseModel): """文件列表响应""" files: List[FileResponse] total: int page: int size: int pages: int class Config: from_attributes = True class FileListRequest(BaseModel): """文件列表请求""" user_id: int = Field(..., description="用户ID") page: int = Field(1, ge=1, description="页码") size: int = Field(20, ge=1, le=100, description="每页数量") class FileIdRequest(BaseModel): """文件ID请求""" user_id: int = Field(..., description="用户ID") file_id: int = Field(..., description="文件ID") class StorageInfoRequest(BaseModel): """存储信息请求""" user_id: int = Field(..., description="用户ID") class FileUpdateRequest(BaseModel): """文件更新请求""" description: Optional[str] = Field(None, max_length=500, description="文件描述") tags: Optional[str] = Field(None, max_length=200, description="文件标签,用逗号分隔") is_public: Optional[bool] = Field(None, description="是否公开分享") @validator('tags') def validate_tags(cls, v): if v: tags = v.split(',') for tag in tags: tag = tag.strip() if not re.match(r'^[\w\u4e00-\u9fa5-]+$', tag): raise ValueError(f"标签 '{tag}' 格式不正确,只允许字母、数字、中文、下划线、中划线") if len(tag) > 20: raise ValueError(f"标签 '{tag}' 长度不能超过20个字符") return v class FileSearchRequest(BaseModel): """文件搜索请求""" filename: Optional[str] = Field(None, description="文件名搜索") tags: Optional[str] = Field(None, description="标签搜索,用逗号分隔") mime_type: Optional[str] = Field(None, description="MIME类型过滤") is_public: Optional[bool] = Field(None, description="是否公开文件") start_date: Optional[datetime] = Field(None, description="开始日期") end_date: Optional[datetime] = Field(None, description="结束日期") min_size: Optional[int] = Field(None, ge=0, description="最小文件大小(字节)") max_size: Optional[int] = Field(None, ge=0, description="最大文件大小(字节)") class FileInfo(BaseModel): """文件信息""" id: int filename: str original_filename: str file_size: int mime_type: str file_hash: str is_image: bool is_document: bool file_extension: str size_formatted: str is_public: bool = False download_count: int = 0 description: Optional[str] = None tags: Optional[str] = None created_at: datetime updated_at: datetime last_accessed_at: Optional[datetime] = None class Config: from_attributes = True class UploadResponse(BaseModel): """文件上传响应""" file_info: FileResponse message: str success: bool class DeleteResponse(BaseModel): """删除文件响应""" message: str success: bool class StorageInfo(BaseModel): """存储信息""" total_quota: int used_space: int available_space: int usage_percentage: float file_count: int # 通用API响应格式 class ApiResponse(BaseModel): """API响应""" success: bool message: str data: Optional[dict] = None code: Optional[str] = None