feat: merge coursechapters with courses

This commit is contained in:
swve 2023-04-07 23:12:23 +02:00
parent f0fb9b545a
commit 6eb396b459
4 changed files with 89 additions and 98 deletions

View file

@ -31,7 +31,7 @@ class ActivityInDB(Activity):
async def create_activity(request: Request, activity_object: Activity, org_id: str, coursechapter_id: str, current_user: PublicUser): async def create_activity(request: Request, activity_object: Activity, org_id: str, coursechapter_id: str, current_user: PublicUser):
activities = request.app.db["activities"] activities = request.app.db["activities"]
coursechapters = request.app.db["coursechapters"] courses = request.app.db["courses"]
# generate activity_id # generate activity_id
activity_id = str(f"activity_{uuid4()}") activity_id = str(f"activity_{uuid4()}")
@ -48,8 +48,8 @@ async def create_activity(request: Request, activity_object: Activity, org_id: s
await activities.insert_one(activity.dict()) await activities.insert_one(activity.dict())
# update chapter # update chapter
await coursechapters.update_one({"coursechapter_id": coursechapter_id}, { await courses.update_one({"chapters_content.coursechapter_id": coursechapter_id}, {
"$addToSet": {"activities": activity_id}}) "$addToSet": {"chapters_content.$.activities": activity_id}})
return activity return activity

View file

@ -1,5 +1,6 @@
from datetime import datetime from datetime import datetime
import json import json
import pprint
from typing import List from typing import List
from uuid import uuid4 from uuid import uuid4
from pydantic import BaseModel from pydantic import BaseModel
@ -36,10 +37,9 @@ class CourseChapterMetaData(BaseModel):
#################################################### ####################################################
async def create_coursechapter(request: Request,coursechapter_object: CourseChapter, course_id: str, current_user: PublicUser): async def create_coursechapter(request: Request, coursechapter_object: CourseChapter, course_id: str, current_user: PublicUser):
coursechapters = request.app.db["coursechapters"]
courses = request.app.db["courses"] courses = request.app.db["courses"]
print(course_id)
# get course org_id and verify rights # get course org_id and verify rights
course = await courses.find_one({"course_id": course_id}) course = await courses.find_one({"course_id": course_id})
@ -55,22 +55,17 @@ async def create_coursechapter(request: Request,coursechapter_object: CourseChap
coursechapter = CourseChapterInDB(coursechapter_id=coursechapter_id, creationDate=str( coursechapter = CourseChapterInDB(coursechapter_id=coursechapter_id, creationDate=str(
datetime.now()), updateDate=str(datetime.now()), course_id=course_id, **coursechapter_object.dict()) datetime.now()), updateDate=str(datetime.now()), course_id=course_id, **coursechapter_object.dict())
coursechapter_in_db = await coursechapters.insert_one(coursechapter.dict())
courses.update_one({"course_id": course_id}, { courses.update_one({"course_id": course_id}, {
"$addToSet": {"chapters": coursechapter_id}}) "$addToSet": {"chapters": coursechapter_id, "chapters_content": coursechapter.dict()}})
if not coursechapter_in_db:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Unavailable database")
return coursechapter.dict() return coursechapter.dict()
async def get_coursechapter(request: Request,coursechapter_id: str, current_user: PublicUser): async def get_coursechapter(request: Request, coursechapter_id: str, current_user: PublicUser):
coursechapters = request.app.db["coursechapters"] courses = request.app.db["courses"]
coursechapter = await coursechapters.find_one( coursechapter = await courses.find_one(
{"coursechapter_id": coursechapter_id}) {"chapters_content.coursechapter_id": coursechapter_id})
if coursechapter: if coursechapter:
# verify course rights # verify course rights
@ -84,57 +79,44 @@ async def get_coursechapter(request: Request,coursechapter_id: str, current_user
status_code=status.HTTP_409_CONFLICT, detail="CourseChapter does not exist") status_code=status.HTTP_409_CONFLICT, detail="CourseChapter does not exist")
async def update_coursechapter(request: Request,coursechapter_object: CourseChapter, coursechapter_id: str, current_user: PublicUser): async def update_coursechapter(request: Request, coursechapter_object: CourseChapter, coursechapter_id: str, current_user: PublicUser):
coursechapters = request.app.db["coursechapters"] courses = request.app.db["courses"]
coursechapter = await coursechapters.find_one( coursechapter = await courses.find_one(
{"coursechapter_id": coursechapter_id}) {"chapters_content.coursechapter_id": coursechapter_id})
if coursechapter: if coursechapter:
# verify course rights # verify course rights
await verify_rights(request, coursechapter["course_id"], current_user, "update") await verify_rights(request, coursechapter["course_id"], current_user, "update")
creationDate = coursechapter["creationDate"]
# get today's date coursechapter = CourseChapterInDB(coursechapter_id=coursechapter_id, creationDate=str(
datetime_object = datetime.now() datetime.now()), updateDate=str(datetime.now()), course_id=coursechapter["course_id"], **coursechapter_object.dict())
updated_coursechapter = CourseChapterInDB( courses.update_one({"chapters_content.coursechapter_id": coursechapter_id}, {
coursechapter_id=coursechapter_id, creationDate=creationDate, course_id=coursechapter["course_id"], updateDate=str(datetime_object), **coursechapter_object.dict()) "$set": {"chapters_content.$": coursechapter.dict()}})
await coursechapters.update_one({"coursechapter_id": coursechapter_id}, { return coursechapter
"$set": updated_coursechapter.dict()})
return CourseChapterInDB(**updated_coursechapter.dict())
else: else:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Coursechapter does not exist") status_code=status.HTTP_409_CONFLICT, detail="Coursechapter does not exist")
async def delete_coursechapter(request: Request,coursechapter_id: str, current_user: PublicUser): async def delete_coursechapter(request: Request, coursechapter_id: str, current_user: PublicUser):
coursechapters = request.app.db["coursechapters"]
courses = request.app.db["courses"] courses = request.app.db["courses"]
coursechapter = await coursechapters.find_one( course = await courses.find_one(
{"coursechapter_id": coursechapter_id}) {"chapters_content.coursechapter_id": coursechapter_id})
if coursechapter: if course:
# verify course rights # verify course rights
await verify_rights(request, coursechapter["course_id"], current_user, "delete") await verify_rights(request, course["course_id"], current_user, "delete")
isDeleted = await coursechapters.delete_one( courses.update_one({"chapters_content.coursechapter_id": coursechapter_id}, {
{"coursechapter_id": coursechapter_id}) "$pull": {"chapters_content": {"coursechapter_id": coursechapter_id}}})
# Remove coursechapter from course return {"message": "Coursechapter deleted"}
await courses.update_one({"course_id": coursechapter["course_id"]}, {
"$pull": {"chapters": coursechapter_id}})
if isDeleted:
return {"detail": "coursechapter deleted"}
else:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Unavailable database")
else: else:
raise HTTPException( raise HTTPException(
@ -145,43 +127,44 @@ async def delete_coursechapter(request: Request,coursechapter_id: str, current_
#################################################### ####################################################
async def get_coursechapters(request: Request,course_id: str, page: int = 1, limit: int = 10): async def get_coursechapters(request: Request, course_id: str, page: int = 1, limit: int = 10):
courses = request.app.db["coursechapters"] courses = request.app.db["courses"]
# TODO : Get only courses that user is admin/has roles of
# get all courses from database
all_coursechapters = courses.find({"course_id": course_id}).sort(
"name", 1).skip(10 * (page - 1)).limit(limit)
return [json.loads(json.dumps(coursechapter, default=str)) for coursechapter in await all_coursechapters.to_list(length=100)] course = await courses.find_one({"course_id": course_id})
if course:
course = Course(**course)
coursechapters = course.chapters_content
return coursechapters
async def get_coursechapters_meta(request: Request, course_id: str, current_user: PublicUser): async def get_coursechapters_meta(request: Request, course_id: str, current_user: PublicUser):
coursechapters = request.app.db["coursechapters"]
courses = request.app.db["courses"] courses = request.app.db["courses"]
activities = request.app.db["activities"] activities = request.app.db["activities"]
coursechapters = coursechapters.find( coursechapters = await courses.find_one({"course_id": course_id}, {"chapters": 1, "chapters_content": 1, "_id": 0})
{"course_id": course_id}).sort("name", 1)
course = await courses.find_one({"course_id": course_id}) coursechapters = coursechapters
course = Course(**course) # type: ignore
# activities # activities
coursechapter_activityIds_global = [] coursechapter_activityIds_global = []
# chapters # chapters
chapters = {} chapters = {}
for coursechapter in await coursechapters.to_list(length=100): if coursechapters["chapters_content"]:
coursechapter = CourseChapterInDB(**coursechapter) for coursechapter in coursechapters["chapters_content"]:
coursechapter_activityIds = []
for activity in coursechapter.activities: coursechapter = CourseChapterInDB(**coursechapter)
coursechapter_activityIds.append(activity) coursechapter_activityIds = []
coursechapter_activityIds_global.append(activity)
chapters[coursechapter.coursechapter_id] = { for activity in coursechapter.activities:
"id": coursechapter.coursechapter_id, "name": coursechapter.name, "activityIds": coursechapter_activityIds coursechapter_activityIds.append(activity)
} coursechapter_activityIds_global.append(activity)
chapters[coursechapter.coursechapter_id] = {
"id": coursechapter.coursechapter_id, "name": coursechapter.name, "activityIds": coursechapter_activityIds
}
# activities # activities
activities_list = {} activities_list = {}
@ -193,37 +176,41 @@ async def get_coursechapters_meta(request: Request, course_id: str, current_user
final = { final = {
"chapters": chapters, "chapters": chapters,
"chapterOrder": course.chapters, "chapterOrder": coursechapters["chapters"],
"activities": activities_list "activities": activities_list
} }
return final return final
async def update_coursechapters_meta(request: Request,course_id: str, coursechapters_metadata: CourseChapterMetaData, current_user: PublicUser): async def update_coursechapters_meta(request: Request, course_id: str, coursechapters_metadata: CourseChapterMetaData, current_user: PublicUser):
coursechapters = request.app.db["coursechapters"]
courses = request.app.db["courses"] courses = request.app.db["courses"]
# update chapters in course # update chapters in course
courseInDB = await courses.update_one({"course_id": course_id}, { courseInDB = await courses.update_one({"course_id": course_id}, {
"$set": {"chapters": coursechapters_metadata.chapterOrder}}) "$set": {"chapters": coursechapters_metadata.chapterOrder}})
if coursechapters_metadata.chapters is not None: if coursechapters_metadata.chapters is not None:
for coursechapter_id, chapter_metadata in coursechapters_metadata.chapters.items(): for coursechapter_id, chapter_metadata in coursechapters_metadata.chapters.items():
filter_query = {"coursechapter_id": coursechapter_id} filter_query = {
update_query = {"$set": {"activities": chapter_metadata["activityIds"]}} "chapters_content.coursechapter_id": coursechapter_id}
result = await coursechapters.update_one(filter_query, update_query) update_query = {
"$set": {
"chapters_content.$.activities": chapter_metadata["activityIds"]
}
}
result = await courses.update_one(filter_query, update_query)
if result.matched_count == 0: if result.matched_count == 0:
# handle error when no documents are matched by the filter query # handle error when no documents are matched by the filter query
print(f"No documents found for course chapter ID {coursechapter_id}") print(
f"No documents found for course chapter ID {coursechapter_id}")
return {"detail": "coursechapters metadata updated"} return {"detail": "coursechapters metadata updated"}
#### Security #################################################### #### Security ####################################################
async def verify_rights(request: Request,course_id: str, current_user: PublicUser, action: str): async def verify_rights(request: Request, course_id: str, current_user: PublicUser, action: str):
courses = request.app.db["courses"] courses = request.app.db["courses"]
course = await courses.find_one({"course_id": course_id}) course = await courses.find_one({"course_id": course_id})

View file

@ -1,5 +1,5 @@
import json import json
from typing import List from typing import List, Optional
from uuid import uuid4 from uuid import uuid4
from pydantic import BaseModel from pydantic import BaseModel
from src.services.courses.activities.activities import ActivityInDB from src.services.courses.activities.activities import ActivityInDB
@ -20,6 +20,7 @@ class Course(BaseModel):
thumbnail: str thumbnail: str
public: bool public: bool
chapters: List[str] chapters: List[str]
chapters_content: Optional[List]
org_id: str org_id: str
@ -71,7 +72,6 @@ async def get_course(request: Request, course_id: str, current_user: PublicUser)
async def get_course_meta(request: Request, course_id: str, current_user: PublicUser): async def get_course_meta(request: Request, course_id: str, current_user: PublicUser):
courses = request.app.db["courses"] courses = request.app.db["courses"]
coursechapters = request.app.db["coursechapters"]
trails = request.app.db["trails"] trails = request.app.db["trails"]
course = await courses.find_one({"course_id": course_id}) course = await courses.find_one({"course_id": course_id})
@ -84,25 +84,26 @@ async def get_course_meta(request: Request, course_id: str, current_user: Public
raise HTTPException( raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist") status_code=status.HTTP_409_CONFLICT, detail="Course does not exist")
coursechapters = coursechapters.find( coursechapters = await courses.find_one({"course_id": course_id}, {
{"course_id": course_id}).sort("name", 1) "chapters_content": 1, "_id": 0})
# activities # activities
coursechapter_activityIds_global = [] coursechapter_activityIds_global = []
# chapters # chapters
chapters = {} chapters = {}
for coursechapter in await coursechapters.to_list(length=100): if coursechapters["chapters_content"]:
coursechapter = CourseChapterInDB(**coursechapter) for coursechapter in coursechapters["chapters_content"]:
coursechapter_activityIds = [] coursechapter = CourseChapterInDB(**coursechapter)
coursechapter_activityIds = []
for activity in coursechapter.activities: for activity in coursechapter.activities:
coursechapter_activityIds.append(activity) coursechapter_activityIds.append(activity)
coursechapter_activityIds_global.append(activity) coursechapter_activityIds_global.append(activity)
chapters[coursechapter.coursechapter_id] = { chapters[coursechapter.coursechapter_id] = {
"id": coursechapter.coursechapter_id, "name": coursechapter.name, "activityIds": coursechapter_activityIds "id": coursechapter.coursechapter_id, "name": coursechapter.name, "activityIds": coursechapter_activityIds
} }
# activities # activities
activities_list = {} activities_list = {}
@ -144,16 +145,16 @@ async def create_course(request: Request, course_object: Course, org_id: str, cu
# TODO(fix) : the implementation here is clearly not the best one (this entire function) # TODO(fix) : the implementation here is clearly not the best one (this entire function)
course_object.org_id = org_id course_object.org_id = org_id
await verify_user_rights_with_roles(request, "create", current_user.user_id, course_id,org_id) course_object.chapters_content = []
await verify_user_rights_with_roles(request, "create", current_user.user_id, course_id, org_id)
if thumbnail_file: if thumbnail_file:
name_in_disk = f"{course_id}_thumbnail_{uuid4()}.{thumbnail_file.filename.split('.')[-1]}" name_in_disk = f"{course_id}_thumbnail_{uuid4()}.{thumbnail_file.filename.split('.')[-1]}"
await upload_thumbnail(thumbnail_file, name_in_disk) await upload_thumbnail(thumbnail_file, name_in_disk)
course_object.thumbnail = name_in_disk course_object.thumbnail = name_in_disk
course = CourseInDB(course_id=course_id, authors=[ course = CourseInDB(course_id=course_id, authors=[
current_user.user_id], creationDate=str(datetime.now()), updateDate=str(datetime.now()), **course_object.dict()) current_user.user_id], creationDate=str(datetime.now()), updateDate=str(datetime.now()), **course_object.dict())
course_in_db = await courses.insert_one(course.dict()) course_in_db = await courses.insert_one(course.dict())
@ -258,6 +259,7 @@ async def get_courses(request: Request, page: int = 1, limit: int = 10, org_id:
return [json.loads(json.dumps(course, default=str)) for course in await all_courses.to_list(length=100)] return [json.loads(json.dumps(course, default=str)) for course in await all_courses.to_list(length=100)]
async def get_courses_orgslug(request: Request, page: int = 1, limit: int = 10, org_slug: str | None = None): async def get_courses_orgslug(request: Request, page: int = 1, limit: int = 10, org_slug: str | None = None):
courses = request.app.db["courses"] courses = request.app.db["courses"]
orgs = request.app.db["organizations"] orgs = request.app.db["organizations"]
@ -269,7 +271,7 @@ async def get_courses_orgslug(request: Request, page: int = 1, limit: int = 10,
if not org: if not org:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_409_CONFLICT, detail=f"Organization does not exist") status_code=status.HTTP_409_CONFLICT, detail=f"Organization does not exist")
# get all courses from database # get all courses from database
all_courses = courses.find({"org_id": org['org_id']}).sort( all_courses = courses.find({"org_id": org['org_id']}).sort(
"name", 1).skip(10 * (page - 1)).limit(limit) "name", 1).skip(10 * (page - 1)).limit(limit)
@ -277,7 +279,6 @@ async def get_courses_orgslug(request: Request, page: int = 1, limit: int = 10,
return [json.loads(json.dumps(course, default=str)) for course in await all_courses.to_list(length=100)] return [json.loads(json.dumps(course, default=str)) for course in await all_courses.to_list(length=100)]
#### Security #################################################### #### Security ####################################################

View file

@ -181,10 +181,13 @@ async def add_course_to_trail(request: Request, user: PublicUser, orgslug: str,
trail = await trails.find_one( trail = await trails.find_one(
{"user_id": user.user_id, "org_id": org["org_id"]}) {"user_id": user.user_id, "org_id": org["org_id"]})
if not trail: if not trail:
raise HTTPException( trail = TrailInDB(trail_id=f"trail_{uuid4()}", user_id=user.user_id, org_id=org["org_id"], courses=[])
status_code=status.HTTP_404_NOT_FOUND, detail="Trail not found") trail = await trails.insert_one(trail.dict())
trail = await trails.find_one({"trail_id": trail.inserted_id})
# check if course is already present in the trail # check if course is already present in the trail
for element in trail["courses"]: for element in trail["courses"]: