feat: add support for filename in public file access and update temp link generation

This commit is contained in:
shiyu
2026-01-16 20:55:03 +08:00
parent 7a9a20509c
commit 31d347d24f
2 changed files with 21 additions and 3 deletions

View File

@@ -63,6 +63,16 @@ async def access_public_file(
return await VirtualFSService.access_public_file(token, request.headers.get("Range"))
@router.get("/public/{token}/{filename}")
@audit(action=AuditAction.DOWNLOAD, description="访问临时链接文件")
async def access_public_file_with_name(
token: str,
filename: str,
request: Request,
):
return await VirtualFSService.access_public_file(token, request.headers.get("Range"))
@router.get("/stat/{full_path:path}")
@audit(action=AuditAction.READ, description="查看文件信息")
async def get_file_stat(

View File

@@ -1,5 +1,6 @@
import mimetypes
import re
from urllib.parse import quote
from fastapi import HTTPException, UploadFile
from fastapi.responses import Response
@@ -112,12 +113,14 @@ class VirtualFSRouteMixin(VirtualFSTempLinkMixin):
async def create_temp_link(cls, full_path: str, expires_in: int):
full_path = cls._normalize_path(full_path)
token = await cls.generate_temp_link_token(full_path, expires_in=expires_in)
filename = full_path.rstrip("/").split("/")[-1]
filename_part = f"/{quote(filename, safe='')}" if filename else ""
file_domain = await ConfigService.get("FILE_DOMAIN")
if file_domain:
file_domain = file_domain.rstrip("/")
url = f"{file_domain}/api/fs/public/{token}"
url = f"{file_domain}/api/fs/public/{token}{filename_part}"
else:
url = f"/api/fs/public/{token}"
url = f"/api/fs/public/{token}{filename_part}"
return {"token": token, "path": full_path, "url": url}
@classmethod
@@ -128,12 +131,17 @@ class VirtualFSRouteMixin(VirtualFSTempLinkMixin):
raise exc
try:
return await cls.stream_file(path, range_header)
response = await cls.stream_file(path, range_header)
except FileNotFoundError:
raise HTTPException(404, detail="File not found via token")
except Exception as exc:
raise HTTPException(500, detail=f"File access error: {exc}")
filename = path.rstrip("/").split("/")[-1]
if filename and not response.headers.get("Content-Disposition"):
response.headers["Content-Disposition"] = f"inline; filename*=UTF-8''{quote(filename, safe='')}"
return response
@classmethod
async def stat(cls, full_path: str):
full_path = cls._normalize_path(full_path)