统一的文件上传服务
| 36 | |
| 37 | # ============ 公共服务层 ============ |
| 38 | class FileUploadService: |
| 39 | """统一的文件上传服务""" |
| 40 | |
| 41 | @staticmethod |
| 42 | async def generate_file_path( |
| 43 | file_name: str, upload_id: Optional[str] = None |
| 44 | ) -> tuple[str, str, str, str, str]: |
| 45 | """统一的路径生成""" |
| 46 | today = datetime.datetime.now() |
| 47 | storage_path = settings.storage_path.strip("/") |
| 48 | file_uuid = upload_id or uuid.uuid4().hex |
| 49 | filename = await sanitize_filename(unquote(file_name)) |
| 50 | base_path = f"share/data/{today.strftime('%Y/%m/%d')}/{file_uuid}" |
| 51 | path = f"{storage_path}/{base_path}" if storage_path else base_path |
| 52 | prefix, suffix = os.path.splitext(filename) |
| 53 | save_path = f"{path}/{filename}" |
| 54 | return path, suffix, prefix, filename, save_path |
| 55 | |
| 56 | @staticmethod |
| 57 | async def create_file_record( |
| 58 | file_name: str, |
| 59 | file_size: int, |
| 60 | file_path: str, |
| 61 | expire_value: int, |
| 62 | expire_style: str, |
| 63 | **extra_fields, |
| 64 | ) -> str: |
| 65 | """统一创建FileCodes记录,返回code""" |
| 66 | expired_at, expired_count, used_count, code = await get_expire_info( |
| 67 | expire_value, expire_style |
| 68 | ) |
| 69 | prefix, suffix = os.path.splitext(file_name) |
| 70 | |
| 71 | await FileCodes.create( |
| 72 | code=code, |
| 73 | prefix=prefix, |
| 74 | suffix=suffix, |
| 75 | uuid_file_name=file_name, |
| 76 | file_path=file_path, |
| 77 | size=file_size, |
| 78 | expired_at=expired_at, |
| 79 | expired_count=expired_count, |
| 80 | used_count=used_count, |
| 81 | **extra_fields, |
| 82 | ) |
| 83 | return code |
| 84 | |
| 85 | |
| 86 | async def validate_file_size(file: UploadFile, max_size: int) -> int: |
nothing calls this directly
no outgoing calls
no test coverage detected