from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session from typing import List, Optional from .. import crud, schemas, auth from ..database import get_db from ..models import User router = APIRouter(prefix="/courses", tags=["courses"]) @router.get("/", response_model=schemas.SuccessResponse) def get_courses( skip: int = Query(0, ge=0), limit: int = Query(100, ge=1, le=100), level: Optional[str] = Query(None, pattern="^(beginner|intermediate|advanced)$"), db: Session = Depends(get_db) ): # Get published courses for all users (including guests) courses = crud.get_courses(db, skip=skip, limit=limit, level=level, published_only=True) # Convert SQLAlchemy models to Pydantic models course_responses = [schemas.CourseResponse.from_orm(course) for course in courses] return schemas.SuccessResponse( data={ "courses": course_responses, "total": len(courses), "skip": skip, "limit": limit, "level": level } ) @router.get("/{course_id}", response_model=schemas.SuccessResponse) def get_course( course_id: int, db: Session = Depends(get_db), current_user: Optional[User] = Depends(auth.get_optional_current_user) ): course = crud.get_course_by_id(db, course_id=course_id) if not course: raise HTTPException( status_code=404, detail="Course not found" ) # Check access based on status course_status = getattr(course, 'status', 'draft') author_id = getattr(course, 'author_id', None) if course_status == 'published': pass # Anyone can access published course elif course_status == 'draft': # Only author can access drafts if current_user is None or author_id != current_user.id: raise HTTPException( status_code=403, detail="Not authorized to access this draft" ) else: # Archived - author-only access if current_user is None or author_id != current_user.id: raise HTTPException( status_code=403, detail="Not authorized to access this course" ) # Convert SQLAlchemy model to Pydantic model course_response = schemas.CourseResponse.from_orm(course) return schemas.SuccessResponse(data={"course": course_response}) @router.put("/{course_id}", response_model=schemas.SuccessResponse) def update_course( course_id: int, course_update: schemas.CourseUpdate, db: Session = Depends(get_db), current_user: User = Depends(auth.get_current_user) ): course = crud.get_course_by_id(db, course_id) if not course: raise HTTPException(status_code=404, detail="Course not found") if course.author_id != current_user.id: raise HTTPException(status_code=403, detail="Not authorized to update this course") updated_course = crud.update_course(db, course_id, course_update) course_response = schemas.CourseResponse.from_orm(updated_course) return schemas.SuccessResponse(data={"course": course_response}) @router.get("/{course_id}/structure", response_model=schemas.SuccessResponse) def get_course_structure( course_id: int, db: Session = Depends(get_db), current_user: Optional[User] = Depends(auth.get_optional_current_user) ): course = crud.get_course_by_id(db, course_id=course_id, include_structure=True) if not course: raise HTTPException(status_code=404, detail="Course not found") if course.status != 'published': if current_user is None or course.author_id != current_user.id: raise HTTPException(status_code=403, detail="Not authorized") course_data = { "id": course.id, "title": course.title, "description": course.description, "level": course.level, "duration": course.duration, "status": course.status, "modules": [ { "id": module.id, "title": module.title, "description": module.description, "duration": module.duration, "order_index": module.order_index, "lessons": [ { "id": lesson.id, "title": lesson.title, "description": lesson.description, "order_index": lesson.order_index, "steps": [ { "id": step.id, "step_type": step.step_type, "title": step.title, "order_index": step.order_index } for step in sorted(lesson.steps, key=lambda s: s.order_index) ] if lesson.steps else [] } for lesson in sorted(module.lessons, key=lambda l: l.order_index) ] if module.lessons else [] } for module in sorted(course.modules, key=lambda m: m.order_index) ] if course.modules else [] } return schemas.SuccessResponse(data={"course": course_data})