247 lines
9.1 KiB
Python
247 lines
9.1 KiB
Python
from typing import Any, List, Optional
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Path, Response, status
|
|
from sqlalchemy.orm import Session
|
|
from datetime import datetime
|
|
|
|
from app import crud, 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.ClassEnrollment])
|
|
def read_enrollments(
|
|
db: Session = Depends(get_db),
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
student_id: Optional[int] = None,
|
|
course_id: Optional[int] = None,
|
|
current_user: models.User = Depends(get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Retrieve class enrollments.
|
|
"""
|
|
# Regular users can only see their own enrollments if they are a student
|
|
if not crud.user.is_admin(current_user):
|
|
user_student = db.query(models.Student).filter(models.Student.user_id == current_user.id).first()
|
|
if user_student:
|
|
student_id = user_student.id
|
|
else:
|
|
# Check if they are a teacher, in which case they can see enrollments for their courses
|
|
user_teacher = db.query(models.Teacher).filter(models.Teacher.user_id == current_user.id).first()
|
|
if not user_teacher:
|
|
return []
|
|
|
|
# Get courses taught by this teacher
|
|
teacher_courses = db.query(models.Course).filter(models.Course.teacher_id == user_teacher.id).all()
|
|
if not teacher_courses:
|
|
return []
|
|
|
|
course_ids = [course.id for course in teacher_courses]
|
|
enrollments = db.query(models.ClassEnrollment).filter(
|
|
models.ClassEnrollment.course_id.in_(course_ids)
|
|
).offset(skip).limit(limit).all()
|
|
return enrollments
|
|
|
|
# Apply filters
|
|
query = db.query(models.ClassEnrollment)
|
|
if student_id:
|
|
query = query.filter(models.ClassEnrollment.student_id == student_id)
|
|
if course_id:
|
|
query = query.filter(models.ClassEnrollment.course_id == course_id)
|
|
|
|
enrollments = query.offset(skip).limit(limit).all()
|
|
return enrollments
|
|
|
|
|
|
@router.get("/{enrollment_id}", response_model=schemas.ClassEnrollmentWithDetails)
|
|
def read_enrollment(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
enrollment_id: int = Path(..., title="The ID of the enrollment to get"),
|
|
current_user: models.User = Depends(get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Get class enrollment by ID with student and course details.
|
|
"""
|
|
enrollment = db.query(models.ClassEnrollment).filter(models.ClassEnrollment.id == enrollment_id).first()
|
|
if not enrollment:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail="Class enrollment not found",
|
|
)
|
|
|
|
# Check permissions
|
|
if not crud.user.is_admin(current_user):
|
|
# Students can only see their own enrollments
|
|
user_student = db.query(models.Student).filter(models.Student.user_id == current_user.id).first()
|
|
if user_student and user_student.id == enrollment.student_id:
|
|
pass # OK, student is viewing their own enrollment
|
|
else:
|
|
# Check if they are a teacher for this course
|
|
user_teacher = db.query(models.Teacher).filter(models.Teacher.user_id == current_user.id).first()
|
|
if not user_teacher:
|
|
raise HTTPException(
|
|
status_code=403,
|
|
detail="Not enough permissions to view this enrollment",
|
|
)
|
|
|
|
course = db.query(models.Course).filter(
|
|
models.Course.id == enrollment.course_id,
|
|
models.Course.teacher_id == user_teacher.id
|
|
).first()
|
|
if not course:
|
|
raise HTTPException(
|
|
status_code=403,
|
|
detail="Not enough permissions to view this enrollment",
|
|
)
|
|
|
|
# Get student and course details
|
|
student = db.query(models.Student).filter(models.Student.id == enrollment.student_id).first()
|
|
course = db.query(models.Course).filter(models.Course.id == enrollment.course_id).first()
|
|
|
|
# Create a combined response
|
|
result = schemas.ClassEnrollmentWithDetails.from_orm(enrollment)
|
|
result.student = schemas.Student.from_orm(student) if student else None
|
|
result.course = schemas.Course.from_orm(course) if course else None
|
|
|
|
return result
|
|
|
|
|
|
@router.post("/", response_model=schemas.ClassEnrollment)
|
|
def create_enrollment(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
enrollment_in: schemas.ClassEnrollmentCreate,
|
|
current_user: models.User = Depends(get_admin_user),
|
|
) -> Any:
|
|
"""
|
|
Create new class enrollment.
|
|
"""
|
|
# Check if student exists
|
|
student = db.query(models.Student).filter(models.Student.id == enrollment_in.student_id).first()
|
|
if not student:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail=f"Student with ID {enrollment_in.student_id} not found",
|
|
)
|
|
|
|
# Check if course exists
|
|
course = db.query(models.Course).filter(models.Course.id == enrollment_in.course_id).first()
|
|
if not course:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail=f"Course with ID {enrollment_in.course_id} not found",
|
|
)
|
|
|
|
# Check if student is already enrolled in this course for this semester/academic year
|
|
existing_enrollment = db.query(models.ClassEnrollment).filter(
|
|
models.ClassEnrollment.student_id == enrollment_in.student_id,
|
|
models.ClassEnrollment.course_id == enrollment_in.course_id,
|
|
models.ClassEnrollment.semester == enrollment_in.semester,
|
|
models.ClassEnrollment.academic_year == enrollment_in.academic_year,
|
|
).first()
|
|
if existing_enrollment:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"Student is already enrolled in this course for {enrollment_in.semester} {enrollment_in.academic_year}",
|
|
)
|
|
|
|
# Create enrollment with current date if not provided
|
|
enrollment_data = enrollment_in.dict()
|
|
if not enrollment_data.get("enrollment_date"):
|
|
enrollment_data["enrollment_date"] = datetime.utcnow()
|
|
|
|
db_enrollment = models.ClassEnrollment(**enrollment_data)
|
|
db.add(db_enrollment)
|
|
db.commit()
|
|
db.refresh(db_enrollment)
|
|
|
|
return db_enrollment
|
|
|
|
|
|
@router.put("/{enrollment_id}", response_model=schemas.ClassEnrollment)
|
|
def update_enrollment(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
enrollment_id: int = Path(..., title="The ID of the enrollment to update"),
|
|
enrollment_in: schemas.ClassEnrollmentUpdate,
|
|
current_user: models.User = Depends(get_current_active_user),
|
|
) -> Any:
|
|
"""
|
|
Update a class enrollment.
|
|
"""
|
|
enrollment = db.query(models.ClassEnrollment).filter(models.ClassEnrollment.id == enrollment_id).first()
|
|
if not enrollment:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail="Class enrollment not found",
|
|
)
|
|
|
|
# Check permissions - only teachers of the course or admins can update enrollments
|
|
if not crud.user.is_admin(current_user):
|
|
user_teacher = db.query(models.Teacher).filter(models.Teacher.user_id == current_user.id).first()
|
|
if not user_teacher:
|
|
raise HTTPException(
|
|
status_code=403,
|
|
detail="Not enough permissions to update this enrollment",
|
|
)
|
|
|
|
course = db.query(models.Course).filter(
|
|
models.Course.id == enrollment.course_id,
|
|
models.Course.teacher_id == user_teacher.id
|
|
).first()
|
|
if not course:
|
|
raise HTTPException(
|
|
status_code=403,
|
|
detail="Not enough permissions to update this enrollment",
|
|
)
|
|
|
|
# Update enrollment fields
|
|
update_data = enrollment_in.dict(exclude_unset=True)
|
|
for field, value in update_data.items():
|
|
setattr(enrollment, field, value)
|
|
|
|
db.add(enrollment)
|
|
db.commit()
|
|
db.refresh(enrollment)
|
|
|
|
return enrollment
|
|
|
|
|
|
@router.delete("/{enrollment_id}", response_model=None, status_code=status.HTTP_204_NO_CONTENT)
|
|
def delete_enrollment(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
enrollment_id: int = Path(..., title="The ID of the enrollment to delete"),
|
|
current_user: models.User = Depends(get_admin_user),
|
|
) -> Any:
|
|
"""
|
|
Delete a class enrollment.
|
|
"""
|
|
enrollment = db.query(models.ClassEnrollment).filter(models.ClassEnrollment.id == enrollment_id).first()
|
|
if not enrollment:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail="Class enrollment not found",
|
|
)
|
|
|
|
# Check if there are any exam results for this student in this course
|
|
exam_results = db.query(models.ExamResult).join(
|
|
models.Exam, models.Exam.id == models.ExamResult.exam_id
|
|
).filter(
|
|
models.ExamResult.student_id == enrollment.student_id,
|
|
models.Exam.course_id == enrollment.course_id
|
|
).first()
|
|
|
|
if exam_results:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail="Cannot delete enrollment with associated exam results",
|
|
)
|
|
|
|
db.delete(enrollment)
|
|
db.commit()
|
|
|
|
return Response(status_code=status.HTTP_204_NO_CONTENT) |