nex_math/backend/routers/courses.py

97 lines
2.7 KiB
Python

"""在线课程:只有外链的视频/课程资源,与教材分表维护。"""
from __future__ import annotations
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from database import get_db
from dependencies import get_current_user, require_permission
from models import Course, User
from schemas import CourseCreate, CourseOut, CourseUpdate
router = APIRouter(prefix="/courses", tags=["courses"])
def _load(db: Session, course_id: int) -> Course:
course = db.get(Course, course_id)
if course is None:
raise HTTPException(status_code=404, detail="课程不存在")
return course
def _clean_url(url: str | None) -> str:
url = (url or "").strip()
if not url:
raise HTTPException(status_code=400, detail="请填写课程链接")
return url
@router.get("", response_model=list[CourseOut])
def list_courses(
db: Session = Depends(get_db),
_: User = Depends(get_current_user),
):
return (
db.query(Course)
.order_by(Course.position.asc(), Course.id.asc())
.all()
)
@router.post("", response_model=CourseOut)
def create_course(
payload: CourseCreate,
db: Session = Depends(get_db),
_: User = Depends(require_permission("catalog:manage")),
):
if db.query(Course).filter(Course.name == payload.name).first():
raise HTTPException(status_code=400, detail="同名课程已存在")
course = Course(
name=payload.name,
provider=payload.provider,
url=_clean_url(payload.url),
grade=payload.grade,
description=payload.description,
position=db.query(Course).count(),
)
db.add(course)
db.commit()
return course
@router.put("/{course_id}", response_model=CourseOut)
def update_course(
course_id: int,
payload: CourseUpdate,
db: Session = Depends(get_db),
_: User = Depends(require_permission("catalog:manage")),
):
course = _load(db, course_id)
fields = payload.model_dump(exclude_unset=True)
if "name" in fields and fields["name"] != course.name:
exists = (
db.query(Course)
.filter(Course.name == fields["name"], Course.id != course.id)
.first()
)
if exists:
raise HTTPException(status_code=400, detail="同名课程已存在")
if "url" in fields:
fields["url"] = _clean_url(fields["url"])
for field, value in fields.items():
setattr(course, field, value)
db.commit()
return course
@router.delete("/{course_id}")
def delete_course(
course_id: int,
db: Session = Depends(get_db),
_: User = Depends(require_permission("catalog:manage")),
):
course = _load(db, course_id)
db.delete(course)
db.commit()
return {"deleted": course_id}