242 lines
6.7 KiB
Python
242 lines
6.7 KiB
Python
"""Admin (JWT-protected) endpoints: edit every section, manage enquiries.
|
|
|
|
All routes here depend on ``get_current_admin`` via the router dependency, so an
|
|
unauthenticated request gets 401 before reaching a handler.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.db import get_db
|
|
from app.models import (
|
|
Course,
|
|
Enquiry,
|
|
FeePlan,
|
|
Profile,
|
|
Review,
|
|
SiteSettings,
|
|
Subject,
|
|
Testimonial,
|
|
)
|
|
from app.schemas import (
|
|
CourseIn,
|
|
CourseOut,
|
|
EnquiryOut,
|
|
EnquiryPatch,
|
|
FeePlanIn,
|
|
FeePlanOut,
|
|
ProfileIn,
|
|
ProfileOut,
|
|
ReviewOut,
|
|
ReviewPatch,
|
|
SiteSettingsIn,
|
|
SiteSettingsOut,
|
|
SubjectIn,
|
|
SubjectOut,
|
|
TestimonialIn,
|
|
TestimonialOut,
|
|
)
|
|
from app.security import get_current_admin
|
|
|
|
router = APIRouter(prefix="/admin", dependencies=[Depends(get_current_admin)])
|
|
|
|
|
|
# ---- Profile (singleton) ----
|
|
@router.put("/profile", response_model=ProfileOut)
|
|
def update_profile(body: ProfileIn, db: Session = Depends(get_db)) -> Profile:
|
|
obj = db.query(Profile).first()
|
|
if not obj:
|
|
obj = Profile()
|
|
db.add(obj)
|
|
for k, v in body.model_dump().items():
|
|
setattr(obj, k, v)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
# ---- Settings (singleton) ----
|
|
@router.put("/settings", response_model=SiteSettingsOut)
|
|
def update_settings(body: SiteSettingsIn, db: Session = Depends(get_db)) -> SiteSettings:
|
|
obj = db.query(SiteSettings).first()
|
|
if not obj:
|
|
obj = SiteSettings()
|
|
db.add(obj)
|
|
for k, v in body.model_dump().items():
|
|
setattr(obj, k, v)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
# ---- Subjects CRUD ----
|
|
@router.post("/subjects", response_model=SubjectOut, status_code=201)
|
|
def create_subject(body: SubjectIn, db: Session = Depends(get_db)) -> Subject:
|
|
obj = Subject(**body.model_dump())
|
|
db.add(obj)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
@router.put("/subjects/{item_id}", response_model=SubjectOut)
|
|
def update_subject(item_id: int, body: SubjectIn, db: Session = Depends(get_db)) -> Subject:
|
|
obj = db.get(Subject, item_id)
|
|
if not obj:
|
|
raise HTTPException(404, "Subject not found")
|
|
for k, v in body.model_dump().items():
|
|
setattr(obj, k, v)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
@router.delete("/subjects/{item_id}", status_code=204)
|
|
def delete_subject(item_id: int, db: Session = Depends(get_db)) -> None:
|
|
obj = db.get(Subject, item_id)
|
|
if obj:
|
|
db.delete(obj)
|
|
db.commit()
|
|
|
|
|
|
# ---- Courses CRUD ----
|
|
@router.post("/courses", response_model=CourseOut, status_code=201)
|
|
def create_course(body: CourseIn, db: Session = Depends(get_db)) -> Course:
|
|
obj = Course(**body.model_dump())
|
|
db.add(obj)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
@router.put("/courses/{item_id}", response_model=CourseOut)
|
|
def update_course(item_id: int, body: CourseIn, db: Session = Depends(get_db)) -> Course:
|
|
obj = db.get(Course, item_id)
|
|
if not obj:
|
|
raise HTTPException(404, "Course not found")
|
|
for k, v in body.model_dump().items():
|
|
setattr(obj, k, v)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
@router.delete("/courses/{item_id}", status_code=204)
|
|
def delete_course(item_id: int, db: Session = Depends(get_db)) -> None:
|
|
obj = db.get(Course, item_id)
|
|
if obj:
|
|
db.delete(obj)
|
|
db.commit()
|
|
|
|
|
|
# ---- Fees CRUD ----
|
|
@router.post("/fees", response_model=FeePlanOut, status_code=201)
|
|
def create_fee(body: FeePlanIn, db: Session = Depends(get_db)) -> FeePlan:
|
|
obj = FeePlan(**body.model_dump())
|
|
db.add(obj)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
@router.put("/fees/{item_id}", response_model=FeePlanOut)
|
|
def update_fee(item_id: int, body: FeePlanIn, db: Session = Depends(get_db)) -> FeePlan:
|
|
obj = db.get(FeePlan, item_id)
|
|
if not obj:
|
|
raise HTTPException(404, "Fee plan not found")
|
|
for k, v in body.model_dump().items():
|
|
setattr(obj, k, v)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
@router.delete("/fees/{item_id}", status_code=204)
|
|
def delete_fee(item_id: int, db: Session = Depends(get_db)) -> None:
|
|
obj = db.get(FeePlan, item_id)
|
|
if obj:
|
|
db.delete(obj)
|
|
db.commit()
|
|
|
|
|
|
# ---- Testimonials CRUD ----
|
|
@router.post("/testimonials", response_model=TestimonialOut, status_code=201)
|
|
def create_testimonial(body: TestimonialIn, db: Session = Depends(get_db)) -> Testimonial:
|
|
obj = Testimonial(**body.model_dump())
|
|
db.add(obj)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
@router.put("/testimonials/{item_id}", response_model=TestimonialOut)
|
|
def update_testimonial(item_id: int, body: TestimonialIn, db: Session = Depends(get_db)) -> Testimonial:
|
|
obj = db.get(Testimonial, item_id)
|
|
if not obj:
|
|
raise HTTPException(404, "Testimonial not found")
|
|
for k, v in body.model_dump().items():
|
|
setattr(obj, k, v)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
@router.delete("/testimonials/{item_id}", status_code=204)
|
|
def delete_testimonial(item_id: int, db: Session = Depends(get_db)) -> None:
|
|
obj = db.get(Testimonial, item_id)
|
|
if obj:
|
|
db.delete(obj)
|
|
db.commit()
|
|
|
|
|
|
# ---- Reviews (moderation) ----
|
|
@router.get("/reviews", response_model=list[ReviewOut])
|
|
def list_reviews(db: Session = Depends(get_db)) -> list[Review]:
|
|
return db.query(Review).order_by(Review.created_at.desc(), Review.id.desc()).all()
|
|
|
|
|
|
@router.patch("/reviews/{item_id}", response_model=ReviewOut)
|
|
def patch_review(item_id: int, body: ReviewPatch, db: Session = Depends(get_db)) -> Review:
|
|
obj = db.get(Review, item_id)
|
|
if not obj:
|
|
raise HTTPException(404, "Review not found")
|
|
obj.is_approved = body.is_approved
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
@router.delete("/reviews/{item_id}", status_code=204)
|
|
def delete_review(item_id: int, db: Session = Depends(get_db)) -> None:
|
|
obj = db.get(Review, item_id)
|
|
if obj:
|
|
db.delete(obj)
|
|
db.commit()
|
|
|
|
|
|
# ---- Enquiries ----
|
|
@router.get("/enquiries", response_model=list[EnquiryOut])
|
|
def list_enquiries(db: Session = Depends(get_db)) -> list[Enquiry]:
|
|
return db.query(Enquiry).order_by(Enquiry.created_at.desc(), Enquiry.id.desc()).all()
|
|
|
|
|
|
@router.patch("/enquiries/{item_id}", response_model=EnquiryOut)
|
|
def patch_enquiry(item_id: int, body: EnquiryPatch, db: Session = Depends(get_db)) -> Enquiry:
|
|
obj = db.get(Enquiry, item_id)
|
|
if not obj:
|
|
raise HTTPException(404, "Enquiry not found")
|
|
obj.is_read = body.is_read
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
@router.delete("/enquiries/{item_id}", status_code=204)
|
|
def delete_enquiry(item_id: int, db: Session = Depends(get_db)) -> None:
|
|
obj = db.get(Enquiry, item_id)
|
|
if obj:
|
|
db.delete(obj)
|
|
db.commit()
|