diff --git a/src/main.py b/src/main.py index 4d189a38..6a41e764 100644 --- a/src/main.py +++ b/src/main.py @@ -1,12 +1,12 @@ from fastapi import APIRouter -from src.routers import users, auth, houses, orgs, roles, files +from src.routers import activity, users, auth, houses, orgs, roles, files from src.routers.courses import chapters, collections, courses,lectures global_router = APIRouter(prefix="/api") -# API Routes +# API Routes global_router.include_router(users.router, prefix="/users", tags=["users"]) global_router.include_router(auth.router, prefix="/auth", tags=["auth"]) global_router.include_router(houses.router, prefix="/houses", tags=["houses"]) @@ -17,4 +17,6 @@ global_router.include_router(courses.router, prefix="/courses", tags=["courses"] global_router.include_router(chapters.router, prefix="/chapters", tags=["chapters"]) global_router.include_router(lectures.router, prefix="/lectures", tags=["lectures"]) global_router.include_router(collections.router, prefix="/collections", tags=["collections"]) +global_router.include_router(activity.router, prefix="/activity", tags=["activity"]) + diff --git a/src/routers/activity.py b/src/routers/activity.py new file mode 100644 index 00000000..2ccc2362 --- /dev/null +++ b/src/routers/activity.py @@ -0,0 +1,38 @@ +from fastapi import APIRouter, Depends, Request +from src.dependencies.auth import get_current_user +from src.services.activity import Activity, add_chapter_to_activity, close_activity, create_activity, get_user_activities + + +router = APIRouter() + + +@router.post("/") +async def api_start_activity(request: Request, activity_object: Activity, user=Depends(get_current_user)): + """ + Start activity + """ + return await create_activity(request, user, activity_object) + + +@router.get("{org_id}/activities") +async def api_get_activity_by_userid(request: Request, org_id: str, user=Depends(get_current_user)): + """ + Get a user activities + """ + return await get_user_activities(request, user, org_id) + + +@router.post("/{org_id}/add_chapter/{course_id}/{chapter_id}") +async def api_add_chapter_to_activity(request: Request, org_id: str, course_id: str, chapter_id: str, user=Depends(get_current_user)): + """ + Add chapter to activity + """ + return await add_chapter_to_activity(request, user, org_id, course_id, chapter_id) + + +@router.patch("{org_id}/close_activity/{activity_id}") +async def api_close_activity(request: Request, org_id: str, activity_id: str, user=Depends(get_current_user)): + """ + Close activity + """ + return await close_activity(request, user, org_id, activity_id) diff --git a/src/services/activity.py b/src/services/activity.py new file mode 100644 index 00000000..926b443e --- /dev/null +++ b/src/services/activity.py @@ -0,0 +1,108 @@ +from datetime import datetime +import json +from typing import List, Literal, Optional +from uuid import uuid4 +from fastapi import HTTPException, Request, status +from pydantic import BaseModel + +from src.services.users import PublicUser + +#### Classes #################################################### + + +class Activity(BaseModel): + course_id: str + status: Optional[Literal['ongoing', 'done', 'closed']] = 'ongoing' + masked: Optional[bool] = False + chapters_marked_complete: Optional[List[str]] + chapters_data: Optional[List[dict]] + + +class ActivityInDB(Activity): + activity_id: str = str(f"activity_{uuid4()}") + user_id: str + org_id: str + creationDate: str = datetime.now().isoformat() + updateDate: str = datetime.now().isoformat() + + +#### Classes #################################################### + + +async def create_activity(request: Request, user: PublicUser, activity_object: Activity): + activities = request.app.db["activities"] + + # find if the user has already started the course + isActivityAlreadyStarted = activities.find_one( + {"course_id": activity_object.course_id, "user_id": user.user_id}) + + if isActivityAlreadyStarted: + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, detail="Activity already started") + + # create activity + activity = ActivityInDB(**activity_object.dict(), + user_id=user.user_id, org_id=activity_object.course_id) + + activities.insert_one(activity.dict()) + + return activity + + +async def get_user_activities(request: Request, user: PublicUser, org_id: str): + activities = request.app.db["activities"] + + user_activities = activities.find( + {"user_id": user.user_id, "org_id": org_id}) + + if not user_activities: + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, detail="No activities found") + + return [json.loads(json.dumps(activity, default=str)) for activity in user_activities] + + +async def add_chapter_to_activity(request: Request, user: PublicUser, org_id: str, course_id: str, chapter_id: str): + activities = request.app.db["activities"] + + activity = activities.find_one( + {"course_id": course_id, + "user_id": user.user_id, + "org_id": org_id + }) + + if not activity: + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, detail="Activity not found") + + if chapter_id in activity['chapters_marked_complete']: + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, detail="Chapter already marked complete") + + activity['chapters_marked_complete'].append(chapter_id) + + activities.update_one( + {"activity_id": activity['activity_id']}, {"$set": activity}) + + # send 200 custom message + return {"message": "Chapter added to activity"} + + +async def close_activity(request: Request, user: PublicUser, org_id: str, activity_id: str): + activities = request.app.db["activities"] + + activity = activities.find_one( + {"activity_id": activity_id, "user_id": user.user_id, "org_id": org_id}) + + if not activity: + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, detail="Activity not found") + + activity['status'] = 'closed' + + activities.update_one( + {"activity_id": activity['activity_id']}, {"$set": activity}) + + activity = ActivityInDB(**activity) + + return activity diff --git a/src/services/orgs.py b/src/services/orgs.py index 4c16e15a..fe07f291 100644 --- a/src/services/orgs.py +++ b/src/services/orgs.py @@ -135,7 +135,6 @@ async def delete_org(request: Request, org_id: str, current_user: PublicUser): async def get_orgs_by_user(request: Request, user_id: str, page: int = 1, limit: int = 10): orgs = request.app.db["organizations"] - print(user_id) # find all orgs where user_id is in owners or admins arrays all_orgs = orgs.find({"$or": [{"owners": user_id}, {"admins": user_id}]}).sort( "name", 1).skip(10 * (page - 1)).limit(limit) @@ -155,7 +154,7 @@ async def verify_org_rights(request: Request, org_id: str, current_user: Public status_code=status.HTTP_409_CONFLICT, detail="Organization does not exist") isOwner = current_user.user_id in org["owners"] - hasRoleRights = await verify_user_rights_with_roles(action, current_user.user_id, org_id) + hasRoleRights = await verify_user_rights_with_roles(request, action, current_user.user_id, org_id) if not hasRoleRights and not isOwner: raise HTTPException(