mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: init chapters, coursechapters. fix courses
This commit is contained in:
parent
eca819b896
commit
4fcc8aa77c
8 changed files with 151 additions and 36 deletions
|
|
@ -50,7 +50,7 @@ class ActivityCreate(ActivityBase):
|
||||||
order: int
|
order: int
|
||||||
org_id: int = Field(default=None, foreign_key="organization.id")
|
org_id: int = Field(default=None, foreign_key="organization.id")
|
||||||
course_id: int = Field(default=None, foreign_key="course.id")
|
course_id: int = Field(default=None, foreign_key="course.id")
|
||||||
chapter_id : int
|
chapter_id: int
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from enum import Enum
|
||||||
class ChapterActivity(SQLModel, table=True):
|
class ChapterActivity(SQLModel, table=True):
|
||||||
id: Optional[int] = Field(default=None, primary_key=True)
|
id: Optional[int] = Field(default=None, primary_key=True)
|
||||||
order: int
|
order: int
|
||||||
chapter_id: int = Field(default=None, foreign_key="chapter.id")
|
chapter_id: int = Field(default=None, foreign_key="chapter.id", )
|
||||||
activity_id: int = Field(default=None, foreign_key="activity.id")
|
activity_id: int = Field(default=None, foreign_key="activity.id")
|
||||||
course_id : int = Field(default=None, foreign_key="course.id")
|
course_id : int = Field(default=None, foreign_key="course.id")
|
||||||
org_id : int = Field(default=None, foreign_key="organization.id")
|
org_id : int = Field(default=None, foreign_key="organization.id")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
from typing import Optional
|
from typing import List, Optional
|
||||||
|
from pydantic import BaseModel
|
||||||
from sqlmodel import Field, SQLModel
|
from sqlmodel import Field, SQLModel
|
||||||
|
from src.db.activities import Activity, ActivityRead, ActivityUpdate
|
||||||
|
|
||||||
|
|
||||||
class ChapterBase(SQLModel):
|
class ChapterBase(SQLModel):
|
||||||
|
|
@ -7,24 +9,55 @@ class ChapterBase(SQLModel):
|
||||||
description: Optional[str] = ""
|
description: Optional[str] = ""
|
||||||
thumbnail_image: Optional[str] = ""
|
thumbnail_image: Optional[str] = ""
|
||||||
org_id: int = Field(default=None, foreign_key="organization.id")
|
org_id: int = Field(default=None, foreign_key="organization.id")
|
||||||
|
course_id: int = Field(default=None, foreign_key="course.id")
|
||||||
creation_date: str
|
creation_date: str
|
||||||
update_date: str
|
update_date: str
|
||||||
|
|
||||||
|
|
||||||
class Chapter(ChapterBase, table=True):
|
class Chapter(ChapterBase, table=True):
|
||||||
id: Optional[int] = Field(default=None, primary_key=True)
|
id: Optional[int] = Field(default=None, primary_key=True)
|
||||||
chapter_uuid: str
|
chapter_uuid: str = ""
|
||||||
creation_date: str
|
creation_date: str = ""
|
||||||
update_date: str
|
update_date: str = ""
|
||||||
|
|
||||||
|
|
||||||
class ChapterCreate(ChapterBase):
|
class ChapterCreate(ChapterBase):
|
||||||
|
# referenced order here will be ignored and just used for validation
|
||||||
|
# used order will be the next available.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ChapterUpdate(ChapterBase):
|
||||||
|
chapter_id: int
|
||||||
|
name: Optional[str]
|
||||||
|
description: Optional[str]
|
||||||
|
thumbnail_image: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class ChapterRead(ChapterBase):
|
class ChapterRead(ChapterBase):
|
||||||
id: int
|
id: int
|
||||||
|
activities: List[ActivityRead]
|
||||||
chapter_uuid: str
|
chapter_uuid: str
|
||||||
creation_date: str
|
creation_date: str
|
||||||
update_date: str
|
update_date: str
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ActivityOrder(BaseModel):
|
||||||
|
activity_id: int
|
||||||
|
|
||||||
|
|
||||||
|
class ChapterOrder(BaseModel):
|
||||||
|
chapter_id: int
|
||||||
|
activities_order_by_ids: List[ActivityOrder]
|
||||||
|
|
||||||
|
|
||||||
|
class ChapterUpdateOrder(BaseModel):
|
||||||
|
chapter_order_by_ids: List[ChapterOrder]
|
||||||
|
|
||||||
|
|
||||||
|
class DepreceatedChaptersRead(BaseModel):
|
||||||
|
chapter_order: list[str]
|
||||||
|
chapters: List[ChapterRead]
|
||||||
|
activities: List[ActivityRead]
|
||||||
|
pass
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
from typing import Optional
|
from typing import List, Optional
|
||||||
from sqlmodel import Field, SQLModel
|
from sqlmodel import Field, SQLModel
|
||||||
|
|
||||||
|
from src.db.chapters import ChapterRead
|
||||||
|
|
||||||
|
|
||||||
class CourseBase(SQLModel):
|
class CourseBase(SQLModel):
|
||||||
name: str
|
name: str
|
||||||
|
|
@ -41,3 +43,13 @@ class CourseRead(CourseBase):
|
||||||
creation_date: str
|
creation_date: str
|
||||||
update_date: str
|
update_date: str
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FullCourseRead(CourseBase):
|
||||||
|
id: int
|
||||||
|
course_uuid: str
|
||||||
|
creation_date: str
|
||||||
|
update_date: str
|
||||||
|
# Chapters, Activities
|
||||||
|
chapters: List[ChapterRead]
|
||||||
|
pass
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,23 @@
|
||||||
|
from typing import List
|
||||||
from fastapi import APIRouter, Depends, Request
|
from fastapi import APIRouter, Depends, Request
|
||||||
|
from src.core.events.database import get_db_session
|
||||||
|
from src.db.chapters import (
|
||||||
|
ChapterCreate,
|
||||||
|
ChapterRead,
|
||||||
|
ChapterUpdate,
|
||||||
|
ChapterUpdateOrder,
|
||||||
|
DepreceatedChaptersRead,
|
||||||
|
)
|
||||||
|
from src.services.courses.chapters import (
|
||||||
|
create_chapter,
|
||||||
|
delete_chapter,
|
||||||
|
get_chapter,
|
||||||
|
get_course_chapters,
|
||||||
|
get_depreceated_course_chapters,
|
||||||
|
reorder_chapters_and_activities,
|
||||||
|
update_chapter,
|
||||||
|
)
|
||||||
|
|
||||||
from src.services.courses.chapters import CourseChapter, CourseChapterMetaData, create_coursechapter, delete_coursechapter, get_coursechapter, get_coursechapters, get_coursechapters_meta, update_coursechapter, update_coursechapters_meta
|
|
||||||
from src.services.users.users import PublicUser
|
from src.services.users.users import PublicUser
|
||||||
from src.security.auth import get_current_user
|
from src.security.auth import get_current_user
|
||||||
|
|
||||||
|
|
@ -8,57 +25,99 @@ router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
@router.post("/")
|
@router.post("/")
|
||||||
async def api_create_coursechapter(request: Request,coursechapter_object: CourseChapter, course_id: str, current_user: PublicUser = Depends(get_current_user)):
|
async def api_create_coursechapter(
|
||||||
|
request: Request,
|
||||||
|
coursechapter_object: ChapterCreate,
|
||||||
|
current_user: PublicUser = Depends(get_current_user),
|
||||||
|
db_session=Depends(get_db_session),
|
||||||
|
) -> ChapterRead:
|
||||||
"""
|
"""
|
||||||
Create new CourseChapter
|
Create new Course Chapter
|
||||||
"""
|
"""
|
||||||
return await create_coursechapter(request, coursechapter_object, course_id, current_user)
|
return await create_chapter(request, coursechapter_object, current_user, db_session)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{coursechapter_id}")
|
@router.get("/{chapter_id}")
|
||||||
async def api_get_coursechapter(request: Request,coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)):
|
async def api_get_coursechapter(
|
||||||
|
request: Request,
|
||||||
|
chapter_id: int,
|
||||||
|
current_user: PublicUser = Depends(get_current_user),
|
||||||
|
db_session=Depends(get_db_session),
|
||||||
|
) -> ChapterRead:
|
||||||
"""
|
"""
|
||||||
Get single CourseChapter by coursechapter_id
|
Get single CourseChapter by chapter_id
|
||||||
"""
|
"""
|
||||||
return await get_coursechapter(request, coursechapter_id, current_user=current_user)
|
return await get_chapter(request, chapter_id, current_user, db_session)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/meta/{course_id}")
|
@router.get("/meta/{course_id}")
|
||||||
async def api_get_coursechapter_meta(request: Request,course_id: str, current_user: PublicUser = Depends(get_current_user)):
|
async def api_get_chapter_meta(
|
||||||
|
request: Request,
|
||||||
|
course_id: int,
|
||||||
|
current_user: PublicUser = Depends(get_current_user),
|
||||||
|
db_session=Depends(get_db_session),
|
||||||
|
) -> DepreceatedChaptersRead:
|
||||||
"""
|
"""
|
||||||
Get coursechapter metadata
|
Get Chapters metadata
|
||||||
"""
|
"""
|
||||||
return await get_coursechapters_meta(request, course_id, current_user=current_user)
|
return await get_depreceated_course_chapters(request, course_id, current_user, db_session)
|
||||||
|
|
||||||
|
|
||||||
@router.put("/meta/{course_id}")
|
@router.put("/order/{course_id}")
|
||||||
async def api_update_coursechapter_meta(request: Request,course_id: str, coursechapters_metadata: CourseChapterMetaData, current_user: PublicUser = Depends(get_current_user)):
|
async def api_update_chapter_meta(
|
||||||
|
request: Request,
|
||||||
|
course_id: int,
|
||||||
|
order: ChapterUpdateOrder,
|
||||||
|
current_user: PublicUser = Depends(get_current_user),
|
||||||
|
db_session=Depends(get_db_session),
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Update coursechapter metadata
|
Update Chapter metadata
|
||||||
"""
|
"""
|
||||||
return await update_coursechapters_meta(request, course_id, coursechapters_metadata, current_user=current_user)
|
return await reorder_chapters_and_activities(
|
||||||
|
request, course_id, order, current_user, db_session
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{course_id}/page/{page}/limit/{limit}")
|
@router.get("/{course_id}/page/{page}/limit/{limit}")
|
||||||
async def api_get_coursechapter_by(request: Request,course_id: str, page: int, limit: int):
|
async def api_get_chapter_by(
|
||||||
|
request: Request,
|
||||||
|
course_id: int,
|
||||||
|
page: int,
|
||||||
|
limit: int,
|
||||||
|
db_session=Depends(get_db_session),
|
||||||
|
) -> List[ChapterRead]:
|
||||||
"""
|
"""
|
||||||
Get CourseChapters by page and limit
|
Get Course Chapters by page and limit
|
||||||
"""
|
"""
|
||||||
return await get_coursechapters(request, course_id, page, limit)
|
return await get_course_chapters(request, course_id, db_session, page, limit)
|
||||||
|
|
||||||
|
|
||||||
@router.put("/{coursechapter_id}")
|
@router.put("/{coursechapter_id}")
|
||||||
async def api_update_coursechapter(request: Request,coursechapter_object: CourseChapter, coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)):
|
async def api_update_coursechapter(
|
||||||
|
request: Request,
|
||||||
|
coursechapter_object: ChapterUpdate,
|
||||||
|
coursechapter_id: str,
|
||||||
|
current_user: PublicUser = Depends(get_current_user),
|
||||||
|
db_session=Depends(get_db_session),
|
||||||
|
) -> ChapterRead:
|
||||||
"""
|
"""
|
||||||
Update CourseChapters by course_id
|
Update CourseChapters by course_id
|
||||||
"""
|
"""
|
||||||
return await update_coursechapter(request, coursechapter_object, coursechapter_id, current_user)
|
return await update_chapter(request, coursechapter_object, current_user, db_session)
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/{coursechapter_id}")
|
@router.delete("/{coursechapter_id}")
|
||||||
async def api_delete_coursechapter(request: Request,coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)):
|
async def api_delete_coursechapter(
|
||||||
|
request: Request,
|
||||||
|
coursechapter_id: str,
|
||||||
|
current_user: PublicUser = Depends(get_current_user),
|
||||||
|
db_session=Depends(get_db_session),
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Delete CourseChapters by ID
|
Delete CourseChapters by ID
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return await delete_coursechapter(request,coursechapter_id, current_user)
|
return await delete_chapter(
|
||||||
|
request, coursechapter_id, current_user, db_session
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ async def api_create_course(
|
||||||
tags=tags,
|
tags=tags,
|
||||||
)
|
)
|
||||||
return await create_course(
|
return await create_course(
|
||||||
request, course, org_id, current_user, db_session, thumbnail
|
request, course, current_user, db_session, thumbnail
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import stat
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from sqlmodel import Session, select
|
from sqlmodel import Session, select
|
||||||
|
from src.db.chapters import Chapter
|
||||||
from src.db.organizations import Organization
|
from src.db.organizations import Organization
|
||||||
from src import db
|
from src import db
|
||||||
from src.db.activities import ActivityCreate, Activity, ActivityRead, ActivityUpdate
|
from src.db.activities import ActivityCreate, Activity, ActivityRead, ActivityUpdate
|
||||||
|
|
@ -49,15 +50,26 @@ async def create_activity(
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
db_session.refresh(activity)
|
db_session.refresh(activity)
|
||||||
|
|
||||||
|
# Find the last activity in the Chapter and add it to the list
|
||||||
|
statement = (
|
||||||
|
select(ChapterActivity)
|
||||||
|
.where(ChapterActivity.chapter_id == activity_object.chapter_id)
|
||||||
|
.order_by(ChapterActivity.order)
|
||||||
|
)
|
||||||
|
chapter_activities = db_session.exec(statement).all()
|
||||||
|
|
||||||
|
last_order = chapter_activities[-1].order if chapter_activities else 0
|
||||||
|
to_be_used_order = last_order + 1
|
||||||
|
|
||||||
# Add activity to chapter
|
# Add activity to chapter
|
||||||
activity_chapter = ChapterActivity(
|
activity_chapter = ChapterActivity(
|
||||||
chapter_id=activity_object.chapter_id,
|
chapter_id=activity_object.chapter_id,
|
||||||
activity_id=activity.id is not None,
|
activity_id=activity.id if activity.id else 0,
|
||||||
course_id=activity_object.course_id,
|
course_id=activity_object.course_id,
|
||||||
org_id=activity_object.org_id,
|
org_id=activity_object.org_id,
|
||||||
creation_date=str(datetime.now()),
|
creation_date=str(datetime.now()),
|
||||||
update_date=str(datetime.now()),
|
update_date=str(datetime.now()),
|
||||||
order=activity_object.order,
|
order=to_be_used_order,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Insert ChapterActivity link in DB
|
# Insert ChapterActivity link in DB
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,6 @@ async def get_course_meta(
|
||||||
async def create_course(
|
async def create_course(
|
||||||
request: Request,
|
request: Request,
|
||||||
course_object: CourseCreate,
|
course_object: CourseCreate,
|
||||||
org_id: int,
|
|
||||||
current_user: PublicUser,
|
current_user: PublicUser,
|
||||||
db_session: Session,
|
db_session: Session,
|
||||||
thumbnail_file: UploadFile | None = None,
|
thumbnail_file: UploadFile | None = None,
|
||||||
|
|
@ -62,7 +61,7 @@ async def create_course(
|
||||||
course = Course.from_orm(course_object)
|
course = Course.from_orm(course_object)
|
||||||
|
|
||||||
# Complete course object
|
# Complete course object
|
||||||
course.org_id = org_id
|
course.org_id = course.org_id
|
||||||
course.course_uuid = str(uuid4())
|
course.course_uuid = str(uuid4())
|
||||||
course.creation_date = str(datetime.now())
|
course.creation_date = str(datetime.now())
|
||||||
course.update_date = str(datetime.now())
|
course.update_date = str(datetime.now())
|
||||||
|
|
@ -70,7 +69,7 @@ async def create_course(
|
||||||
# Upload thumbnail
|
# Upload thumbnail
|
||||||
if thumbnail_file and thumbnail_file.filename:
|
if thumbnail_file and thumbnail_file.filename:
|
||||||
name_in_disk = f"{course.course_uuid}_thumbnail_{uuid4()}.{thumbnail_file.filename.split('.')[-1]}"
|
name_in_disk = f"{course.course_uuid}_thumbnail_{uuid4()}.{thumbnail_file.filename.split('.')[-1]}"
|
||||||
await upload_thumbnail(thumbnail_file, name_in_disk, org_id, course.course_uuid)
|
await upload_thumbnail(thumbnail_file, name_in_disk, course_object.org_id, course.course_uuid)
|
||||||
course_object.thumbnail = name_in_disk
|
course_object.thumbnail = name_in_disk
|
||||||
|
|
||||||
# Insert course
|
# Insert course
|
||||||
|
|
@ -80,7 +79,7 @@ async def create_course(
|
||||||
|
|
||||||
# Make the user the creator of the course
|
# Make the user the creator of the course
|
||||||
course_author = CourseAuthor(
|
course_author = CourseAuthor(
|
||||||
course_id=course.id is not None,
|
course_id=course.id if course.id else 0,
|
||||||
user_id=current_user.id,
|
user_id=current_user.id,
|
||||||
authorship=CourseAuthorshipEnum.CREATOR,
|
authorship=CourseAuthorshipEnum.CREATOR,
|
||||||
creation_date=str(datetime.now()),
|
creation_date=str(datetime.now()),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue