mirror of
https://github.com/velocitatem/cvfs.git
synced 2026-05-31 08:43:37 +00:00
Fix document loading: circular FK, patch validation 500, and token expiry redirect
- 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
This commit is contained in:
@@ -7,6 +7,7 @@ from app.api.deps import get_current_user, get_db
|
||||
from app.schemas import BranchCreateRequest, VersionResponse
|
||||
from app.services.versions import create_branch, delete_version
|
||||
from dlib.auth import AuthenticatedUser
|
||||
from dlib.cv.ats_guard import PatchValidationError
|
||||
|
||||
|
||||
router = APIRouter(prefix="/versions", tags=["versions"])
|
||||
@@ -18,6 +19,7 @@ async def create_version_branch(
|
||||
session: AsyncSession = Depends(get_db),
|
||||
user: AuthenticatedUser = Depends(get_current_user),
|
||||
):
|
||||
try:
|
||||
version = await create_branch(
|
||||
session,
|
||||
owner_id=user.sub,
|
||||
@@ -26,6 +28,8 @@ async def create_version_branch(
|
||||
version_label=payload.version_label,
|
||||
patches=payload.patches,
|
||||
)
|
||||
except PatchValidationError as exc:
|
||||
raise HTTPException(status_code=422, detail=str(exc)) from exc
|
||||
if not version:
|
||||
raise HTTPException(status_code=404, detail="Parent version not found")
|
||||
return VersionResponse.model_validate(version)
|
||||
|
||||
@@ -57,6 +57,13 @@ class Settings(BaseSettings):
|
||||
return [origin.strip() for origin in value.split(",") if origin.strip()]
|
||||
return value
|
||||
|
||||
@field_validator("storage_endpoint_url", mode="before")
|
||||
@classmethod
|
||||
def _empty_endpoint_to_none(cls, value):
|
||||
if isinstance(value, str) and not value.strip():
|
||||
return None
|
||||
return value
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def get_settings() -> Settings:
|
||||
|
||||
@@ -23,20 +23,22 @@ async def create_document(
|
||||
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=doc,
|
||||
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},
|
||||
)
|
||||
doc.versions.append(version)
|
||||
doc.root_version_id = version.id
|
||||
session.add(version)
|
||||
await session.flush() # persist version so root_version_id FK is satisfied
|
||||
|
||||
session.add(doc)
|
||||
doc.root_version_id = version.id
|
||||
await session.commit()
|
||||
await session.refresh(doc)
|
||||
|
||||
stmt = (
|
||||
select(CvDocument)
|
||||
|
||||
@@ -92,6 +92,11 @@ async function req<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
headers: { accept: 'application/json', ...getAuthHeader(), ...init?.headers },
|
||||
});
|
||||
if (!res.ok) {
|
||||
if (res.status === 401 && typeof window !== 'undefined') {
|
||||
document.cookie = 'oidc_token_pub=; max-age=0; path=/';
|
||||
document.cookie = 'oidc_token=; max-age=0; path=/';
|
||||
window.location.href = '/login';
|
||||
}
|
||||
const detail = await res.text().catch(() => res.statusText);
|
||||
throw new Error(detail || `HTTP ${res.status}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user