diff --git a/front/app/orgs/[orgslug]/(withmenu)/collections/admin.tsx b/front/app/orgs/[orgslug]/(withmenu)/collections/admin.tsx index bb5b9c8d..0acef9ba 100644 --- a/front/app/orgs/[orgslug]/(withmenu)/collections/admin.tsx +++ b/front/app/orgs/[orgslug]/(withmenu)/collections/admin.tsx @@ -9,10 +9,7 @@ import React from 'react' const CollectionAdminEditsArea = (props: any) => { const org_roles_values = ["admin", "owner"]; const user_roles_values = ["role_admin"]; - console.log("props: ", props); - const auth: any = React.useContext(AuthContext); - console.log("auth: ", auth); // this is amazingly terrible code, but gotta release that MVP diff --git a/front/app/orgs/[orgslug]/(withmenu)/collections/page.tsx b/front/app/orgs/[orgslug]/(withmenu)/collections/page.tsx index 930b9b1c..03035fec 100644 --- a/front/app/orgs/[orgslug]/(withmenu)/collections/page.tsx +++ b/front/app/orgs/[orgslug]/(withmenu)/collections/page.tsx @@ -22,7 +22,6 @@ export async function generateMetadata( const access_token_cookie: any = cookieStore.get('access_token_cookie'); // Get Org context information const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] }); - return { title: `Collections — ${org.name}`, description: `Collections of courses from ${org.name}`, @@ -38,10 +37,9 @@ const CollectionsPage = async (params: any) => { const cookieStore = cookies(); const access_token_cookie: any = cookieStore.get('access_token_cookie'); const orgslug = params.params.orgslug; - const collections = await getOrgCollectionsWithAuthHeader(access_token_cookie ? access_token_cookie.value : null); - - - + const org = await getOrganizationContextInfo(orgslug, { revalidate: 1800, tags: ['organizations'] }); + const org_id = org.org_id; + const collections = await getOrgCollectionsWithAuthHeader(org_id, access_token_cookie ? access_token_cookie.value : null); return (
diff --git a/front/app/orgs/[orgslug]/(withmenu)/page.tsx b/front/app/orgs/[orgslug]/(withmenu)/page.tsx index f4d48efc..b51d1a7d 100644 --- a/front/app/orgs/[orgslug]/(withmenu)/page.tsx +++ b/front/app/orgs/[orgslug]/(withmenu)/page.tsx @@ -35,7 +35,8 @@ const OrgHomePage = async (params: any) => { const access_token_cookie: any = cookieStore.get('access_token_cookie'); const courses = await getOrgCoursesWithAuthHeader(orgslug, { revalidate: 0, tags: ['courses'] }, access_token_cookie ? access_token_cookie.value : null); - const collections = await getOrgCollectionsWithAuthHeader(access_token_cookie ? access_token_cookie.value : null); + const org = await getOrganizationContextInfo(orgslug, { revalidate: 1800, tags: ['organizations'] }); + const collections = await getOrgCollectionsWithAuthHeader(org.org_id, access_token_cookie ? access_token_cookie.value : null); // function to remove "course_" from the course_id diff --git a/front/services/courses/collections.ts b/front/services/courses/collections.ts index ad0bf20c..26ba6f92 100644 --- a/front/services/courses/collections.ts +++ b/front/services/courses/collections.ts @@ -19,7 +19,6 @@ export async function createCollection(collection: any) { return res; } - // Get a colletion by id export async function getCollectionById(collection_id: any) { const result: any = await fetch(`${getAPIUrl()}collections/${collection_id}`, { next: { revalidate: 10 } }); @@ -41,8 +40,8 @@ export async function getOrgCollections() { return res; } -export async function getOrgCollectionsWithAuthHeader(access_token: string) { - const result: any = await fetch(`${getAPIUrl()}collections/page/1/limit/10`, RequestBodyWithAuthHeader("GET", null, { revalidate: 3 }, access_token)); +export async function getOrgCollectionsWithAuthHeader(org_id: string, access_token: string) { + const result: any = await fetch(`${getAPIUrl()}collections/org_id/${org_id}/page/1/limit/10`, RequestBodyWithAuthHeader("GET", null, { revalidate: 3 }, access_token)); const res = await errorHandling(result); return res; } diff --git a/src/routers/courses/collections.py b/src/routers/courses/collections.py index 3dc39569..87dfe81c 100644 --- a/src/routers/courses/collections.py +++ b/src/routers/courses/collections.py @@ -1,14 +1,25 @@ from fastapi import APIRouter, Depends, Request from src.security.auth import get_current_user from src.services.users.users import PublicUser -from src.services.courses.collections import Collection, create_collection, get_collection, get_collections, update_collection, delete_collection +from src.services.courses.collections import ( + Collection, + create_collection, + get_collection, + get_collections, + update_collection, + delete_collection, +) router = APIRouter() @router.post("/") -async def api_create_collection(request: Request,collection_object: Collection, current_user: PublicUser = Depends(get_current_user)): +async def api_create_collection( + request: Request, + collection_object: Collection, + current_user: PublicUser = Depends(get_current_user), +): """ Create new Collection """ @@ -16,31 +27,52 @@ async def api_create_collection(request: Request,collection_object: Collection, @router.get("/{collection_id}") -async def api_get_collection(request: Request,collection_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_get_collection( + request: Request, + collection_id: str, + current_user: PublicUser = Depends(get_current_user), +): """ Get single collection by ID """ return await get_collection(request, collection_id, current_user) -@router.get("/page/{page}/limit/{limit}") -async def api_get_collections_by(request: Request,page: int, limit: int, current_user: PublicUser = Depends(get_current_user)): +@router.get("/org_id/{org_id}/page/{page}/limit/{limit}") +async def api_get_collections_by( + request: Request, + page: int, + limit: int, + org_id: str, + current_user: PublicUser = Depends(get_current_user), +): """ Get collections by page and limit """ - return await get_collections(request, page, limit) + return await get_collections(request, org_id, current_user, page, limit) @router.put("/{collection_id}") -async def api_update_collection(request: Request,collection_object: Collection, collection_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_update_collection( + request: Request, + collection_object: Collection, + collection_id: str, + current_user: PublicUser = Depends(get_current_user), +): """ Update collection by ID """ - return await update_collection(request, collection_object, collection_id, current_user) + return await update_collection( + request, collection_object, collection_id, current_user + ) @router.delete("/{collection_id}") -async def api_delete_collection(request: Request,collection_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_delete_collection( + request: Request, + collection_id: str, + current_user: PublicUser = Depends(get_current_user), +): """ Delete collection by ID """ diff --git a/src/services/courses/collections.py b/src/services/courses/collections.py index 8f482f1c..aabd502c 100644 --- a/src/services/courses/collections.py +++ b/src/services/courses/collections.py @@ -2,7 +2,7 @@ from typing import List from uuid import uuid4 from pydantic import BaseModel from src.services.users.users import PublicUser -from src.security.security import * +from src.security.security import verify_user_rights_with_roles from fastapi import HTTPException, status, Request #### Classes #################################################### @@ -25,7 +25,10 @@ class CollectionInDB(Collection): # CRUD #################################################### -async def get_collection(request: Request,collection_id: str, current_user: PublicUser): + +async def get_collection( + request: Request, collection_id: str, current_user: PublicUser +): collections = request.app.db["collections"] collection = await collections.find_one({"collection_id": collection_id}) @@ -35,7 +38,8 @@ async def get_collection(request: Request,collection_id: str, current_user: Publ if not collection: raise HTTPException( - status_code=status.HTTP_409_CONFLICT, detail="Collection does not exist") + status_code=status.HTTP_409_CONFLICT, detail="Collection does not exist" + ) collection = Collection(**collection) @@ -44,46 +48,56 @@ async def get_collection(request: Request,collection_id: str, current_user: Publ courseids = [course for course in collection.courses] collection.courses = [] - collection.courses = courses.find( - {"course_id": {"$in": courseids}}, {'_id': 0}) - - collection.courses = [course for course in await collection.courses.to_list(length=100)] + collection.courses = courses.find({"course_id": {"$in": courseids}}, {"_id": 0}) + collection.courses = [ + course for course in await collection.courses.to_list(length=100) + ] return collection -async def create_collection(request: Request,collection_object: Collection, current_user: PublicUser): +async def create_collection( + request: Request, collection_object: Collection, current_user: PublicUser +): collections = request.app.db["collections"] # find if collection already exists using name isCollectionNameAvailable = await collections.find_one( - {"name": collection_object.name}) + {"name": collection_object.name} + ) # TODO # await verify_collection_rights("*", current_user, "create") if isCollectionNameAvailable: raise HTTPException( - status_code=status.HTTP_409_CONFLICT, detail="Collection name already exists") + status_code=status.HTTP_409_CONFLICT, + detail="Collection name already exists", + ) # generate collection_id with uuid4 collection_id = str(f"collection_{uuid4()}") - collection = CollectionInDB( - collection_id=collection_id, **collection_object.dict()) + collection = CollectionInDB(collection_id=collection_id, **collection_object.dict()) collection_in_db = await collections.insert_one(collection.dict()) if not collection_in_db: raise HTTPException( - status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Unavailable database") + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail="Unavailable database", + ) return collection.dict() -async def update_collection(request: Request,collection_object: Collection, collection_id: str, current_user: PublicUser): - +async def update_collection( + request: Request, + collection_object: Collection, + collection_id: str, + current_user: PublicUser, +): # verify collection rights await verify_collection_rights(request, collection_id, current_user, "update") @@ -93,19 +107,23 @@ async def update_collection(request: Request,collection_object: Collection, coll if not collection: raise HTTPException( - status_code=status.HTTP_409_CONFLICT, detail="Collection does not exist") + status_code=status.HTTP_409_CONFLICT, detail="Collection does not exist" + ) updated_collection = CollectionInDB( - collection_id=collection_id, **collection_object.dict()) + collection_id=collection_id, **collection_object.dict() + ) - await collections.update_one({"collection_id": collection_id}, { - "$set": updated_collection.dict()}) + await collections.update_one( + {"collection_id": collection_id}, {"$set": updated_collection.dict()} + ) return Collection(**updated_collection.dict()) -async def delete_collection(request: Request,collection_id: str, current_user: PublicUser): - +async def delete_collection( + request: Request, collection_id: str, current_user: PublicUser +): await verify_collection_rights(request, collection_id, current_user, "delete") collections = request.app.db["collections"] @@ -114,7 +132,8 @@ async def delete_collection(request: Request,collection_id: str, current_user: P if not collection: raise HTTPException( - status_code=status.HTTP_409_CONFLICT, detail="Collection does not exist") + status_code=status.HTTP_409_CONFLICT, detail="Collection does not exist" + ) isDeleted = await collections.delete_one({"collection_id": collection_id}) @@ -122,20 +141,34 @@ async def delete_collection(request: Request,collection_id: str, current_user: P return {"detail": "collection deleted"} else: raise HTTPException( - status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Unavailable database") + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail="Unavailable database", + ) + #################################################### # Misc #################################################### -async def get_collections(request: Request,page: int = 1, limit: int = 10): - ## TODO : auth +async def get_collections( + request: Request, + org_id: str, + current_user: PublicUser, + page: int = 1, + limit: int = 10, +): collections = request.app.db["collections"] # get all collections from database without ObjectId - all_collections = collections.find({}).sort( - "name", 1).skip(10 * (page - 1)).limit(limit) + all_collections = ( + collections.find({"org_id": org_id}) + .sort("name", 1) + .skip(10 * (page - 1)) + .limit(limit) + ) + + await verify_collection_rights(request, "*", current_user, "read") # create list of collections and include courses in each collection collections_list = [] @@ -148,30 +181,42 @@ async def get_collections(request: Request,page: int = 1, limit: int = 10): courses = request.app.db["courses"] collection.courses = [] collection.courses = courses.find( - {"course_id": {"$in": collection_courses}}, {'_id': 0}) + {"course_id": {"$in": collection_courses}}, {"_id": 0} + ) - collection.courses = [course for course in await collection.courses.to_list(length=100)] + collection.courses = [ + course for course in await collection.courses.to_list(length=100) + ] return collections_list + #### Security #################################################### -async def verify_collection_rights(request: Request,collection_id: str, current_user: PublicUser, action: str): +async def verify_collection_rights( + request: Request, collection_id: str, current_user: PublicUser, action: str +): collections = request.app.db["collections"] collection = await collections.find_one({"collection_id": collection_id}) if not collection and action != "create": raise HTTPException( - status_code=status.HTTP_409_CONFLICT, detail="Collection does not exist") + status_code=status.HTTP_409_CONFLICT, detail="Collection does not exist" + ) - hasRoleRights = await verify_user_rights_with_roles(request, action, current_user.user_id, collection_id, collection["org_id"]) + hasRoleRights = await verify_user_rights_with_roles( + request, action, current_user.user_id, collection_id, collection["org_id"] + ) if not hasRoleRights: raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, detail="You do not have rights to this Collection") + status_code=status.HTTP_403_FORBIDDEN, + detail="You do not have rights to this Collection", + ) return True + #### Security ####################################################