202 lines
7.5 KiB
Python
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 |