173 lines
5.1 KiB
Python
173 lines
5.1 KiB
Python
from pathlib import Path
|
|
from typing import List, Optional
|
|
|
|
from fastapi import APIRouter, File, HTTPException, UploadFile
|
|
from pydantic import BaseModel
|
|
|
|
from templates.preview import FontCheckResponse, check_fonts_in_pptx_handler
|
|
from utils.font_uploads import (
|
|
FONT_CONTENT_TYPES,
|
|
delete_font_upload,
|
|
font_upload_to_info,
|
|
get_font_upload_url,
|
|
list_font_uploads,
|
|
persist_upload_file,
|
|
)
|
|
|
|
|
|
FONTS_ROUTER = APIRouter(prefix="/fonts", tags=["fonts"])
|
|
|
|
SUPPORTED_FONT_EXTENSIONS = FONT_CONTENT_TYPES
|
|
|
|
|
|
class FontUploadResponse(BaseModel):
|
|
success: bool
|
|
font_name: str
|
|
font_url: str
|
|
font_path: str
|
|
message: Optional[str] = None
|
|
|
|
|
|
class FontListResponse(BaseModel):
|
|
success: bool
|
|
fonts: List[dict]
|
|
message: Optional[str] = None
|
|
|
|
|
|
class UploadedFontsResponse(BaseModel):
|
|
fonts: List[dict]
|
|
|
|
|
|
def _font_display_name(font_info) -> str:
|
|
return (
|
|
font_info.family_name
|
|
or font_info.full_name
|
|
or font_info.normalized_family_name
|
|
or Path(font_info.filename).stem
|
|
)
|
|
|
|
|
|
def _font_original_name(filename: str) -> str:
|
|
path = Path(filename)
|
|
stem = path.stem
|
|
if "_" in stem and len(stem.rsplit("_", 1)[-1]) == 8:
|
|
stem = stem.rsplit("_", 1)[0]
|
|
return f"{stem}{path.suffix}"
|
|
|
|
|
|
@FONTS_ROUTER.post("/upload", response_model=FontUploadResponse)
|
|
async def upload_font(
|
|
font_file: UploadFile = File(
|
|
..., description="Font file to upload (.ttf, .otf, .woff, .woff2, .eot)"
|
|
)
|
|
):
|
|
try:
|
|
if not font_file.filename:
|
|
raise HTTPException(status_code=400, detail="No file name provided")
|
|
|
|
font_upload, _font_path = await persist_upload_file(font_file)
|
|
font_info = await font_upload_to_info(font_upload)
|
|
font_name = _font_display_name(font_info)
|
|
|
|
return FontUploadResponse(
|
|
success=True,
|
|
font_name=font_name,
|
|
font_url=await get_font_upload_url(font_upload),
|
|
font_path=font_info.path,
|
|
message=f"Font '{font_name}' uploaded successfully",
|
|
)
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as exc:
|
|
print(f"Error uploading font: {exc}")
|
|
raise HTTPException(
|
|
status_code=500, detail=f"Error uploading font: {exc}"
|
|
) from exc
|
|
|
|
|
|
@FONTS_ROUTER.get("/list", response_model=FontListResponse)
|
|
async def list_fonts():
|
|
try:
|
|
response = await list_font_uploads()
|
|
fonts = []
|
|
for font_info in response.fonts:
|
|
file_ext = Path(font_info.filename).suffix.lower()
|
|
fonts.append(
|
|
{
|
|
"id": str(font_info.id),
|
|
"filename": font_info.filename,
|
|
"font_name": _font_display_name(font_info),
|
|
"original_name": _font_original_name(font_info.filename),
|
|
"font_url": font_info.url,
|
|
"font_path": font_info.path,
|
|
"font_type": SUPPORTED_FONT_EXTENSIONS.get(file_ext, "unknown"),
|
|
"file_size": font_info.size_bytes,
|
|
"family_name": font_info.family_name,
|
|
"subfamily_name": font_info.subfamily_name,
|
|
"full_name": font_info.full_name,
|
|
"postscript_name": font_info.postscript_name,
|
|
"normalized_family_name": font_info.normalized_family_name,
|
|
"weight_class": font_info.weight_class,
|
|
"width_class": font_info.width_class,
|
|
"format": font_info.format,
|
|
}
|
|
)
|
|
|
|
return FontListResponse(
|
|
success=True,
|
|
fonts=fonts,
|
|
message=f"Found {len(fonts)} font files",
|
|
)
|
|
|
|
except Exception as exc:
|
|
print(f"Error listing fonts: {exc}")
|
|
raise HTTPException(
|
|
status_code=500, detail=f"Error listing fonts: {exc}"
|
|
) from exc
|
|
|
|
|
|
@FONTS_ROUTER.get("/uploaded", response_model=UploadedFontsResponse)
|
|
async def get_uploaded_fonts():
|
|
try:
|
|
response = await list_font_uploads()
|
|
return UploadedFontsResponse(
|
|
fonts=[
|
|
{
|
|
"id": str(font_info.id),
|
|
"name": _font_display_name(font_info),
|
|
"url": font_info.url,
|
|
}
|
|
for font_info in response.fonts
|
|
]
|
|
)
|
|
|
|
except Exception as exc:
|
|
print(f"Error getting uploaded fonts: {exc}")
|
|
raise HTTPException(
|
|
status_code=500, detail=f"Error getting uploaded fonts: {exc}"
|
|
) from exc
|
|
|
|
|
|
FONTS_ROUTER.post("/check", response_model=FontCheckResponse)(
|
|
check_fonts_in_pptx_handler
|
|
)
|
|
|
|
|
|
@FONTS_ROUTER.delete("/delete/{filename}")
|
|
async def delete_font(filename: str):
|
|
try:
|
|
deleted = await delete_font_upload(filename)
|
|
return {
|
|
"success": True,
|
|
"message": f"Font '{deleted.filename}' deleted successfully",
|
|
}
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as exc:
|
|
print(f"Error deleting font: {exc}")
|
|
raise HTTPException(
|
|
status_code=500, detail=f"Error deleting font: {exc}"
|
|
) from exc
|