mirror of
https://github.com/velocitatem/cvfs.git
synced 2026-05-31 16:53:38 +00:00
- documents.py: fix root_version_id never being saved due to SQLAlchemy deferring the circular FK (CvDocument↔CvVersion). Use flush-based approach: flush doc, flush version, then set root_version_id before final commit. - config.py: add validator to coerce empty MINIO_ENDPOINT string to None, preventing boto3 ValueError: Invalid endpoint at startup. - versions.py: catch PatchValidationError and return 422 instead of 500 when a patch violates ATS guard rules. - api.ts: on 401, clear stale OIDC cookies and redirect to /login instead of showing the "Failed to load documents" error. https://claude.ai/code/session_01KKbzWYz8fLyG2qcwiDZ8fy
84 lines
2.5 KiB
Python
84 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
from fastapi import UploadFile
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy.orm import selectinload
|
|
|
|
from dlib.cv import parse_docx_bytes
|
|
|
|
from app.models import CvDocument, CvVersion
|
|
from app.services.storage import persist_upload
|
|
|
|
|
|
async def create_document(
|
|
session: AsyncSession,
|
|
*,
|
|
owner_id: str,
|
|
title: str,
|
|
description: str | None,
|
|
upload: UploadFile,
|
|
) -> CvDocument:
|
|
artifact_key, file_bytes = await persist_upload(upload, owner_id)
|
|
structured = parse_docx_bytes(file_bytes, version_label="root")
|
|
|
|
doc = CvDocument(owner_id=owner_id, title=title, description=description)
|
|
session.add(doc)
|
|
await session.flush() # persist doc so version FK is satisfied
|
|
|
|
version = CvVersion(
|
|
document_id=doc.id,
|
|
branch_name="root",
|
|
version_label="root",
|
|
artifact_docx_key=artifact_key,
|
|
structured_blocks=[block.model_dump() for block in structured.blocks],
|
|
metadata_json={"ingested": True},
|
|
)
|
|
session.add(version)
|
|
await session.flush() # persist version so root_version_id FK is satisfied
|
|
|
|
doc.root_version_id = version.id
|
|
await session.commit()
|
|
|
|
stmt = (
|
|
select(CvDocument)
|
|
.where(CvDocument.id == doc.id)
|
|
.options(selectinload(CvDocument.versions).selectinload(CvVersion.patches))
|
|
)
|
|
result = await session.execute(stmt)
|
|
return result.scalars().unique().one()
|
|
|
|
|
|
async def list_documents(session: AsyncSession, owner_id: str) -> list[CvDocument]:
|
|
stmt = (
|
|
select(CvDocument)
|
|
.where(CvDocument.owner_id == owner_id)
|
|
.options(selectinload(CvDocument.versions).selectinload(CvVersion.patches))
|
|
.order_by(CvDocument.created_at.desc())
|
|
)
|
|
result = await session.execute(stmt)
|
|
return result.scalars().unique().all()
|
|
|
|
|
|
async def get_document(
|
|
session: AsyncSession, owner_id: str, document_id: str
|
|
) -> CvDocument | None:
|
|
stmt = (
|
|
select(CvDocument)
|
|
.where(CvDocument.id == document_id, CvDocument.owner_id == owner_id)
|
|
.options(selectinload(CvDocument.versions).selectinload(CvVersion.patches))
|
|
)
|
|
result = await session.execute(stmt)
|
|
return result.scalars().unique().one_or_none()
|
|
|
|
|
|
async def delete_document(
|
|
session: AsyncSession, owner_id: str, document_id: str
|
|
) -> bool:
|
|
doc = await get_document(session, owner_id, document_id)
|
|
if not doc:
|
|
return False
|
|
await session.delete(doc)
|
|
await session.commit()
|
|
return True
|