from typing import Any, List, Optional from fastapi import APIRouter, Depends, HTTPException, Path, Response, status from sqlalchemy.orm import Session from app import models, schemas from app.api.v1.deps import get_db, get_current_active_user, get_admin_user router = APIRouter() @router.get("/", response_model=List[schemas.Course]) def read_courses( db: Session = Depends(get_db), skip: int = 0, limit: int = 100, teacher_id: Optional[int] = None, current_user: models.User = Depends(get_current_active_user), ) -> Any: """ Retrieve courses. """ if teacher_id: # Filter courses by teacher_id courses = db.query(models.Course).filter(models.Course.teacher_id == teacher_id).offset(skip).limit(limit).all() else: # Get all courses courses = db.query(models.Course).offset(skip).limit(limit).all() return courses @router.get("/{course_id}", response_model=schemas.CourseWithTeacher) def read_course( *, db: Session = Depends(get_db), course_id: int = Path(..., title="The ID of the course to get"), current_user: models.User = Depends(get_current_active_user), ) -> Any: """ Get course by ID with teacher details. """ course = db.query(models.Course).filter(models.Course.id == course_id).first() if not course: raise HTTPException( status_code=404, detail="Course not found", ) # Get teacher details if there is a teacher assigned teacher = None if course.teacher_id: teacher = db.query(models.Teacher).filter(models.Teacher.id == course.teacher_id).first() # Create a combined response result = schemas.CourseWithTeacher.from_orm(course) if teacher: result.teacher = schemas.Teacher.from_orm(teacher) return result @router.post("/", response_model=schemas.Course) def create_course( *, db: Session = Depends(get_db), course_in: schemas.CourseCreate, current_user: models.User = Depends(get_admin_user), ) -> Any: """ Create new course. """ # Check if course code is unique existing_course = db.query(models.Course).filter(models.Course.course_code == course_in.course_code).first() if existing_course: raise HTTPException( status_code=400, detail=f"Course with code {course_in.course_code} already exists", ) # Check if teacher exists if provided if course_in.teacher_id: teacher = db.query(models.Teacher).filter(models.Teacher.id == course_in.teacher_id).first() if not teacher: raise HTTPException( status_code=404, detail=f"Teacher with ID {course_in.teacher_id} not found", ) # Create the course db_course = models.Course( course_code=course_in.course_code, title=course_in.title, description=course_in.description, credits=course_in.credits, is_active=course_in.is_active, teacher_id=course_in.teacher_id, ) db.add(db_course) db.commit() db.refresh(db_course) return db_course @router.put("/{course_id}", response_model=schemas.Course) def update_course( *, db: Session = Depends(get_db), course_id: int = Path(..., title="The ID of the course to update"), course_in: schemas.CourseUpdate, current_user: models.User = Depends(get_admin_user), ) -> Any: """ Update a course. """ course = db.query(models.Course).filter(models.Course.id == course_id).first() if not course: raise HTTPException( status_code=404, detail="Course not found", ) # Check if course code is unique if it's being updated if course_in.course_code and course_in.course_code != course.course_code: existing_course = db.query(models.Course).filter(models.Course.course_code == course_in.course_code).first() if existing_course: raise HTTPException( status_code=400, detail=f"Course with code {course_in.course_code} already exists", ) # Check if teacher exists if provided if course_in.teacher_id and course_in.teacher_id != course.teacher_id: teacher = db.query(models.Teacher).filter(models.Teacher.id == course_in.teacher_id).first() if not teacher: raise HTTPException( status_code=404, detail=f"Teacher with ID {course_in.teacher_id} not found", ) # Update course fields update_data = course_in.dict(exclude_unset=True) for field, value in update_data.items(): setattr(course, field, value) db.add(course) db.commit() db.refresh(course) return course @router.delete("/{course_id}", response_model=None, status_code=status.HTTP_204_NO_CONTENT) def delete_course( *, db: Session = Depends(get_db), course_id: int = Path(..., title="The ID of the course to delete"), current_user: models.User = Depends(get_admin_user), ) -> Any: """ Delete a course. """ course = db.query(models.Course).filter(models.Course.id == course_id).first() if not course: raise HTTPException( status_code=404, detail="Course not found", ) # Check if there are any exams associated with this course exams = db.query(models.Exam).filter(models.Exam.course_id == course_id).first() if exams: raise HTTPException( status_code=400, detail="Cannot delete course with associated exams", ) # Check if there are any enrollments for this course enrollments = db.query(models.ClassEnrollment).filter(models.ClassEnrollment.course_id == course_id).first() if enrollments: raise HTTPException( status_code=400, detail="Cannot delete course with student enrollments", ) db.delete(course) db.commit() return Response(status_code=status.HTTP_204_NO_CONTENT) @router.get("/{course_id}/exams", response_model=List[schemas.Exam]) def read_course_exams( *, db: Session = Depends(get_db), course_id: int = Path(..., title="The ID of the course to get exams for"), current_user: models.User = Depends(get_current_active_user), ) -> Any: """ Get all exams for a course. """ course = db.query(models.Course).filter(models.Course.id == course_id).first() if not course: raise HTTPException( status_code=404, detail="Course not found", ) exams = db.query(models.Exam).filter(models.Exam.course_id == course_id).all() return exams