● Zion Boggan
repos/Sightline/backend/app/api/routes/imports.py
zionboggan.com ↗
72 lines · python
History for this file →
1
from __future__ import annotations
2
 
3
import hashlib
4
 
5
from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
6
from sqlalchemy import select
7
from sqlalchemy.orm import Session
8
 
9
from app.api.deps import Perm, get_db, require
10
from app.core.config import settings
11
from app.core.storage import get_storage
12
from app.models import AuditLog, Import, User
13
 
14
router = APIRouter(prefix="/imports", tags=["imports"])
15
 
16
 
17
@router.post("", status_code=201)
18
async def create_import(
19
    file: UploadFile = File(...),
20
    source_id: str | None = Form(default=None),
21
    process_now: bool = Form(default=True),
22
    db: Session = Depends(get_db),
23
    user: User = Depends(require(Perm.INGEST)),
24
):
25
    data = await file.read()
26
    if not data:
27
        raise HTTPException(400, "empty file")
28
    if len(data) > settings.max_upload_bytes:
29
        raise HTTPException(413, f"file exceeds {settings.max_upload_bytes} bytes")
30
    sha = hashlib.sha256(data).hexdigest()
31
 
32
    existing = db.scalar(select(Import).where(Import.sha256 == sha))
33
    if existing:
34
        return {"import_id": existing.id, "status": existing.status, "deduplicated": True,
35
                "row_count": existing.row_count}
36
 
37
    blob_ref = get_storage().put(f"imports/{sha[:16]}_{file.filename}", data)
38
 
39
    imp = Import(source_id=source_id, filename=file.filename, content_type=file.content_type,
40
                 sha256=sha, raw_blob_ref=blob_ref, status="received", created_by=user.id)
41
    db.add(imp)
42
    db.flush()
43
    db.add(AuditLog(actor_user_id=user.id, action="import.upload",
44
                    entity_type="import", entity_id=imp.id, meta={"filename": file.filename}))
45
    db.commit()
46
    db.refresh(imp)
47
 
48
    if process_now:
49
        from app.services.ingest import process_import
50
        summary = process_import(db, imp.id)
51
        return {"import_id": imp.id, **summary}
52
    else:
53
        from app.workers.tasks import process_import_task
54
        process_import_task.delay(imp.id)
55
        return {"import_id": imp.id, "status": "queued"}
56
 
57
 
58
@router.get("/{import_id}")
59
def get_import(import_id: str, db: Session = Depends(get_db), _: User = Depends(require(Perm.READ))):
60
    imp = db.get(Import, import_id)
61
    if not imp:
62
        raise HTTPException(404, "import not found")
63
    return {"id": imp.id, "filename": imp.filename, "status": imp.status,
64
            "row_count": imp.row_count, "error": imp.error, "sha256": imp.sha256,
65
            "created_at": imp.created_at}
66
 
67
 
68
@router.get("")
69
def list_imports(db: Session = Depends(get_db), _: User = Depends(require(Perm.READ))):
70
    rows = db.scalars(select(Import).order_by(Import.created_at.desc()).limit(100)).all()
71
    return [{"id": i.id, "filename": i.filename, "status": i.status,
72
             "row_count": i.row_count, "created_at": i.created_at} for i in rows]