202 lines
7.5 KiB
Python

from typing import Any, List, Optional
from fastapi import APIRouter, Depends, HTTPException, Path
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.QuestionOption])
def read_options(
db: Session = Depends(get_db),
question_id: Optional[int] = None,
current_user: models.User = Depends(get_current_active_user),
) -> Any:
"""
Retrieve question options.
"""
if question_id:
options = crud.question_option.get_by_question_id(db, question_id=question_id)
else:
options = crud.question_option.get_multi(db)
return options
@router.post("/", response_model=schemas.QuestionOption)
def create_option(
*,
db: Session = Depends(get_db),
option_in: schemas.QuestionOptionCreate,
current_user: models.User = Depends(get_teacher_user),
) -> Any:
"""
Create new question option.
"""
# Check if the question exists
question = crud.question.get(db=db, id=option_in.question_id)
if not question:
raise HTTPException(
status_code=404,
detail=f"Question with ID {option_in.question_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:
exam = db.query(models.Exam).filter(models.Exam.id == question.exam_id).first()
if not exam:
raise HTTPException(
status_code=404,
detail="Exam not found",
)
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 create an option for this question",
)
# If this is marked as correct, check if there are other correct options
if option_in.is_correct and question.question_type != schemas.QuestionType.MULTIPLE_CHOICE:
existing_correct = crud.question_option.get_correct_option(db=db, question_id=question.id)
if existing_correct:
# For non-multiple-choice questions, only one option can be correct
raise HTTPException(
status_code=400,
detail=f"This question type ({question.question_type}) can only have one correct option",
)
option = crud.question_option.create(db=db, obj_in=option_in)
return option
@router.get("/{option_id}", response_model=schemas.QuestionOption)
def read_option(
*,
db: Session = Depends(get_db),
option_id: int = Path(..., title="The ID of the option to get"),
current_user: models.User = Depends(get_current_active_user),
) -> Any:
"""
Get question option by ID.
"""
option = crud.question_option.get(db=db, id=option_id)
if not option:
raise HTTPException(
status_code=404,
detail="Question option not found",
)
return option
@router.put("/{option_id}", response_model=schemas.QuestionOption)
def update_option(
*,
db: Session = Depends(get_db),
option_id: int = Path(..., title="The ID of the option to update"),
option_in: schemas.QuestionOptionUpdate,
current_user: models.User = Depends(get_teacher_user),
) -> Any:
"""
Update a question option.
"""
option = crud.question_option.get(db=db, id=option_id)
if not option:
raise HTTPException(
status_code=404,
detail="Question option 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:
question = db.query(models.Question).filter(models.Question.id == option.question_id).first()
if not question:
raise HTTPException(
status_code=404,
detail="Question not found",
)
exam = db.query(models.Exam).filter(models.Exam.id == question.exam_id).first()
if not exam:
raise HTTPException(
status_code=404,
detail="Exam not found",
)
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 question option",
)
# If changing to correct, check if there are other correct options
if option_in.is_correct is not None and option_in.is_correct:
question = db.query(models.Question).filter(models.Question.id == option.question_id).first()
if question and question.question_type != schemas.QuestionType.MULTIPLE_CHOICE:
existing_correct = crud.question_option.get_correct_option(db=db, question_id=question.id)
if existing_correct and existing_correct.id != option_id:
# For non-multiple-choice questions, only one option can be correct
raise HTTPException(
status_code=400,
detail=f"This question type ({question.question_type}) can only have one correct option",
)
option = crud.question_option.update(db=db, db_obj=option, obj_in=option_in)
return option
@router.delete("/{option_id}", response_model=schemas.QuestionOption)
def delete_option(
*,
db: Session = Depends(get_db),
option_id: int = Path(..., title="The ID of the option to delete"),
current_user: models.User = Depends(get_teacher_user),
) -> Any:
"""
Delete a question option.
"""
option = crud.question_option.get(db=db, id=option_id)
if not option:
raise HTTPException(
status_code=404,
detail="Question option 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:
question = db.query(models.Question).filter(models.Question.id == option.question_id).first()
if not question:
raise HTTPException(
status_code=404,
detail="Question not found",
)
exam = db.query(models.Exam).filter(models.Exam.id == question.exam_id).first()
if not exam:
raise HTTPException(
status_code=404,
detail="Exam not found",
)
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 question option",
)
option = crud.question_option.remove(db=db, id=option_id)
return option