pdf-quiz-generator/backend/app/schemas/course.py
Daniel a2a2da7da0 Add LMS, user quiz creation, manual questions, course system
LMS / Course System:
- Course → Module → Lesson hierarchy (any user can create)
- Lesson types: text, video (Vimeo/YouTube/local), document, quiz, live_session
- Video provider auto-detection from URL
- BBB API integration (create/join meetings) with env config
- Course enrollment with per-lesson progress tracking
- AI content generation/refinement for text lessons
- Draft/published/archived status workflow
- Subscription gate placeholder (requires_subscription flag)
- Thumbnail upload support
- Module/lesson reorder with up/down controls

User Quiz Creation:
- Any user can create quizzes from question bank (was moderator-only)
- User quizzes: is_published=0, is_shared=0 (private by default)
- Fixed section_id fallback: None instead of hardcoded 1

Manual Question Creation:
- POST /questions/create endpoint for manual MCQ entry
- CreateQuestionModal on QuestionBankPage with options, radio for correct answer
- Auto-generates embedding on creation

Frontend:
- CoursesPage: Browse/My Courses/Created tabs with search and pagination
- CourseDetailPage: Student view with module accordion, lesson viewer, progress
- CourseEditorPage: Full course builder with AI generate, question bank browser
- Courses link in Navbar
- Create Question button on Question Bank (available to all users)

Backend:
- 5 new tables: courses, course_modules, course_lessons, course_enrollments, course_lesson_progress
- Course model + schemas + router (22 endpoints)
- BBB_SERVER_URL + BBB_SECRET config
- Updated CLAUDE.md with LMS documentation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 02:07:04 +02:00

135 lines
3.4 KiB
Python

from datetime import datetime
from pydantic import BaseModel
class CourseCreate(BaseModel):
title: str
description: str | None = None
class CourseUpdate(BaseModel):
title: str | None = None
description: str | None = None
status: str | None = None
is_featured: int | None = None
requires_subscription: int | None = None
class ModuleCreate(BaseModel):
title: str
description: str | None = None
class ModuleUpdate(BaseModel):
title: str | None = None
description: str | None = None
position: int | None = None
class LessonCreate(BaseModel):
title: str
lesson_type: str # text, video, document, quiz, live_session
description: str | None = None
content_text: str | None = None
video_url: str | None = None
local_file_path: str | None = None
quiz_id: int | None = None
live_session_url: str | None = None
live_session_start: datetime | None = None
live_session_end: datetime | None = None
duration_minutes: int | None = None
is_required: int = 1
class LessonUpdate(BaseModel):
title: str | None = None
description: str | None = None
content_text: str | None = None
video_url: str | None = None
local_file_path: str | None = None
quiz_id: int | None = None
live_session_url: str | None = None
live_session_start: datetime | None = None
live_session_end: datetime | None = None
duration_minutes: int | None = None
is_required: int | None = None
position: int | None = None
class LessonResponse(BaseModel):
id: int
module_id: int
title: str
description: str | None = None
position: int
lesson_type: str
content_text: str | None = None
video_url: str | None = None
video_provider: str | None = None
local_file_path: str | None = None
quiz_id: int | None = None
live_session_url: str | None = None
live_session_start: datetime | None = None
live_session_end: datetime | None = None
bbb_meeting_id: str | None = None
duration_minutes: int | None = None
is_required: int = 1
class Config:
from_attributes = True
class ModuleResponse(BaseModel):
id: int
course_id: int
title: str
description: str | None = None
position: int
lessons: list[LessonResponse] = []
class Config:
from_attributes = True
class CourseResponse(BaseModel):
id: int
title: str
description: str | None = None
thumbnail_path: str | None = None
user_id: int
status: str
is_featured: int = 0
requires_subscription: int = 0
created_at: datetime
updated_at: datetime | None = None
class Config:
from_attributes = True
class CourseDetail(CourseResponse):
modules: list[ModuleResponse] = []
creator_name: str | None = None
enrolled_count: int = 0
my_enrollment: dict | None = None
class EnrollmentResponse(BaseModel):
id: int
course_id: int
user_id: int
enrolled_at: datetime
completed_at: datetime | None = None
progress_pct: float = 0.0
status: str
class Config:
from_attributes = True
class LessonProgressUpdate(BaseModel):
status: str | None = None # in_progress, completed
time_spent_seconds: int | None = None
score: float | None = None
class AIContentRequest(BaseModel):
prompt: str
action: str = "generate" # generate, refine
existing_content: str | None = None