from typing import Any, List, Optional from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from app import crud, models, schemas from app.api.v1.deps import get_db, get_current_active_user, get_teacher_user router = APIRouter() @router.get("/", response_model=List[schemas.Exam]) def read_exams( db: Session = Depends(get_db), skip: int = 0, limit: int = 100, course_id: Optional[int] = None, current_user: models.User = Depends(get_current_active_user), ) -> Any: """ Retrieve exams. """ if course_id: exams = crud.exam.get_by_course_id(db, course_id=course_id) else: exams = crud.exam.get_multi(db, skip=skip, limit=limit) return exams @router.get("/active", response_model=List[schemas.Exam]) def read_active_exams( db: Session = Depends(get_db), skip: int = 0, limit: int = 100, current_user: models.User = Depends(get_current_active_user), ) -> Any: """ Retrieve active exams. """ exams = crud.exam.get_active_exams(db, skip=skip, limit=limit) return exams @router.get("/available", response_model=List[schemas.Exam]) def read_available_exams( db: Session = Depends(get_db), skip: int = 0, limit: int = 100, current_user: models.User = Depends(get_current_active_user), ) -> Any: """ Retrieve available exams (active and within time window). """ exams = crud.exam.get_available_exams(db, skip=skip, limit=limit) return exams @router.post("/", response_model=schemas.Exam) def create_exam( *, db: Session = Depends(get_db), exam_in: schemas.ExamCreate, current_user: models.User = Depends(get_teacher_user), ) -> Any: """ Create new exam. """ # Check if the course exists course = db.query(models.Course).filter(models.Course.id == exam_in.course_id).first() if not course: raise HTTPException( status_code=404, detail=f"Course with ID {exam_in.course_id} not found", ) # Check if the user is a teacher of this course or an admin is_admin = any(role.name == "admin" for role in db.query(models.Role).all() if role.id == current_user.role_id) if not is_admin: teacher = db.query(models.Teacher).filter(models.Teacher.user_id == current_user.id).first() if not teacher or teacher.id != course.teacher_id: raise HTTPException( status_code=403, detail="You don't have permission to create an exam for this course", ) # Set the created_by field to the current user's ID exam_data = exam_in.dict() exam_data["created_by"] = current_user.id exam_obj = schemas.ExamCreate(**exam_data) exam = crud.exam.create(db=db, obj_in=exam_obj) return exam @router.get("/{exam_id}", response_model=schemas.ExamWithQuestions) def read_exam( *, db: Session = Depends(get_db), exam_id: int, current_user: models.User = Depends(get_current_active_user), ) -> Any: """ Get exam by ID with questions. """ exam = crud.exam.get(db=db, id=exam_id) if not exam: raise HTTPException( status_code=404, detail="Exam not found", ) # Get questions for this exam questions = crud.question.get_by_exam_id(db=db, exam_id=exam_id) # Create a combined response result = schemas.ExamWithQuestions.from_orm(exam) result.questions = questions return result @router.get("/{exam_id}/creator", response_model=schemas.ExamWithCreator) def read_exam_with_creator( *, db: Session = Depends(get_db), exam_id: int, current_user: models.User = Depends(get_current_active_user), ) -> Any: """ Get exam by ID with creator information. """ exam = crud.exam.get(db=db, id=exam_id) if not exam: raise HTTPException( status_code=404, detail="Exam not found", ) # Create a combined response result = schemas.ExamWithCreator.from_orm(exam) return result @router.put("/{exam_id}", response_model=schemas.Exam) def update_exam( *, db: Session = Depends(get_db), exam_id: int, exam_in: schemas.ExamUpdate, current_user: models.User = Depends(get_teacher_user), ) -> Any: """ Update an exam. """ exam = crud.exam.get(db=db, id=exam_id) if not exam: raise HTTPException( status_code=404, detail="Exam not found", ) # Check if the user is a teacher of this course or an admin is_admin = any(role.name == "admin" for role in db.query(models.Role).all() if role.id == current_user.role_id) if not is_admin: course = db.query(models.Course).filter(models.Course.id == exam.course_id).first() teacher = db.query(models.Teacher).filter(models.Teacher.user_id == current_user.id).first() if not teacher or not course or teacher.id != course.teacher_id: raise HTTPException( status_code=403, detail="You don't have permission to update this exam", ) exam = crud.exam.update(db=db, db_obj=exam, obj_in=exam_in) return exam @router.delete("/{exam_id}", response_model=schemas.Exam) def delete_exam( *, db: Session = Depends(get_db), exam_id: int, current_user: models.User = Depends(get_teacher_user), ) -> Any: """ Delete an exam. """ exam = crud.exam.get(db=db, id=exam_id) if not exam: raise HTTPException( status_code=404, detail="Exam not found", ) # Check if the user is a teacher of this course or an admin is_admin = any(role.name == "admin" for role in db.query(models.Role).all() if role.id == current_user.role_id) if not is_admin: course = db.query(models.Course).filter(models.Course.id == exam.course_id).first() teacher = db.query(models.Teacher).filter(models.Teacher.user_id == current_user.id).first() if not teacher or not course or teacher.id != course.teacher_id: raise HTTPException( status_code=403, detail="You don't have permission to delete this exam", ) exam = crud.exam.remove(db=db, id=exam_id) return exam