Feat: Complete CBT PDF upload, AI parsing, and MinIO storage integration
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
from fastapi import FastAPI, Depends, HTTPException, status, Request
|
||||
from fastapi import FastAPI, Depends, HTTPException, status, Request, UploadFile, File, Form, BackgroundTasks
|
||||
from fastapi.responses import StreamingResponse
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from sqlmodel import Session, select
|
||||
@@ -75,6 +75,13 @@ def verify_otp(phone_or_email: str, code: str, session: Session = Depends(get_se
|
||||
return {"status": "authenticated", "token": "mock_jwt_session_token_string"}
|
||||
|
||||
# --- CBT TEST ENVIRONMENT CONTENT DELIVERY ENDPOINTS ---
|
||||
@app.get("/api/tests", response_model=List[models.Test], tags=["CBT Engine"])
|
||||
def list_active_tests(exam_pattern: Optional[str] = None, session: Session = Depends(get_session)):
|
||||
query = select(models.Test).where(models.Test.is_active == True)
|
||||
if exam_pattern:
|
||||
query = query.where(models.Test.exam_pattern == exam_pattern)
|
||||
return session.exec(query).all()
|
||||
|
||||
|
||||
@app.get("/api/tests/{test_id}", response_model=models.Test, tags=["CBT Engine"])
|
||||
def get_test_by_id(test_id: UUID, user_id: UUID, session: Session = Depends(get_session), current_user = Depends(require_tier([models.TierEnum.PRO, models.TierEnum.AI_COACH]))):
|
||||
@@ -512,3 +519,69 @@ def get_user_attempts(user_id: UUID, session: Session = Depends(get_session)):
|
||||
query = select(models.Attempt).where(models.Attempt.user_id == user_id)
|
||||
return session.exec(query).all()
|
||||
|
||||
|
||||
|
||||
# --- ADMIN ROUTES ---
|
||||
|
||||
@app.get("/api/admin/tests", tags=["Admin"])
|
||||
def get_admin_tests(session: Session = Depends(get_session)):
|
||||
tests = session.exec(select(models.Test)).all()
|
||||
return tests
|
||||
|
||||
@app.post("/api/admin/tests/upload", tags=["Admin"])
|
||||
async def upload_admin_test(
|
||||
file: UploadFile = File(...),
|
||||
title: str = Form(...),
|
||||
exam_pattern: str = Form(...),
|
||||
time_limit: int = Form(...),
|
||||
scheduled_date: Optional[datetime] = Form(None),
|
||||
admin_id: UUID = Form(...),
|
||||
session: Session = Depends(get_session)
|
||||
):
|
||||
import storage
|
||||
import uuid
|
||||
from worker import process_pdf_test
|
||||
|
||||
pdf_bytes = await file.read()
|
||||
object_name = f"tests/{uuid.uuid4()}_{file.filename}"
|
||||
url = storage.upload_file(pdf_bytes, object_name, content_type="application/pdf")
|
||||
if not url:
|
||||
raise HTTPException(status_code=500, detail="Failed to upload PDF to MinIO")
|
||||
|
||||
# Create inactive test
|
||||
test_obj = models.Test(
|
||||
title=title,
|
||||
type="Mock",
|
||||
exam_pattern=models.ExamEnum(exam_pattern),
|
||||
sections={},
|
||||
total_time=time_limit,
|
||||
difficulty="Medium",
|
||||
scheduled_date=scheduled_date,
|
||||
is_active=False, # Inactive until processing finishes
|
||||
created_by=admin_id
|
||||
)
|
||||
session.add(test_obj)
|
||||
session.commit()
|
||||
session.refresh(test_obj)
|
||||
|
||||
# Trigger async background worker
|
||||
process_pdf_test.delay(
|
||||
test_id_str=str(test_obj.id),
|
||||
object_name=object_name,
|
||||
admin_id_str=str(admin_id),
|
||||
exam_pattern=exam_pattern
|
||||
)
|
||||
|
||||
return {"status": "processing", "test_id": test_obj.id, "message": "Test is being processed by AI"}
|
||||
|
||||
@app.put("/api/admin/tests/{test_id}/toggle", tags=["Admin"])
|
||||
def toggle_test_status(test_id: UUID, session: Session = Depends(get_session)):
|
||||
test_obj = session.get(models.Test, test_id)
|
||||
if not test_obj:
|
||||
raise HTTPException(status_code=404, detail="Test not found")
|
||||
|
||||
test_obj.is_active = not test_obj.is_active
|
||||
session.add(test_obj)
|
||||
session.commit()
|
||||
|
||||
return {"status": "success", "is_active": test_obj.is_active}
|
||||
Reference in New Issue
Block a user