feat: init activity endpoints and backend

This commit is contained in:
swve 2023-01-19 22:24:51 +01:00
parent 2c782c7af8
commit a21ccb3626
4 changed files with 151 additions and 4 deletions

View file

@ -1,12 +1,12 @@
from fastapi import APIRouter 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 from src.routers.courses import chapters, collections, courses,lectures
global_router = APIRouter(prefix="/api") global_router = APIRouter(prefix="/api")
# API Routes # API Routes
global_router.include_router(users.router, prefix="/users", tags=["users"]) global_router.include_router(users.router, prefix="/users", tags=["users"])
global_router.include_router(auth.router, prefix="/auth", tags=["auth"]) global_router.include_router(auth.router, prefix="/auth", tags=["auth"])
global_router.include_router(houses.router, prefix="/houses", tags=["houses"]) 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(chapters.router, prefix="/chapters", tags=["chapters"])
global_router.include_router(lectures.router, prefix="/lectures", tags=["lectures"]) global_router.include_router(lectures.router, prefix="/lectures", tags=["lectures"])
global_router.include_router(collections.router, prefix="/collections", tags=["collections"]) global_router.include_router(collections.router, prefix="/collections", tags=["collections"])
global_router.include_router(activity.router, prefix="/activity", tags=["activity"])

38
src/routers/activity.py Normal file
View file

@ -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)

108
src/services/activity.py Normal file
View file

@ -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

View file

@ -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): async def get_orgs_by_user(request: Request, user_id: str, page: int = 1, limit: int = 10):
orgs = request.app.db["organizations"] orgs = request.app.db["organizations"]
print(user_id)
# find all orgs where user_id is in owners or admins arrays # find all orgs where user_id is in owners or admins arrays
all_orgs = orgs.find({"$or": [{"owners": user_id}, {"admins": user_id}]}).sort( all_orgs = orgs.find({"$or": [{"owners": user_id}, {"admins": user_id}]}).sort(
"name", 1).skip(10 * (page - 1)).limit(limit) "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") status_code=status.HTTP_409_CONFLICT, detail="Organization does not exist")
isOwner = current_user.user_id in org["owners"] 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: if not hasRoleRights and not isOwner:
raise HTTPException( raise HTTPException(