feat: add admin file policy actions
This commit is contained in:
@@ -41,3 +41,10 @@ class BatchUpdateFileData(BaseModel):
|
|||||||
expired_count: Optional[int] = None
|
expired_count: Optional[int] = None
|
||||||
clearExpiredAt: Optional[bool] = None
|
clearExpiredAt: Optional[bool] = None
|
||||||
clear_expired_at: Optional[bool] = None
|
clear_expired_at: Optional[bool] = None
|
||||||
|
|
||||||
|
|
||||||
|
class FilePolicyActionData(BaseModel):
|
||||||
|
id: int
|
||||||
|
action: str
|
||||||
|
downloadLimit: Optional[int] = None
|
||||||
|
download_limit: Optional[int] = None
|
||||||
|
|||||||
+64
-1
@@ -1,6 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
from core.response import APIResponse
|
from core.response import APIResponse
|
||||||
@@ -107,6 +107,28 @@ class FileService:
|
|||||||
"failed": failed,
|
"failed": failed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async def apply_file_policy_action(
|
||||||
|
self,
|
||||||
|
file_id: int,
|
||||||
|
action: str,
|
||||||
|
download_limit: Optional[int] = None,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
file_code = await FileCodes.filter(id=file_id).first()
|
||||||
|
if not file_code:
|
||||||
|
raise HTTPException(status_code=404, detail="文件不存在")
|
||||||
|
|
||||||
|
action = action.strip().lower()
|
||||||
|
now = await get_now()
|
||||||
|
update_data = self._build_policy_action_update(
|
||||||
|
file_code=file_code,
|
||||||
|
action=action,
|
||||||
|
now=now,
|
||||||
|
download_limit=download_limit,
|
||||||
|
)
|
||||||
|
|
||||||
|
await file_code.update_from_dict(update_data).save()
|
||||||
|
return await self.get_file_detail(file_id)
|
||||||
|
|
||||||
async def list_files(
|
async def list_files(
|
||||||
self,
|
self,
|
||||||
page: int,
|
page: int,
|
||||||
@@ -449,6 +471,47 @@ class FileService:
|
|||||||
start = start.replace(tzinfo=None)
|
start = start.replace(tzinfo=None)
|
||||||
return int((end - start).total_seconds())
|
return int((end - start).total_seconds())
|
||||||
|
|
||||||
|
def _build_policy_action_update(
|
||||||
|
self,
|
||||||
|
file_code: FileCodes,
|
||||||
|
action: str,
|
||||||
|
now: datetime,
|
||||||
|
download_limit: Optional[int],
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
if action == "extend_24h":
|
||||||
|
return {"expired_at": self._extended_expiration(file_code.expired_at, now, hours=24)}
|
||||||
|
if action == "extend_7d":
|
||||||
|
return {"expired_at": self._extended_expiration(file_code.expired_at, now, days=7)}
|
||||||
|
if action == "make_permanent":
|
||||||
|
return {"expired_at": None, "expired_count": -1}
|
||||||
|
if action == "reset_download_limit":
|
||||||
|
next_limit = download_limit if download_limit is not None else 5
|
||||||
|
if next_limit < 1:
|
||||||
|
raise HTTPException(status_code=400, detail="取件次数必须大于 0")
|
||||||
|
return {"expired_count": next_limit}
|
||||||
|
|
||||||
|
raise HTTPException(status_code=400, detail="不支持的策略动作")
|
||||||
|
|
||||||
|
def _extended_expiration(
|
||||||
|
self,
|
||||||
|
expired_at: Optional[datetime],
|
||||||
|
now: datetime,
|
||||||
|
**duration: int,
|
||||||
|
) -> datetime:
|
||||||
|
base_time = now
|
||||||
|
if expired_at is not None:
|
||||||
|
comparable_expired_at = self._align_datetime(expired_at, now)
|
||||||
|
if comparable_expired_at > now:
|
||||||
|
base_time = comparable_expired_at
|
||||||
|
return base_time + timedelta(**duration)
|
||||||
|
|
||||||
|
def _align_datetime(self, value: datetime, reference: datetime) -> datetime:
|
||||||
|
if value.tzinfo is None and reference.tzinfo is not None:
|
||||||
|
return value.replace(tzinfo=reference.tzinfo)
|
||||||
|
if value.tzinfo is not None and reference.tzinfo is None:
|
||||||
|
return value.replace(tzinfo=None)
|
||||||
|
return value
|
||||||
|
|
||||||
def _match_admin_file(
|
def _match_admin_file(
|
||||||
self,
|
self,
|
||||||
item: dict[str, Any],
|
item: dict[str, Any],
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ from apps.admin.schemas import (
|
|||||||
IDData,
|
IDData,
|
||||||
IDsData,
|
IDsData,
|
||||||
BatchUpdateFileData,
|
BatchUpdateFileData,
|
||||||
|
FilePolicyActionData,
|
||||||
ShareItem,
|
ShareItem,
|
||||||
DeleteItem,
|
DeleteItem,
|
||||||
LoginData,
|
LoginData,
|
||||||
@@ -218,6 +219,38 @@ async def file_batch_update_post(
|
|||||||
return await batch_update_files(data, file_service)
|
return await batch_update_files(data, file_service)
|
||||||
|
|
||||||
|
|
||||||
|
async def apply_file_policy_action(
|
||||||
|
data: FilePolicyActionData,
|
||||||
|
file_service: FileService,
|
||||||
|
):
|
||||||
|
download_limit = data.downloadLimit
|
||||||
|
if download_limit is None:
|
||||||
|
download_limit = data.download_limit
|
||||||
|
|
||||||
|
detail = await file_service.apply_file_policy_action(
|
||||||
|
file_id=data.id,
|
||||||
|
action=data.action,
|
||||||
|
download_limit=download_limit,
|
||||||
|
)
|
||||||
|
return APIResponse(detail=detail)
|
||||||
|
|
||||||
|
|
||||||
|
@admin_api.patch("/file/policy-action")
|
||||||
|
async def file_policy_action(
|
||||||
|
data: FilePolicyActionData,
|
||||||
|
file_service: FileService = Depends(get_file_service),
|
||||||
|
):
|
||||||
|
return await apply_file_policy_action(data, file_service)
|
||||||
|
|
||||||
|
|
||||||
|
@admin_api.post("/file/policy-action")
|
||||||
|
async def file_policy_action_post(
|
||||||
|
data: FilePolicyActionData,
|
||||||
|
file_service: FileService = Depends(get_file_service),
|
||||||
|
):
|
||||||
|
return await apply_file_policy_action(data, file_service)
|
||||||
|
|
||||||
|
|
||||||
@admin_api.get("/file/list")
|
@admin_api.get("/file/list")
|
||||||
async def file_list(
|
async def file_list(
|
||||||
page: int = 1,
|
page: int = 1,
|
||||||
|
|||||||
Reference in New Issue
Block a user