template tutoring-admin-dashboard v1
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
"""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()
|
||||
Reference in New Issue
Block a user