mirror of
https://github.com/velocitatem/cvfs.git
synced 2026-05-31 16:53:38 +00:00
113 lines
4.1 KiB
Python
113 lines
4.1 KiB
Python
from __future__ import annotations
|
|
|
|
from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
|
|
from fastapi.responses import Response
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.api.deps import get_current_user, get_db
|
|
from app.core.config import get_settings
|
|
from app.schemas import DocumentListResponse, DocumentResponse
|
|
from app.services.documents import (
|
|
create_document,
|
|
delete_document,
|
|
get_document,
|
|
list_documents,
|
|
)
|
|
from app.services.storage import storage_client
|
|
from dlib.auth import AuthenticatedUser
|
|
from dlib.cv import generate_patched_docx
|
|
|
|
|
|
router = APIRouter(prefix="/documents", tags=["documents"])
|
|
|
|
|
|
@router.get("", response_model=DocumentListResponse)
|
|
async def list_user_documents(
|
|
session: AsyncSession = Depends(get_db),
|
|
user: AuthenticatedUser = Depends(get_current_user),
|
|
):
|
|
documents = await list_documents(session, owner_id=user.sub)
|
|
payload = [_build_document_response(doc) for doc in documents]
|
|
return DocumentListResponse(items=payload)
|
|
|
|
|
|
@router.get("/{document_id}", response_model=DocumentResponse)
|
|
async def get_user_document(
|
|
document_id: str,
|
|
session: AsyncSession = Depends(get_db),
|
|
user: AuthenticatedUser = Depends(get_current_user),
|
|
):
|
|
document = await get_document(session, owner_id=user.sub, document_id=document_id)
|
|
if not document:
|
|
raise HTTPException(status_code=404, detail="Document not found")
|
|
return _build_document_response(document)
|
|
|
|
|
|
@router.get("/{document_id}/versions/{version_id}/download")
|
|
async def download_version_docx(
|
|
document_id: str,
|
|
version_id: str,
|
|
session: AsyncSession = Depends(get_db),
|
|
user: AuthenticatedUser = Depends(get_current_user),
|
|
):
|
|
document = await get_document(session, owner_id=user.sub, document_id=document_id)
|
|
if not document:
|
|
raise HTTPException(status_code=404, detail="Document not found")
|
|
version = next((v for v in document.versions if v.id == version_id), None)
|
|
if not version or not version.artifact_docx_key:
|
|
raise HTTPException(status_code=404, detail="Version artifact not found")
|
|
original = storage_client.download_bytes(key=version.artifact_docx_key)
|
|
data = generate_patched_docx(original, version.structured_blocks or [])
|
|
slug = f"{document.title.replace(' ', '-')}-{version.branch_name}.docx"
|
|
return Response(
|
|
content=data,
|
|
media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
headers={"Content-Disposition": f'attachment; filename="{slug}"'},
|
|
)
|
|
|
|
|
|
@router.post("", response_model=DocumentResponse)
|
|
async def upload_document(
|
|
title: str = Form(...),
|
|
description: str | None = Form(default=None),
|
|
file: UploadFile = File(...),
|
|
session: AsyncSession = Depends(get_db),
|
|
user: AuthenticatedUser = Depends(get_current_user),
|
|
):
|
|
document = await create_document(
|
|
session,
|
|
owner_id=user.sub,
|
|
title=title,
|
|
description=description,
|
|
upload=file,
|
|
)
|
|
return _build_document_response(document)
|
|
|
|
|
|
@router.delete("/{document_id}", status_code=204)
|
|
async def delete_user_document(
|
|
document_id: str,
|
|
session: AsyncSession = Depends(get_db),
|
|
user: AuthenticatedUser = Depends(get_current_user),
|
|
):
|
|
deleted = await delete_document(session, owner_id=user.sub, document_id=document_id)
|
|
if not deleted:
|
|
raise HTTPException(status_code=404, detail="Document not found")
|
|
|
|
|
|
def _build_document_response(document) -> DocumentResponse:
|
|
settings = get_settings()
|
|
base = (settings.public_base_url or "").rstrip("/")
|
|
response = DocumentResponse.model_validate(document)
|
|
versions = []
|
|
for version in response.versions:
|
|
assets = []
|
|
for asset in version.public_assets:
|
|
slug = asset.slug
|
|
url = asset.url
|
|
if slug and not url:
|
|
url = f"{base}/cv/{slug}" if base else f"/cv/{slug}"
|
|
assets.append(asset.model_copy(update={"url": url}))
|
|
versions.append(version.model_copy(update={"public_assets": assets}))
|
|
return response.model_copy(update={"versions": versions})
|