feat: add admin file metadata

This commit is contained in:
Lan
2026-06-03 06:37:56 +08:00
parent 3467e973ac
commit fc6046a663
3 changed files with 137 additions and 0 deletions
+6
View File
@@ -55,3 +55,9 @@ class BatchFilePolicyActionData(BaseModel):
action: str
downloadLimit: Optional[int] = None
download_limit: Optional[int] = None
class FileMetadataData(BaseModel):
id: int
note: Optional[str] = None
tags: Optional[list[str]] = None
+94
View File
@@ -15,6 +15,11 @@ from core.utils import get_now, hash_password, is_password_hashed
class FileService:
FILE_METADATA_KEY_PREFIX = "admin_file_metadata:"
MAX_METADATA_NOTE_LENGTH = 2000
MAX_METADATA_TAGS = 12
MAX_METADATA_TAG_LENGTH = 24
POLICY_ACTIONS = {
"extend_24h",
"extend_7d",
@@ -37,9 +42,13 @@ class FileService:
def __init__(self):
self.file_storage: FileStorageInterface = storages[settings.file_storage]()
def _file_metadata_key(self, file_id: int) -> str:
return f"{self.FILE_METADATA_KEY_PREFIX}{file_id}"
async def _delete_file_code(self, file_code: FileCodes):
if file_code.text is None:
await self.file_storage.delete_file(file_code)
await KeyValue.filter(key=self._file_metadata_key(file_code.id)).delete()
await file_code.delete()
async def delete_file(self, file_id: int):
@@ -136,6 +145,39 @@ class FileService:
await file_code.update_from_dict(update_data).save()
return await self.get_file_detail(file_id)
async def get_file_metadata(self, file_id: int) -> dict[str, Any]:
record = await KeyValue.filter(key=self._file_metadata_key(file_id)).first()
return self._normalize_file_metadata(record.value if record else None)
async def update_file_metadata(
self,
file_id: int,
note: Optional[str],
tags: Optional[list[str]],
update_note: bool,
update_tags: bool,
) -> dict[str, Any]:
file_code = await FileCodes.filter(id=file_id).first()
if not file_code:
raise HTTPException(status_code=404, detail="文件不存在")
current_metadata = await self.get_file_metadata(file_id)
next_metadata = dict(current_metadata)
if update_note:
next_metadata["note"] = self._normalize_metadata_note(note)
if update_tags:
next_metadata["tags"] = self._normalize_metadata_tags(tags)
now = await get_now()
updated_at = now.isoformat()
next_metadata["updatedAt"] = updated_at
next_metadata["updated_at"] = updated_at
await KeyValue.update_or_create(
key=self._file_metadata_key(file_id),
defaults={"value": next_metadata},
)
return await self.get_file_detail(file_id)
async def apply_files_policy_action(
self,
file_ids: list[int],
@@ -437,8 +479,60 @@ class FileService:
"timeline": timeline,
}
)
metadata = await self.get_file_metadata(file_id)
detail.update(
{
"metadata": metadata,
"meta": metadata,
"note": metadata["note"],
"tags": metadata["tags"],
"metadataUpdatedAt": metadata["updatedAt"],
"metadata_updated_at": metadata["updated_at"],
}
)
return detail
def _normalize_metadata_note(self, note: Optional[str]) -> str:
if note is None:
return ""
return str(note).strip()[: self.MAX_METADATA_NOTE_LENGTH]
def _normalize_metadata_tags(self, tags: Any) -> list[str]:
if not tags:
return []
if isinstance(tags, str):
tags = [tags]
elif not isinstance(tags, list):
return []
normalized_tags = []
seen_tags = set()
for raw_tag in tags:
tag = str(raw_tag).strip()
if not tag:
continue
tag = tag[: self.MAX_METADATA_TAG_LENGTH]
dedupe_key = tag.lower()
if dedupe_key in seen_tags:
continue
seen_tags.add(dedupe_key)
normalized_tags.append(tag)
if len(normalized_tags) >= self.MAX_METADATA_TAGS:
break
return normalized_tags
def _normalize_file_metadata(self, metadata: Any) -> dict[str, Any]:
if not isinstance(metadata, dict):
metadata = {}
updated_at = metadata.get("updatedAt") or metadata.get("updated_at")
return {
"note": self._normalize_metadata_note(metadata.get("note")),
"tags": self._normalize_metadata_tags(metadata.get("tags")),
"updatedAt": updated_at,
"updated_at": updated_at,
}
def _build_file_status_insights(
self,
file_code: FileCodes,
+37
View File
@@ -20,6 +20,7 @@ from apps.admin.schemas import (
BatchUpdateFileData,
BatchFilePolicyActionData,
FilePolicyActionData,
FileMetadataData,
ShareItem,
DeleteItem,
LoginData,
@@ -343,6 +344,42 @@ async def file_detail_post(
return APIResponse(detail=detail)
async def update_file_metadata(
data: FileMetadataData,
file_service: FileService,
):
fields_set = data.model_fields_set
update_note = "note" in fields_set
update_tags = "tags" in fields_set
if not update_note and not update_tags:
raise HTTPException(status_code=400, detail="请选择要更新的元数据")
detail = await file_service.update_file_metadata(
file_id=data.id,
note=data.note,
tags=data.tags,
update_note=update_note,
update_tags=update_tags,
)
return APIResponse(detail=detail)
@admin_api.patch("/file/metadata")
async def file_metadata(
data: FileMetadataData,
file_service: FileService = Depends(get_file_service),
):
return await update_file_metadata(data, file_service)
@admin_api.post("/file/metadata")
async def file_metadata_post(
data: FileMetadataData,
file_service: FileService = Depends(get_file_service),
):
return await update_file_metadata(data, file_service)
@admin_api.get("/config/get")
async def get_config(
config_service: ConfigService = Depends(get_config_service),