mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: init CourseUpdates backend CRUD
This commit is contained in:
parent
171feabe99
commit
d1a620b2e2
4 changed files with 260 additions and 2 deletions
41
apps/api/src/db/course_updates.py
Normal file
41
apps/api/src/db/course_updates.py
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
from typing import Optional
|
||||||
|
from sqlalchemy import Column, ForeignKey, Integer
|
||||||
|
from sqlmodel import Field, SQLModel
|
||||||
|
|
||||||
|
|
||||||
|
class CourseUpdate(SQLModel, table=True):
|
||||||
|
id: Optional[int] = Field(default=None, primary_key=True)
|
||||||
|
courseupdate_uuid: str
|
||||||
|
title: str
|
||||||
|
content: str
|
||||||
|
course_id: int = Field(
|
||||||
|
sa_column=Column(Integer, ForeignKey("course.id", ondelete="CASCADE"))
|
||||||
|
)
|
||||||
|
linked_activity_uuids: Optional[str] = Field(default=None)
|
||||||
|
org_id: int = Field(default=None, foreign_key="organization.id")
|
||||||
|
creation_date: str
|
||||||
|
update_date: str
|
||||||
|
|
||||||
|
class CourseUpdateCreate(SQLModel):
|
||||||
|
title: str
|
||||||
|
content: str
|
||||||
|
linked_activity_uuids: Optional[str] = Field(default=None)
|
||||||
|
org_id: int
|
||||||
|
|
||||||
|
class CourseUpdateRead(SQLModel):
|
||||||
|
id: int
|
||||||
|
title: str
|
||||||
|
content: str
|
||||||
|
course_id: int
|
||||||
|
courseupdate_uuid: str
|
||||||
|
linked_activity_uuids: Optional[str] = Field(default=None)
|
||||||
|
org_id: int
|
||||||
|
creation_date: str
|
||||||
|
update_date: str
|
||||||
|
|
||||||
|
class CourseUpdateUpdate(SQLModel):
|
||||||
|
title: Optional[str] = None
|
||||||
|
content: Optional[str] = None
|
||||||
|
linked_activity_uuids: Optional[str] = Field(default=None)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2,6 +2,11 @@ from typing import List
|
||||||
from fastapi import APIRouter, Depends, UploadFile, Form, Request
|
from fastapi import APIRouter, Depends, UploadFile, Form, Request
|
||||||
from sqlmodel import Session
|
from sqlmodel import Session
|
||||||
from src.core.events.database import get_db_session
|
from src.core.events.database import get_db_session
|
||||||
|
from src.db.course_updates import (
|
||||||
|
CourseUpdateCreate,
|
||||||
|
CourseUpdateRead,
|
||||||
|
CourseUpdateUpdate,
|
||||||
|
)
|
||||||
from src.db.users import PublicUser
|
from src.db.users import PublicUser
|
||||||
from src.db.courses import (
|
from src.db.courses import (
|
||||||
CourseCreate,
|
CourseCreate,
|
||||||
|
|
@ -19,6 +24,7 @@ from src.services.courses.courses import (
|
||||||
delete_course,
|
delete_course,
|
||||||
update_course_thumbnail,
|
update_course_thumbnail,
|
||||||
)
|
)
|
||||||
|
from src.services.courses.updates import create_update, delete_update, get_updates_by_course_uuid, update_update
|
||||||
|
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
@ -51,7 +57,9 @@ async def api_create_course(
|
||||||
learnings=learnings,
|
learnings=learnings,
|
||||||
tags=tags,
|
tags=tags,
|
||||||
)
|
)
|
||||||
return await create_course(request, org_id, course, current_user, db_session, thumbnail)
|
return await create_course(
|
||||||
|
request, org_id, course, current_user, db_session, thumbnail
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.put("/{course_uuid}/thumbnail")
|
@router.put("/{course_uuid}/thumbnail")
|
||||||
|
|
@ -145,3 +153,64 @@ async def api_delete_course(
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return await delete_course(request, course_uuid, current_user, db_session)
|
return await delete_course(request, course_uuid, current_user, db_session)
|
||||||
|
|
||||||
|
@ router.get("/{course_uuid}/updates")
|
||||||
|
async def api_get_course_updates(
|
||||||
|
request: Request,
|
||||||
|
course_uuid: str,
|
||||||
|
db_session: Session = Depends(get_db_session),
|
||||||
|
current_user: PublicUser = Depends(get_current_user),
|
||||||
|
) -> List[CourseUpdateRead]:
|
||||||
|
"""
|
||||||
|
Get Course Updates by course_uuid
|
||||||
|
"""
|
||||||
|
|
||||||
|
return await get_updates_by_course_uuid(request, course_uuid, current_user, db_session)
|
||||||
|
|
||||||
|
@router.post("/{course_uuid}/update")
|
||||||
|
async def api_create_course_update(
|
||||||
|
request: Request,
|
||||||
|
course_uuid: str,
|
||||||
|
update_object: CourseUpdateCreate,
|
||||||
|
db_session: Session = Depends(get_db_session),
|
||||||
|
current_user: PublicUser = Depends(get_current_user),
|
||||||
|
) -> CourseUpdateRead:
|
||||||
|
"""
|
||||||
|
Create new Course Update
|
||||||
|
"""
|
||||||
|
|
||||||
|
return await create_update(
|
||||||
|
request, course_uuid, update_object, current_user, db_session
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.put("/{course_uuid}/update/{courseupdate_uuid}")
|
||||||
|
async def api_update_course_update(
|
||||||
|
request: Request,
|
||||||
|
course_uuid: str,
|
||||||
|
courseupdate_uuid: str,
|
||||||
|
update_object: CourseUpdateUpdate,
|
||||||
|
db_session: Session = Depends(get_db_session),
|
||||||
|
current_user: PublicUser = Depends(get_current_user),
|
||||||
|
) -> CourseUpdateRead:
|
||||||
|
"""
|
||||||
|
Update Course Update by courseupdate_uuid
|
||||||
|
"""
|
||||||
|
|
||||||
|
return await update_update(
|
||||||
|
request, courseupdate_uuid, update_object, current_user, db_session
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.delete("/{course_uuid}/update/{courseupdate_uuid}")
|
||||||
|
async def api_delete_course_update(
|
||||||
|
request: Request,
|
||||||
|
course_uuid: str,
|
||||||
|
courseupdate_uuid: str,
|
||||||
|
db_session: Session = Depends(get_db_session),
|
||||||
|
current_user: PublicUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Delete Course Update by courseupdate_uuid
|
||||||
|
"""
|
||||||
|
|
||||||
|
return await delete_update(request, courseupdate_uuid, current_user, db_session)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ async def check_element_type(element_uuid):
|
||||||
"""
|
"""
|
||||||
Check if the element is a course, a user, a house or a collection, by checking its prefix
|
Check if the element is a course, a user, a house or a collection, by checking its prefix
|
||||||
"""
|
"""
|
||||||
if element_uuid.startswith("course_"):
|
if element_uuid.startswith("course_") or element_uuid.startswith("courseupdate_"):
|
||||||
return "courses"
|
return "courses"
|
||||||
elif element_uuid.startswith("user_"):
|
elif element_uuid.startswith("user_"):
|
||||||
return "users"
|
return "users"
|
||||||
|
|
|
||||||
148
apps/api/src/services/courses/updates.py
Normal file
148
apps/api/src/services/courses/updates.py
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import List
|
||||||
|
from uuid import uuid4
|
||||||
|
from fastapi import HTTPException, Request, status
|
||||||
|
from sqlmodel import Session, select
|
||||||
|
from src.db.course_updates import (
|
||||||
|
CourseUpdate,
|
||||||
|
CourseUpdateCreate,
|
||||||
|
CourseUpdateRead,
|
||||||
|
CourseUpdateUpdate,
|
||||||
|
)
|
||||||
|
from src.db.courses import Course
|
||||||
|
from src.db.organizations import Organization
|
||||||
|
from src.db.users import AnonymousUser, PublicUser
|
||||||
|
from src.services.courses.courses import rbac_check
|
||||||
|
|
||||||
|
|
||||||
|
async def create_update(
|
||||||
|
request: Request,
|
||||||
|
course_uuid: str,
|
||||||
|
update_object: CourseUpdateCreate,
|
||||||
|
current_user: PublicUser | AnonymousUser,
|
||||||
|
db_session: Session,
|
||||||
|
) -> CourseUpdateRead:
|
||||||
|
|
||||||
|
# CHekc if org exists
|
||||||
|
statement_org = select(Organization).where(Organization.id == update_object.org_id)
|
||||||
|
org = db_session.exec(statement_org).first()
|
||||||
|
|
||||||
|
if not org or org.id is None:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_409_CONFLICT, detail="Organization does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
|
statement = select(Course).where(Course.course_uuid == course_uuid)
|
||||||
|
course = db_session.exec(statement).first()
|
||||||
|
|
||||||
|
if not course or course.id is None:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
|
# RBAC check
|
||||||
|
await rbac_check(request, course.course_uuid, current_user, "update", db_session)
|
||||||
|
|
||||||
|
# Generate UUID
|
||||||
|
courseupdate_uuid = str(f"courseupdate_{uuid4()}")
|
||||||
|
|
||||||
|
update = CourseUpdate(
|
||||||
|
**update_object.model_dump(),
|
||||||
|
course_id=course.id,
|
||||||
|
courseupdate_uuid=courseupdate_uuid,
|
||||||
|
creation_date=str(datetime.now()),
|
||||||
|
update_date=str(datetime.now()),
|
||||||
|
)
|
||||||
|
|
||||||
|
db_session.add(update)
|
||||||
|
|
||||||
|
db_session.commit()
|
||||||
|
db_session.refresh(update)
|
||||||
|
|
||||||
|
return CourseUpdateRead(**update.model_dump())
|
||||||
|
|
||||||
|
|
||||||
|
# Update Course Update
|
||||||
|
async def update_update(
|
||||||
|
request: Request,
|
||||||
|
courseupdate_uuid: str,
|
||||||
|
update_object: CourseUpdateUpdate,
|
||||||
|
current_user: PublicUser | AnonymousUser,
|
||||||
|
db_session: Session,
|
||||||
|
) -> CourseUpdateRead:
|
||||||
|
statement = select(CourseUpdate).where(
|
||||||
|
CourseUpdate.courseupdate_uuid == courseupdate_uuid
|
||||||
|
)
|
||||||
|
update = db_session.exec(statement).first()
|
||||||
|
|
||||||
|
if not update or update.id is None:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_409_CONFLICT, detail="Update does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
|
# RBAC check
|
||||||
|
await rbac_check(
|
||||||
|
request, update.courseupdate_uuid, current_user, "update", db_session
|
||||||
|
)
|
||||||
|
|
||||||
|
for key, value in update_object.model_dump().items():
|
||||||
|
if value is not None:
|
||||||
|
setattr(update, key, value)
|
||||||
|
|
||||||
|
|
||||||
|
db_session.add(update)
|
||||||
|
|
||||||
|
db_session.commit()
|
||||||
|
db_session.refresh(update)
|
||||||
|
|
||||||
|
return CourseUpdateRead(**update.model_dump())
|
||||||
|
|
||||||
|
|
||||||
|
# Delete Course Update
|
||||||
|
async def delete_update(
|
||||||
|
request: Request,
|
||||||
|
courseupdate_uuid: str,
|
||||||
|
current_user: PublicUser | AnonymousUser,
|
||||||
|
db_session: Session,
|
||||||
|
):
|
||||||
|
statement = select(CourseUpdate).where(
|
||||||
|
CourseUpdate.courseupdate_uuid == courseupdate_uuid
|
||||||
|
)
|
||||||
|
update = db_session.exec(statement).first()
|
||||||
|
|
||||||
|
if not update or update.id is None:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_409_CONFLICT, detail="Update does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
|
# RBAC check
|
||||||
|
await rbac_check(
|
||||||
|
request, update.courseupdate_uuid, current_user, "delete", db_session
|
||||||
|
)
|
||||||
|
|
||||||
|
db_session.delete(update)
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
return {"message": "Update deleted successfully"}
|
||||||
|
|
||||||
|
|
||||||
|
# Get Course Updates by Course ID
|
||||||
|
async def get_updates_by_course_uuid(
|
||||||
|
request: Request,
|
||||||
|
course_uuid: str,
|
||||||
|
current_user: PublicUser | AnonymousUser,
|
||||||
|
db_session: Session,
|
||||||
|
) -> List[CourseUpdateRead]:
|
||||||
|
# FInd if course exists
|
||||||
|
statement = select(Course).where(Course.course_uuid == course_uuid)
|
||||||
|
course = db_session.exec(statement).first()
|
||||||
|
|
||||||
|
if not course or course.id is None:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
|
statement = select(CourseUpdate).where(CourseUpdate.course_id == course.id)
|
||||||
|
updates = db_session.exec(statement).all()
|
||||||
|
|
||||||
|
return [CourseUpdateRead(**update.model_dump()) for update in updates]
|
||||||
Loading…
Add table
Add a link
Reference in a new issue