Files
xiaozhi-esp32-server/main/manager-api-fastapi/app/routers/correctword.py
T

98 lines
3.4 KiB
Python

from __future__ import annotations
from urllib.parse import quote
from fastapi import APIRouter, Depends, Request
from sqlalchemy.ext.asyncio import AsyncSession
from starlette.responses import Response
from app.core.database import get_db
from app.core.responses import JavaJSONResponse, ok
from app.core.security import require_normal
from app.repositories.correctword import CorrectWordRepository
from app.schemas.correctword import CorrectWordFileBody
from app.services.correctword import CorrectWordService
correctword_router = APIRouter()
def _java_urlencode(value: str) -> str:
# java.net.URLEncoder leaves alphanumerics plus .-*_ unescaped, encodes
# spaces as '+', and encodes '~'. The controller then replaces '+' with
# '%20'. urllib always leaves '~', so handle that final difference here.
return quote(value, safe="*.-_").replace("~", "%7E")
def _service(session: AsyncSession) -> CorrectWordService:
return CorrectWordService(CorrectWordRepository(session))
@correctword_router.post("/correct-word/file")
async def create_file(
body: CorrectWordFileBody, request: Request, session: AsyncSession = Depends(get_db)
) -> JavaJSONResponse:
return ok(await _service(session).create(body, require_normal(request)))
@correctword_router.put("/correct-word/file/{file_id}")
async def update_file(
file_id: str,
body: CorrectWordFileBody,
request: Request,
session: AsyncSession = Depends(get_db),
) -> JavaJSONResponse:
await _service(session).update(file_id, body, require_normal(request))
return ok()
@correctword_router.get("/correct-word/file/list")
async def list_files(
request: Request,
page: str | None = None,
limit: str | None = None,
session: AsyncSession = Depends(get_db),
) -> JavaJSONResponse:
return ok(await _service(session).page(require_normal(request), page, limit))
@correctword_router.get("/correct-word/file/select")
async def select_files(request: Request, session: AsyncSession = Depends(get_db)) -> JavaJSONResponse:
return ok(await _service(session).all(require_normal(request)))
@correctword_router.get("/correct-word/file/download/{file_id}")
async def download_file(
file_id: str, request: Request, session: AsyncSession = Depends(get_db)
) -> Response:
require_normal(request)
item = await _service(session).get(file_id)
if item is None or not item["content"]:
return Response(status_code=404)
body = "\n".join(item["content"]).encode("utf-8")
file_name = str(item["fileName"])
ascii_name = "".join(character if ord(character) < 128 else "_" for character in file_name)
disposition = f"attachment; filename=\"{ascii_name}\"; filename*=UTF-8''{_java_urlencode(file_name)}"
return Response(
body,
media_type="application/octet-stream",
headers={"Content-Disposition": disposition, "Content-Length": str(len(body))},
)
@correctword_router.delete("/correct-word/file/{file_id}")
async def delete_file(
file_id: str, request: Request, session: AsyncSession = Depends(get_db)
) -> JavaJSONResponse:
require_normal(request)
await _service(session).delete([file_id])
return ok()
@correctword_router.post("/correct-word/file/batch-delete")
async def batch_delete_files(
file_ids: list[str], request: Request, session: AsyncSession = Depends(get_db)
) -> JavaJSONResponse:
require_normal(request)
await _service(session).delete(file_ids)
return ok()