File size: 2,309 Bytes
aad7814
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
"""Gated admin override for the operator master template.

Enabled only when ``master_template_upload_enabled=true`` and a valid admin token
is supplied (see :func:`backend.api.deps.require_admin`). Lets an operator replace
the master at runtime (re-discover schema + rebuild MASTER RAG) without redeploy.
"""

from __future__ import annotations

import shutil
import tempfile
from pathlib import Path

from fastapi import APIRouter, Depends, HTTPException, UploadFile, status

from backend.api.deps import require_admin
from backend.core import ingest, pii_scrubber

router = APIRouter(prefix="/admin", tags=["admin"])

_ALLOWED = {".docx", ".docm", ".doc", ".pdf"}


@router.post("/template", status_code=status.HTTP_201_CREATED)
async def override_template(
    file: UploadFile,
    tenant_id: str = Depends(require_admin),
) -> dict:
    """Replace the master template from an uploaded file."""
    suffix = Path(file.filename or "").suffix.lower()
    if suffix not in _ALLOWED:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Unsupported file type '{suffix}'. Allowed: {sorted(_ALLOWED)}",
        )

    tmp_dir = Path(tempfile.mkdtemp(prefix="rics_v2_master_"))
    tmp_path = tmp_dir / (file.filename or f"master{suffix}")
    try:
        with tmp_path.open("wb") as out:
            shutil.copyfileobj(file.file, out)
        result = ingest.ingest_master(tenant_id, tmp_path)
    except pii_scrubber.PiiDetectedError as exc:
        raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(exc)) from exc
    finally:
        shutil.rmtree(tmp_dir, ignore_errors=True)

    return {"status": "master_replaced", **result}


@router.post("/template/reingest")
async def reingest_template(tenant_id: str = Depends(require_admin)) -> dict:
    """Re-run schema discovery + standard-paragraph ingest from configured paths."""
    try:
        result = ingest.ingest_operator_bundle(tenant_id)
    except pii_scrubber.PiiDetectedError as exc:
        raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(exc)) from exc
    except FileNotFoundError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
    return {"status": "reingested", **result}