Files
boc/landvex-admin/backend/app/api/academy.py
T

146 lines
4.6 KiB
Python
Raw Normal View History

"""
quiXzoom Academy API endpoints for LandveX Admin
"""
from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel
from typing import List, Optional
from datetime import datetime
from app.core.security import get_current_user
from app.models.user import User
router = APIRouter(prefix="/academy", tags=["academy"])
# Models
class LessonCompleteRequest(BaseModel):
lesson_id: str
module_id: str
score: Optional[int] = None
class ProgressResponse(BaseModel):
user_id: str
completed_lessons: List[str]
current_module: int
total_progress: float
certificate_earned: bool
certificate_date: Optional[str] = None
class CertificateResponse(BaseModel):
pdf_url: str
verification_code: str
issue_date: str
# In-memory storage (replace with DB in production)
academy_progress = {}
LESSONS_PER_MODULE = {
"module1": 4,
"module2": 4,
"module3": 3,
"module4": 3,
"module5": 3,
"module6": 4
}
TOTAL_LESSONS = sum(LESSONS_PER_MODULE.values())
@router.get("/progress", response_model=ProgressResponse)
async def get_progress(current_user: User = Depends(get_current_user)):
"""Get user's academy progress"""
user_id = str(current_user.id)
progress = academy_progress.get(user_id, {
"completed_lessons": [],
"current_module": 1
})
completed = len(progress["completed_lessons"])
total_progress = (completed / TOTAL_LESSONS) * 100
certificate_earned = completed >= TOTAL_LESSONS
return ProgressResponse(
user_id=user_id,
completed_lessons=progress["completed_lessons"],
current_module=progress["current_module"],
total_progress=round(total_progress, 1),
certificate_earned=certificate_earned,
certificate_date=datetime.utcnow().isoformat() if certificate_earned else None
)
@router.post("/complete", status_code=status.HTTP_200_OK)
async def complete_lesson(
request: LessonCompleteRequest,
current_user: User = Depends(get_current_user)
):
"""Mark a lesson as completed"""
user_id = str(current_user.id)
if user_id not in academy_progress:
academy_progress[user_id] = {
"completed_lessons": [],
"current_module": 1
}
progress = academy_progress[user_id]
if request.lesson_id not in progress["completed_lessons"]:
progress["completed_lessons"].append(request.lesson_id)
# Update current module
module_num = int(request.module_id.replace("module", ""))
module_lessons = [f"m{module_num}l{i}" for i in range(1, LESSONS_PER_MODULE[request.module_id] + 1)]
if all(l in progress["completed_lessons"] for l in module_lessons):
progress["current_module"] = min(module_num + 1, 6)
return {
"success": True,
"lesson_id": request.lesson_id,
"progress": len(progress["completed_lessons"]) / TOTAL_LESSONS * 100
}
@router.get("/certificate", response_model=CertificateResponse)
async def get_certificate(current_user: User = Depends(get_current_user)):
"""Generate certificate PDF"""
user_id = str(current_user.id)
progress = academy_progress.get(user_id, {"completed_lessons": []})
if len(progress["completed_lessons"]) < TOTAL_LESSONS:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Certificate not yet earned. Complete all lessons first."
)
# Generate verification code
verification = f"QX-{user_id[:8].upper()}-{datetime.utcnow().strftime('%Y%m%d')}"
return CertificateResponse(
pdf_url=f"/api/academy/certificate/{user_id}/download",
verification_code=verification,
issue_date=datetime.utcnow().isoformat()
)
@router.get("/stats")
async def get_academy_stats(current_user: User = Depends(get_current_user)):
"""Get academy statistics (admin only)"""
if not current_user.is_admin:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Admin access required"
)
total_users = len(academy_progress)
completed_users = sum(
1 for p in academy_progress.values()
if len(p["completed_lessons"]) >= TOTAL_LESSONS
)
return {
"total_enrolled": total_users,
"completed_all": completed_users,
"completion_rate": round(completed_users / total_users * 100, 1) if total_users > 0 else 0,
"average_progress": round(
sum(len(p["completed_lessons"]) for p in academy_progress.values()) / total_users / TOTAL_LESSONS * 100, 1
) if total_users > 0 else 0
}