diff --git a/app.py b/app.py index d2fb50fb..43b3662e 100644 --- a/app.py +++ b/app.py @@ -1,6 +1,5 @@ import logging -from urllib.request import Request -from fastapi import FastAPI +from fastapi import FastAPI, Request from src.main import global_router from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse @@ -43,7 +42,7 @@ def startup_event(): # Database Connection logging.info("Connecting to database...") try: - app.mongodb_client = pymongo.MongoClient("mongodb://localhost:27017/") # type: ignore + app.mongodb_client = pymongo.MongoClient("mongodb://learnhouse:learnhouse@mongo:27017/") # type: ignore app.db = app.mongodb_client["learnhouse"] # type: ignore logging.info("Connected to database!") except Exception as e: @@ -55,7 +54,6 @@ def shutdown_event(): app.mongodb_client.close() # type: ignore logging.info("LearnHouse has been shut down.") - # JWT Exception Handler @app.exception_handler(AuthJWTException) def authjwt_exception_handler(request: Request, exc: AuthJWTException): @@ -74,7 +72,7 @@ async def root(): @app.get("/initial_data") -async def initial_data(): +async def initial_data(request: Request): - await create_initial_data() + await create_initial_data(request) return {"Message": "Initial data created 🤖"} diff --git a/src/core/events/__init__.py b/src/core/events/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/dependencies/auth.py b/src/dependencies/auth.py index cae1b1be..b4f33a62 100644 --- a/src/dependencies/auth.py +++ b/src/dependencies/auth.py @@ -44,8 +44,8 @@ class TokenData(BaseModel): #### Classes #################################################### -async def authenticate_user(email: str, password: str): - user = await security_get_user(email) +async def authenticate_user(request: Request,email: str, password: str): + user = await security_get_user(request, email) if not user: return False if not await security_verify_password(password, user.password): @@ -63,28 +63,10 @@ def create_access_token(data: dict, expires_delta: timedelta | None = None): encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt -# DEPRECATED -async def get_current_user_old(token: str = Depends(oauth2_scheme)): - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - headers={"WWW-Authenticate": "Bearer"}, - ) - try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - username: str = payload.get("sub") # type: ignore - if username is None: - raise credentials_exception - token_data = TokenData(username=username) - except JWTError: - raise credentials_exception - user = await security_get_user(email=token_data.username) # type: ignore - if user is None: - raise credentials_exception - return PublicUser(**user.dict()) -async def get_current_user(Authorize: AuthJWT = Depends()): + +async def get_current_user(request: Request, Authorize: AuthJWT = Depends()): credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", @@ -97,7 +79,7 @@ async def get_current_user(Authorize: AuthJWT = Depends()): token_data = TokenData(username=username) # type: ignore except JWTError: raise credentials_exception - user = await security_get_user(email=token_data.username) # type: ignore # treated as an email + user = await security_get_user(request, email=token_data.username) # type: ignore # treated as an email if user is None: raise credentials_exception return PublicUser(**user.dict()) diff --git a/src/routers/auth.py b/src/routers/auth.py index 691d5c97..d08ef3ff 100644 --- a/src/routers/auth.py +++ b/src/routers/auth.py @@ -1,5 +1,5 @@ from urllib.request import Request -from fastapi import Depends, APIRouter, HTTPException, status +from fastapi import Depends, APIRouter, HTTPException, status, Request from fastapi.security import OAuth2PasswordRequestForm from src.dependencies.auth import * from src.services.users import * @@ -11,11 +11,11 @@ router = APIRouter() # DEPRECATED @router.post("/token", response_model=Token) -async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()): +async def login_for_access_token(request: Request, form_data: OAuth2PasswordRequestForm = Depends()): """ OAuth2 compatible token login, get access token for future requests """ - user = await authenticate_user(form_data.username, form_data.password) + user = await authenticate_user(request, form_data.username, form_data.password) if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -47,8 +47,8 @@ def refresh(Authorize: AuthJWT = Depends()): return {"access_token": new_access_token} @router.post('/login') -async def login(Authorize: AuthJWT = Depends(), form_data: OAuth2PasswordRequestForm = Depends()): - user = await authenticate_user(form_data.username, form_data.password) +async def login(request: Request,Authorize: AuthJWT = Depends(), form_data: OAuth2PasswordRequestForm = Depends()): + user = await authenticate_user(request, form_data.username, form_data.password) if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, diff --git a/src/routers/courses/chapters.py b/src/routers/courses/chapters.py index 8a3beda9..a00b7b83 100644 --- a/src/routers/courses/chapters.py +++ b/src/routers/courses/chapters.py @@ -8,57 +8,57 @@ router = APIRouter() @router.post("/") -async def api_create_coursechapter(coursechapter_object: CourseChapter, course_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_create_coursechapter(request: Request,coursechapter_object: CourseChapter, course_id: str, current_user: PublicUser = Depends(get_current_user)): """ Create new CourseChapter """ - return await create_coursechapter(coursechapter_object, course_id, current_user) + return await create_coursechapter(request, coursechapter_object, course_id, current_user) @router.get("/{coursechapter_id}") -async def api_get_coursechapter(coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_get_coursechapter(request: Request,coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)): """ Get single CourseChapter by coursechapter_id """ - return await get_coursechapter(coursechapter_id, current_user=current_user) + return await get_coursechapter(request, coursechapter_id, current_user=current_user) @router.get("/meta/{course_id}") -async def api_get_coursechapter_meta(course_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_get_coursechapter_meta(request: Request,course_id: str, current_user: PublicUser = Depends(get_current_user)): """ Get coursechapter metadata """ - return await get_coursechapters_meta(course_id, current_user=current_user) + return await get_coursechapters_meta(request, course_id, current_user=current_user) @router.put("/meta/{course_id}") -async def api_update_coursechapter_meta(course_id: str, coursechapters_metadata: CourseChapterMetaData, current_user: PublicUser = Depends(get_current_user)): +async def api_update_coursechapter_meta(request: Request,course_id: str, coursechapters_metadata: CourseChapterMetaData, current_user: PublicUser = Depends(get_current_user)): """ Update coursechapter metadata """ - return await update_coursechapters_meta(course_id, coursechapters_metadata, current_user=current_user) + return await update_coursechapters_meta(request, course_id, coursechapters_metadata, current_user=current_user) @router.get("/{course_id}/page/{page}/limit/{limit}") -async def api_get_coursechapter_by(course_id: str, page: int, limit: int): +async def api_get_coursechapter_by(request: Request,course_id: str, page: int, limit: int): """ Get CourseChapters by page and limit """ - return await get_coursechapters(course_id, page, limit) + return await get_coursechapters(request, course_id, page, limit) @router.put("/{coursechapter_id}") -async def api_update_coursechapter(coursechapter_object: CourseChapter, coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_update_coursechapter(request: Request,coursechapter_object: CourseChapter, coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)): """ Update CourseChapters by course_id """ - return await update_coursechapter(coursechapter_object, coursechapter_id, current_user) + return await update_coursechapter(request, coursechapter_object, coursechapter_id, current_user) @router.delete("/{coursechapter_id}") -async def api_delete_coursechapter(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)): """ Delete CourseChapters by ID """ - return await delete_coursechapter(coursechapter_id, current_user) + return await delete_coursechapter(request,coursechapter_id, current_user) diff --git a/src/routers/courses/collections.py b/src/routers/courses/collections.py index e2ce3dc5..284b7cad 100644 --- a/src/routers/courses/collections.py +++ b/src/routers/courses/collections.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Depends +from fastapi import APIRouter, Depends, Request from src.dependencies.auth import get_current_user from src.services.users import PublicUser, User from src.services.courses.collections import Collection, create_collection, get_collection, get_collections, update_collection, delete_collection @@ -8,41 +8,41 @@ router = APIRouter() @router.post("/") -async def api_create_collection(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 """ - return await create_collection(collection_object, current_user) + return await create_collection(request, collection_object, current_user) @router.get("/{collection_id}") -async def api_get_collection(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(collection_id, current_user) + return await get_collection(request, collection_id, current_user) @router.get("/page/{page}/limit/{limit}") -async def api_get_collections_by(page: int, limit: int, current_user: PublicUser = Depends(get_current_user)): +async def api_get_collections_by(request: Request,page: int, limit: int, current_user: PublicUser = Depends(get_current_user)): """ Get collections by page and limit """ - return await get_collections(page, limit) + return await get_collections(request, page, limit) @router.put("/{collection_id}") -async def api_update_collection(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(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(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 """ - return await delete_collection(collection_id, current_user) + return await delete_collection(request, collection_id, current_user) diff --git a/src/routers/courses/courses.py b/src/routers/courses/courses.py index cba46fbf..b3ddab1b 100644 --- a/src/routers/courses/courses.py +++ b/src/routers/courses/courses.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Depends, UploadFile, Form +from fastapi import APIRouter, Depends, UploadFile, Form, Request from src.dependencies.auth import get_current_user from src.services.courses.courses import Course, create_course, get_course, get_course_meta, get_courses, update_course, delete_course, update_course_thumbnail @@ -9,59 +9,59 @@ router = APIRouter() @router.post("/") -async def api_create_course(org_id: str, name: str = Form(), mini_description: str = Form(), description: str = Form(), public: bool = Form(), current_user: PublicUser = Depends(get_current_user), thumbnail: UploadFile | None = None): +async def api_create_course(request: Request,org_id: str, name: str = Form(), mini_description: str = Form(), description: str = Form(), public: bool = Form(), current_user: PublicUser = Depends(get_current_user), thumbnail: UploadFile | None = None): """ Create new Course """ course = Course(name=name, mini_description=mini_description, description=description, org_id=org_id, public=public, thumbnail="", chapters=[], learnings=[]) - return await create_course(course, org_id, current_user, thumbnail) + return await create_course(request, course, org_id, current_user, thumbnail) @router.put("/thumbnail/{course_id}") -async def api_create_course_thumbnail(course_id: str, thumbnail: UploadFile | None = None, current_user: PublicUser = Depends(get_current_user)): +async def api_create_course_thumbnail(request: Request,course_id: str, thumbnail: UploadFile | None = None, current_user: PublicUser = Depends(get_current_user)): """ Update new Course Thumbnail """ - return await update_course_thumbnail(course_id, current_user, thumbnail) + return await update_course_thumbnail(request, course_id, current_user, thumbnail) @router.get("/{course_id}") -async def api_get_course(course_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_get_course(request: Request,course_id: str, current_user: PublicUser = Depends(get_current_user)): """ Get single Course by course_id """ - return await get_course(course_id, current_user=current_user) + return await get_course(request, course_id, current_user=current_user) @router.get("/meta/{course_id}") -async def api_get_course_meta(course_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_get_course_meta(request: Request,course_id: str, current_user: PublicUser = Depends(get_current_user)): """ Get single Course Metadata (chapters, lectures) by course_id """ - return await get_course_meta(course_id, current_user=current_user) + return await get_course_meta(request, course_id, current_user=current_user) @router.get("/{org_id}/page/{page}/limit/{limit}") -async def api_get_course_by(page: int, limit: int, org_id: str): +async def api_get_course_by(request: Request,page: int, limit: int, org_id: str): """ Get houses by page and limit """ - return await get_courses(page, limit, org_id) + return await get_courses(request,page, limit, org_id) @router.put("/{course_id}") -async def api_update_course(course_object: Course, course_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_update_course(request: Request,course_object: Course, course_id: str, current_user: PublicUser = Depends(get_current_user)): """ Update Course by course_id """ - return await update_course(course_object, course_id, current_user) + return await update_course(request,course_object, course_id, current_user) @router.delete("/{course_id}") -async def api_delete_course(course_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_delete_course(request: Request,course_id: str, current_user: PublicUser = Depends(get_current_user)): """ Delete Course by ID """ - return await delete_course(course_id, current_user) + return await delete_course(request, course_id, current_user) diff --git a/src/routers/courses/lectures.py b/src/routers/courses/lectures.py index d0321e00..bf26a8e9 100644 --- a/src/routers/courses/lectures.py +++ b/src/routers/courses/lectures.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Depends, UploadFile, Form +from fastapi import APIRouter, Depends, UploadFile, Form, Request from src.services.courses.lectures.lectures import * from src.dependencies.auth import get_current_user from src.services.courses.lectures.video import create_video_lecture @@ -7,50 +7,48 @@ router = APIRouter() @router.post("/") -async def api_create_lecture(lecture_object: Lecture, coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_create_lecture(request: Request,lecture_object: Lecture, coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)): """ Create new lecture """ - return await create_lecture(lecture_object, coursechapter_id, current_user) + return await create_lecture(request,lecture_object, coursechapter_id, current_user) @router.get("/{lecture_id}") -async def api_get_lecture(lecture_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_get_lecture(request: Request,lecture_id: str, current_user: PublicUser = Depends(get_current_user)): """ Get single lecture by lecture_id """ - return await get_lecture(lecture_id, current_user=current_user) + return await get_lecture(request, lecture_id, current_user=current_user) @router.get("/coursechapter/{coursechapter_id}") -async def api_get_lectures(coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_get_lectures(request: Request,coursechapter_id: str, current_user: PublicUser = Depends(get_current_user)): """ Get CourseChapter lectures """ - return await get_lectures(coursechapter_id, current_user) + return await get_lectures(request,coursechapter_id, current_user) @router.put("/{lecture_id}") -async def api_update_lecture(lecture_object: Lecture, lecture_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_update_lecture(request: Request,lecture_object: Lecture, lecture_id: str, current_user: PublicUser = Depends(get_current_user)): """ Update lecture by lecture_id """ - return await update_lecture(lecture_object, lecture_id, current_user) + return await update_lecture(request,lecture_object, lecture_id, current_user) @router.delete("/{lecture_id}") -async def api_delete_lecture(lecture_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_delete_lecture(request: Request,lecture_id: str, current_user: PublicUser = Depends(get_current_user)): """ Delete lecture by lecture_id """ - return await delete_lecture(lecture_id, current_user) - -# Video lecture - + return await delete_lecture(request,lecture_id, current_user) +# Video play @router.post("/video") -async def api_create_video_lecture(name: str = Form(), coursechapter_id: str = Form(), current_user: PublicUser = Depends(get_current_user), video_file: UploadFile | None = None): +async def api_create_video_lecture(request: Request,name: str = Form(), coursechapter_id: str = Form(), current_user: PublicUser = Depends(get_current_user), video_file: UploadFile | None = None): """ Create new lecture """ - return await create_video_lecture(name, coursechapter_id, current_user, video_file) + return await create_video_lecture(request,name, coursechapter_id, current_user, video_file) diff --git a/src/routers/files.py b/src/routers/files.py index bfc82d61..d2cfb89d 100644 --- a/src/routers/files.py +++ b/src/routers/files.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Depends, UploadFile, Form +from fastapi import APIRouter, Depends, UploadFile, Form, Request from src.dependencies.auth import get_current_user from fastapi import HTTPException, status, UploadFile @@ -10,32 +10,32 @@ router = APIRouter() @router.post("/picture") -async def api_create_picture_file(file_object: UploadFile, lecture_id: str = Form(), current_user: PublicUser = Depends(get_current_user)): +async def api_create_picture_file(request: Request,file_object: UploadFile, lecture_id: str = Form(), current_user: PublicUser = Depends(get_current_user)): """ Create new picture file """ - return await create_picture_file(file_object, lecture_id) + return await create_picture_file(request,file_object, lecture_id) @router.post("/video") -async def api_create_video_file(file_object: UploadFile,lecture_id: str = Form(), current_user: PublicUser = Depends(get_current_user)): +async def api_create_video_file(request: Request,file_object: UploadFile,lecture_id: str = Form(), current_user: PublicUser = Depends(get_current_user)): """ Create new video file """ - return await create_video_file(file_object, lecture_id) + return await create_video_file(request, file_object, lecture_id) @router.get("/picture") -async def api_get_picture_file(file_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_get_picture_file(request: Request,file_id: str, current_user: PublicUser = Depends(get_current_user)): """ Get picture file """ - return await get_picture_file(file_id, current_user) + return await get_picture_file(request, file_id, current_user) @router.get("/video") -async def api_get_video_file(file_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_get_video_file(request: Request,file_id: str, current_user: PublicUser = Depends(get_current_user)): """ Get video file """ - return await get_video_file(file_id, current_user) + return await get_video_file(request, file_id, current_user) diff --git a/src/routers/houses.py b/src/routers/houses.py index f1770ac8..164d5417 100644 --- a/src/routers/houses.py +++ b/src/routers/houses.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Depends +from fastapi import APIRouter, Depends, Request from src.dependencies.auth import get_current_user from src.services.houses import House, HouseInDB, create_house, get_house, get_houses, update_house, delete_house @@ -9,41 +9,41 @@ router = APIRouter() @router.post("/") -async def api_create_house(house_object: House, current_user: PublicUser = Depends(get_current_user)): +async def api_create_house(request: Request,house_object: House, current_user: PublicUser = Depends(get_current_user)): """ Create new house """ - return await create_house(house_object, current_user) + return await create_house(request, house_object, current_user) @router.get("/{house_id}") -async def api_get_house(house_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_get_house(request: Request,house_id: str, current_user: PublicUser = Depends(get_current_user)): """ Get single House by house_id """ - return await get_house(house_id, current_user=current_user) + return await get_house(request, house_id, current_user=current_user) @router.get("/page/{page}/limit/{limit}") -async def api_get_house_by(page: int, limit: int): +async def api_get_house_by(request: Request,page: int, limit: int): """ Get houses by page and limit """ - return await get_houses(page, limit) + return await get_houses(request, page, limit) @router.put("/{house_id}") -async def api_update_house(house_object: House, house_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_update_house(request: Request,house_object: House, house_id: str, current_user: PublicUser = Depends(get_current_user)): """ Update House by house_id """ - return await update_house(house_object, house_id, current_user) + return await update_house(request, house_object, house_id, current_user) @router.delete("/{house_id}") -async def api_delete_house(house_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_delete_house(request: Request,house_id: str, current_user: PublicUser = Depends(get_current_user)): """ Delete House by ID """ - return await delete_house(house_id, current_user) + return await delete_house(request, house_id, current_user) diff --git a/src/routers/roles.py b/src/routers/roles.py index 9a1496d9..5efebe00 100644 --- a/src/routers/roles.py +++ b/src/routers/roles.py @@ -1,6 +1,5 @@ -from fastapi import APIRouter, Depends +from fastapi import APIRouter, Depends, Request from src.dependencies.auth import get_current_user - from src.services.roles import Role, create_role, delete_role, get_role, get_roles, update_role from src.services.users import PublicUser, User @@ -9,41 +8,41 @@ router = APIRouter() @router.post("/") -async def api_create_role(role_object: Role, current_user: PublicUser = Depends(get_current_user)): +async def api_create_role(request: Request,role_object: Role, current_user: PublicUser = Depends(get_current_user)): """ Create new role """ - return await create_role(role_object, current_user) + return await create_role(request, role_object, current_user) @router.get("/{role_id}") -async def api_get_role(role_id: str): +async def api_get_role(request: Request,role_id: str): """ Get single role by role_id """ - return await get_role(role_id) + return await get_role(request, role_id) @router.get("/page/{page}/limit/{limit}") -async def api_get_role_by(page: int, limit: int): +async def api_get_role_by(request: Request,page: int, limit: int): """ Get roles by page and limit """ - return await get_roles(page, limit) + return await get_roles(request, page, limit) @router.put("/{role_id}") -async def api_update_role(role_object: Role, role_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_update_role(request: Request,role_object: Role, role_id: str, current_user: PublicUser = Depends(get_current_user)): """ Update role by role_id """ - return await update_role(role_object, role_id, current_user) + return await update_role(request, role_object, role_id, current_user) @router.delete("/{role_id}") -async def api_delete_role(role_id: str, current_user: PublicUser = Depends(get_current_user)): +async def api_delete_role(request: Request,role_id: str, current_user: PublicUser = Depends(get_current_user)): """ Delete role by ID """ - return await delete_role(role_id, current_user) + return await delete_role(request, role_id, current_user) diff --git a/src/routers/users.py b/src/routers/users.py index aea469a6..0ccc4818 100644 --- a/src/routers/users.py +++ b/src/routers/users.py @@ -9,13 +9,6 @@ from src.services.users import * router = APIRouter() -# DEPRECATED -@router.get("/me") -async def api_get_current_user_old(current_user: User = Depends(get_current_user)): - """ - Get current user - """ - return current_user.dict() @router.get("/profile") async def api_get_current_user(current_user: User = Depends(get_current_user)): @@ -25,49 +18,49 @@ async def api_get_current_user(current_user: User = Depends(get_current_user)): return current_user.dict() @router.get("/profile_metadata") -async def api_get_current_user_metadata(current_user: User = Depends(get_current_user)): +async def api_get_current_user_metadata(request: Request,current_user: User = Depends(get_current_user)): """ Get current user """ - return await get_profile_metadata(current_user.dict()) + return await get_profile_metadata(request , current_user.dict()) @router.get("/username/{username}") -async def api_get_user_by_username(username: str): +async def api_get_user_by_username(request: Request, username: str): """ Get single user by username """ - return await get_user(username) + return await get_user(request, username) @router.get("/user_id/{user_id}") -async def api_get_user_by_userid(user_id: str): +async def api_get_user_by_userid(request: Request,user_id: str): """ Get single user by user_id """ - return await get_user_by_userid(user_id) + return await get_user_by_userid(request, user_id) @router.post("/") -async def api_create_user(user_object: UserWithPassword): +async def api_create_user(request: Request,user_object: UserWithPassword): """ Create new user """ - return await create_user(user_object) + return await create_user(request, user_object) @router.delete("/user_id/{user_id}") -async def api_delete_user(user_id: str): +async def api_delete_user(request: Request, user_id: str): """ Delete user by ID """ - return await delete_user(user_id) + return await delete_user(request, user_id) @router.put("/user_id/{user_id}") -async def api_update_user(user_object: UserWithPassword, user_id: str): +async def api_update_user(request: Request, user_object: UserWithPassword, user_id: str): """ Update user by ID """ - return await update_user(user_id, user_object) + return await update_user(request, user_id, user_object) diff --git a/src/services/courses/chapters.py b/src/services/courses/chapters.py index a6b9ce9b..17391764 100644 --- a/src/services/courses/chapters.py +++ b/src/services/courses/chapters.py @@ -5,7 +5,6 @@ from uuid import uuid4 from pydantic import BaseModel from src.services.courses.courses import Course, CourseInDB from src.services.courses.lectures.lectures import Lecture, LectureInDB -from src.services.database import create_config_collection, check_database, create_database, learnhouseDB, learnhouseDB from src.services.security import verify_user_rights_with_roles from src.services.users import PublicUser from fastapi import HTTPException, status, Request, Response, BackgroundTasks, UploadFile, File @@ -37,15 +36,14 @@ class CourseChapterMetaData(BaseModel): #################################################### -async def create_coursechapter(coursechapter_object: CourseChapter, course_id: str, current_user: PublicUser): - await check_database() - coursechapters = learnhouseDB["coursechapters"] - courses = learnhouseDB["courses"] +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"] # generate coursechapter_id with uuid4 coursechapter_id = str(f"coursechapter_{uuid4()}") - hasRoleRights = await verify_user_rights_with_roles("create", current_user.user_id, coursechapter_id) + hasRoleRights = await verify_user_rights_with_roles(request, "create", current_user.user_id, coursechapter_id) if not hasRoleRights: raise HTTPException( @@ -65,16 +63,15 @@ async def create_coursechapter(coursechapter_object: CourseChapter, course_id: s return coursechapter.dict() -async def get_coursechapter(coursechapter_id: str, current_user: PublicUser): - await check_database() - coursechapters = learnhouseDB["coursechapters"] +async def get_coursechapter(request: Request,coursechapter_id: str, current_user: PublicUser): + coursechapters = request.app.db["coursechapters"] coursechapter = coursechapters.find_one( {"coursechapter_id": coursechapter_id}) if coursechapter: # verify course rights - await verify_rights(coursechapter["course_id"], current_user, "read") + await verify_rights(request, coursechapter["course_id"], current_user, "read") coursechapter = CourseChapter(**coursechapter) return coursechapter @@ -84,16 +81,15 @@ async def get_coursechapter(coursechapter_id: str, current_user: PublicUser): status_code=status.HTTP_409_CONFLICT, detail="CourseChapter does not exist") -async def update_coursechapter(coursechapter_object: CourseChapter, coursechapter_id: str, current_user: PublicUser): - await check_database() - coursechapters = learnhouseDB["coursechapters"] +async def update_coursechapter(request: Request,coursechapter_object: CourseChapter, coursechapter_id: str, current_user: PublicUser): + coursechapters = request.app.db["coursechapters"] coursechapter = coursechapters.find_one( {"coursechapter_id": coursechapter_id}) if coursechapter: # verify course rights - await verify_rights(coursechapter["course_id"], current_user, "update") + await verify_rights(request, coursechapter["course_id"], current_user, "update") creationDate = coursechapter["creationDate"] # get today's date @@ -112,18 +108,17 @@ async def update_coursechapter(coursechapter_object: CourseChapter, coursechapt status_code=status.HTTP_409_CONFLICT, detail="Coursechapter does not exist") -async def delete_coursechapter(coursechapter_id: str, current_user: PublicUser): - await check_database() +async def delete_coursechapter(request: Request,coursechapter_id: str, current_user: PublicUser): - coursechapters = learnhouseDB["coursechapters"] - courses = learnhouseDB["courses"] + coursechapters = request.app.db["coursechapters"] + courses = request.app.db["courses"] coursechapter = coursechapters.find_one( {"coursechapter_id": coursechapter_id}) if coursechapter: # verify course rights - await verify_rights(coursechapter["course_id"], current_user, "delete") + await verify_rights(request, coursechapter["course_id"], current_user, "delete") isDeleted = coursechapters.delete_one( {"coursechapter_id": coursechapter_id}) @@ -147,9 +142,8 @@ async def delete_coursechapter(coursechapter_id: str, current_user: PublicUser) #################################################### -async def get_coursechapters(course_id: str, page: int = 1, limit: int = 10): - await check_database() - courses = learnhouseDB["coursechapters"] +async def get_coursechapters(request: Request,course_id: str, page: int = 1, limit: int = 10): + courses = request.app.db["coursechapters"] # 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( @@ -158,11 +152,10 @@ async def get_coursechapters(course_id: str, page: int = 1, limit: int = 10): return [json.loads(json.dumps(coursechapter, default=str)) for coursechapter in all_coursechapters] -async def get_coursechapters_meta(course_id: str, current_user: PublicUser): - await check_database() - coursechapters = learnhouseDB["coursechapters"] - courses = learnhouseDB["courses"] - lectures = learnhouseDB["lectures"] +async def get_coursechapters_meta(request: Request,course_id: str, current_user: PublicUser): + coursechapters = request.app.db["coursechapters"] + courses = request.app.db["courses"] + lectures = request.app.db["lectures"] coursechapters = coursechapters.find( {"course_id": course_id}).sort("name", 1) @@ -204,10 +197,9 @@ async def get_coursechapters_meta(course_id: str, current_user: PublicUser): return final -async def update_coursechapters_meta(course_id: str, coursechapters_metadata: CourseChapterMetaData, current_user: PublicUser): - await check_database() - coursechapters = learnhouseDB["coursechapters"] - courses = learnhouseDB["courses"] +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"] # update chapters in course courseInDB = courses.update_one({"course_id": course_id}, { @@ -217,16 +209,15 @@ async def update_coursechapters_meta(course_id: str, coursechapters_metadata: Co # TODO : performance/optimization improvement for coursechapter in coursechapters_metadata.chapters.__dict__.items(): coursechapters.update_one({"coursechapter_id": coursechapter}, { - "$set": {"lectures": coursechapters_metadata.chapters[coursechapter]["lectureIds"]}}) + "$set": {"lectures": coursechapters_metadata.chapters[coursechapter]["lectureIds"]}}) # type: ignore return {"detail": "coursechapters metadata updated"} #### Security #################################################### -async def verify_rights(course_id: str, current_user: PublicUser, action: str): - await check_database() - courses = learnhouseDB["courses"] +async def verify_rights(request: Request,course_id: str, current_user: PublicUser, action: str): + courses = request.app.db["courses"] course = courses.find_one({"course_id": course_id}) @@ -234,7 +225,7 @@ async def verify_rights(course_id: str, current_user: PublicUser, action: str): raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail=f"Course does not exist") - hasRoleRights = await verify_user_rights_with_roles(action, current_user.user_id, course_id) + hasRoleRights = await verify_user_rights_with_roles(request, action, current_user.user_id, course_id) isAuthor = current_user.user_id in course["authors"] if not hasRoleRights and not isAuthor: diff --git a/src/services/courses/collections.py b/src/services/courses/collections.py index abb020f1..6c719819 100644 --- a/src/services/courses/collections.py +++ b/src/services/courses/collections.py @@ -3,7 +3,6 @@ from typing import List from uuid import uuid4 from pydantic import BaseModel from src.services.users import PublicUser, User -from src.services.database import create_config_collection, check_database, create_database, learnhouseDB, learnhouseDB from src.services.security import * from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks from datetime import datetime @@ -28,14 +27,13 @@ class CollectionInDB(Collection): # CRUD #################################################### -async def get_collection(collection_id: str, current_user: PublicUser): - await check_database() - collections = learnhouseDB["collections"] +async def get_collection(request: Request,collection_id: str, current_user: PublicUser): + collections = request.app.db["collections"] collection = collections.find_one({"collection_id": collection_id}) # verify collection rights - await verify_collection_rights(collection_id, current_user, "read") + await verify_collection_rights(request, collection_id, current_user, "read") if not collection: raise HTTPException( @@ -45,9 +43,8 @@ async def get_collection(collection_id: str, current_user: PublicUser): return collection -async def create_collection(collection_object: Collection, current_user: PublicUser): - await check_database() - collections = learnhouseDB["collections"] +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 = collections.find_one( @@ -75,13 +72,12 @@ async def create_collection(collection_object: Collection, current_user: PublicU return collection.dict() -async def update_collection(collection_object: Collection, collection_id: str, current_user: PublicUser): - await check_database() +async def update_collection(request: Request,collection_object: Collection, collection_id: str, current_user: PublicUser): # verify collection rights - await verify_collection_rights(collection_id, current_user, "update") + await verify_collection_rights(request, collection_id, current_user, "update") - collections = learnhouseDB["collections"] + collections = request.app.db["collections"] collection = collections.find_one({"collection_id": collection_id}) @@ -98,12 +94,11 @@ async def update_collection(collection_object: Collection, collection_id: str, c return Collection(**updated_collection.dict()) -async def delete_collection(collection_id: str, current_user: PublicUser): - await check_database() +async def delete_collection(request: Request,collection_id: str, current_user: PublicUser): - await verify_collection_rights(collection_id, current_user, "delete") + await verify_collection_rights(request, collection_id, current_user, "delete") - collections = learnhouseDB["collections"] + collections = request.app.db["collections"] collection = collections.find_one({"collection_id": collection_id}) @@ -124,10 +119,9 @@ async def delete_collection(collection_id: str, current_user: PublicUser): #################################################### -async def get_collections(page: int = 1, limit: int = 10): +async def get_collections(request: Request,page: int = 1, limit: int = 10): ## TODO : auth - await check_database() - collections = learnhouseDB["collections"] + collections = request.app.db["collections"] # get all collections from database without ObjectId all_collections = collections.find({}).sort( @@ -141,7 +135,7 @@ async def get_collections(page: int = 1, limit: int = 10): collection_courses = [course for course in collection.courses] # add courses to collection - courses = learnhouseDB["courses"] + courses = request.app.db["courses"] collection.courses = [] collection.courses = courses.find( {"course_id": {"$in": collection_courses}}, {'_id': 0}) @@ -153,9 +147,8 @@ async def get_collections(page: int = 1, limit: int = 10): #### Security #################################################### -async def verify_collection_rights(collection_id: str, current_user: PublicUser, action: str): - await check_database() - collections = learnhouseDB["collections"] +async def verify_collection_rights(request: Request,collection_id: str, current_user: PublicUser, action: str): + collections = request.app.db["collections"] collection = collections.find_one({"collection_id": collection_id}) @@ -163,7 +156,7 @@ async def verify_collection_rights(collection_id: str, current_user: PublicUser raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="Collection does not exist") - hasRoleRights = await verify_user_rights_with_roles(action, current_user.user_id, collection_id) + hasRoleRights = await verify_user_rights_with_roles(request, action, current_user.user_id, collection_id) if not hasRoleRights: raise HTTPException( diff --git a/src/services/courses/courses.py b/src/services/courses/courses.py index b4acb30a..c27ef657 100644 --- a/src/services/courses/courses.py +++ b/src/services/courses/courses.py @@ -5,7 +5,6 @@ from pydantic import BaseModel from src.services.courses.lectures.lectures import LectureInDB from src.services.courses.thumbnails import upload_thumbnail from src.services.users import PublicUser -from src.services.database import check_database, learnhouseDB from src.services.security import * from fastapi import HTTPException, status, UploadFile from datetime import datetime @@ -54,14 +53,13 @@ class CourseChapterInDB(CourseChapter): # CRUD #################################################### -async def get_course(course_id: str, current_user: PublicUser): - await check_database() - courses = learnhouseDB["courses"] +async def get_course(request: Request,course_id: str, current_user: PublicUser): + courses = request.app.db["courses"] course = courses.find_one({"course_id": course_id}) # verify course rights - await verify_rights(course_id, current_user, "read") + await verify_rights(request,course_id, current_user, "read") if not course: raise HTTPException( @@ -71,15 +69,14 @@ async def get_course(course_id: str, current_user: PublicUser): return course -async def get_course_meta(course_id: str, current_user: PublicUser): - await check_database() - courses = learnhouseDB["courses"] - coursechapters = learnhouseDB["coursechapters"] +async def get_course_meta(request: Request,course_id: str, current_user: PublicUser): + courses = request.app.db["courses"] + coursechapters = request.app.db["coursechapters"] course = courses.find_one({"course_id": course_id}) - lectures = learnhouseDB["lectures"] + lectures = request.app.db["lectures"] # verify course rights - await verify_rights(course_id, current_user, "read") + await verify_rights(request,course_id, current_user, "read") if not course: raise HTTPException( @@ -124,16 +121,15 @@ async def get_course_meta(course_id: str, current_user: PublicUser): } -async def create_course(course_object: Course, org_id: str, current_user: PublicUser, thumbnail_file: UploadFile | None = None): - await check_database() - courses = learnhouseDB["courses"] +async def create_course(request: Request,course_object: Course, org_id: str, current_user: PublicUser, thumbnail_file: UploadFile | None = None): + courses = request.app.db["courses"] # generate course_id with uuid4 course_id = str(f"course_{uuid4()}") # TODO(fix) : the implementation here is clearly not the best one (this entire function) course_object.org_id = org_id - hasRoleRights = await verify_user_rights_with_roles("create", current_user.user_id, course_id) + hasRoleRights = await verify_user_rights_with_roles(request, "create", current_user.user_id, course_id) if not hasRoleRights: raise HTTPException( @@ -156,13 +152,12 @@ async def create_course(course_object: Course, org_id: str, current_user: Public return course.dict() -async def update_course_thumbnail(course_id: str, current_user: PublicUser, thumbnail_file: UploadFile | None = None): - await check_database() +async def update_course_thumbnail(request: Request,course_id: str, current_user: PublicUser, thumbnail_file: UploadFile | None = None): # verify course rights - await verify_rights(course_id, current_user, "update") + await verify_rights(request, course_id, current_user, "update") - courses = learnhouseDB["courses"] + courses = request.app.db["courses"] course = courses.find_one({"course_id": course_id}) # TODO(fix) : the implementation here is clearly not the best one @@ -187,13 +182,12 @@ async def update_course_thumbnail(course_id: str, current_user: PublicUser, thum status_code=status.HTTP_409_CONFLICT, detail="Course does not exist") -async def update_course(course_object: Course, course_id: str, current_user: PublicUser): - await check_database() +async def update_course(request: Request,course_object: Course, course_id: str, current_user: PublicUser): # verify course rights - await verify_rights(course_id, current_user, "update") + await verify_rights(request, course_id, current_user, "update") - courses = learnhouseDB["courses"] + courses = request.app.db["courses"] course = courses.find_one({"course_id": course_id}) @@ -217,13 +211,12 @@ async def update_course(course_object: Course, course_id: str, current_user: Pub status_code=status.HTTP_409_CONFLICT, detail="Course does not exist") -async def delete_course(course_id: str, current_user: PublicUser): - await check_database() +async def delete_course(request: Request,course_id: str, current_user: PublicUser): # verify course rights - await verify_rights(course_id, current_user, "delete") + await verify_rights(request, course_id, current_user, "delete") - courses = learnhouseDB["courses"] + courses = request.app.db["courses"] course = courses.find_one({"course_id": course_id}) @@ -244,9 +237,8 @@ async def delete_course(course_id: str, current_user: PublicUser): #################################################### -async def get_courses(page: int = 1, limit: int = 10, org_id: str | None = None): - await check_database() - courses = learnhouseDB["courses"] +async def get_courses(request: Request,page: int = 1, limit: int = 10, org_id: str | None = None): + courses = request.app.db["courses"] # TODO : Get only courses that user is admin/has roles of # get all courses from database all_courses = courses.find({"org_id": org_id}).sort( @@ -258,9 +250,8 @@ async def get_courses(page: int = 1, limit: int = 10, org_id: str | None = None) #### Security #################################################### -async def verify_rights(course_id: str, current_user: PublicUser, action: str): - await check_database() - courses = learnhouseDB["courses"] +async def verify_rights(request: Request,course_id: str, current_user: PublicUser, action: str): + courses = request.app.db["courses"] course = courses.find_one({"course_id": course_id}) @@ -268,7 +259,7 @@ async def verify_rights(course_id: str, current_user: PublicUser, action: str): raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail=f"Course/CourseChapter does not exist") - hasRoleRights = await verify_user_rights_with_roles(action, current_user.user_id, course_id) + hasRoleRights = await verify_user_rights_with_roles(request, action, current_user.user_id, course_id) isAuthor = current_user.user_id in course["authors"] if not hasRoleRights and not isAuthor: diff --git a/src/services/courses/lectures/lectures.py b/src/services/courses/lectures/lectures.py index c3a542d6..ad43f8a8 100644 --- a/src/services/courses/lectures/lectures.py +++ b/src/services/courses/lectures/lectures.py @@ -1,5 +1,4 @@ from pydantic import BaseModel -from src.services.database import create_config_collection, check_database, create_database, learnhouseDB from src.services.security import verify_user_rights_with_roles from src.services.users import PublicUser, User from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks, UploadFile, File @@ -29,15 +28,14 @@ class LectureInDB(Lecture): #################################################### -async def create_lecture(lecture_object: Lecture, coursechapter_id: str, current_user: PublicUser): - await check_database() - lectures = learnhouseDB["lectures"] - coursechapters = learnhouseDB["coursechapters"] +async def create_lecture(request: Request,lecture_object: Lecture, coursechapter_id: str, current_user: PublicUser): + lectures = request.app.db["lectures"] + coursechapters = request.app.db["coursechapters"] # generate lecture_id lecture_id = str(f"lecture_{uuid4()}") - hasRoleRights = await verify_user_rights_with_roles("create", current_user.user_id, lecture_id) + hasRoleRights = await verify_user_rights_with_roles(request, "create", current_user.user_id, lecture_id) if not hasRoleRights: raise HTTPException( @@ -55,14 +53,13 @@ async def create_lecture(lecture_object: Lecture, coursechapter_id: str, current return lecture -async def get_lecture(lecture_id: str, current_user: PublicUser): - await check_database() - lectures = learnhouseDB["lectures"] +async def get_lecture(request: Request,lecture_id: str, current_user: PublicUser): + lectures = request.app.db["lectures"] lecture = lectures.find_one({"lecture_id": lecture_id}) # verify course rights - hasRoleRights = await verify_user_rights_with_roles("read", current_user.user_id, lecture_id) + hasRoleRights = await verify_user_rights_with_roles(request,"read", current_user.user_id, lecture_id) if not hasRoleRights: raise HTTPException( @@ -76,13 +73,12 @@ async def get_lecture(lecture_id: str, current_user: PublicUser): return lecture -async def update_lecture(lecture_object: Lecture, lecture_id: str, current_user: PublicUser): - await check_database() +async def update_lecture(request: Request,lecture_object: Lecture, lecture_id: str, current_user: PublicUser): # verify course rights - await verify_user_rights_with_roles("update", current_user.user_id, lecture_id) + await verify_user_rights_with_roles(request, "update", current_user.user_id, lecture_id) - lectures = learnhouseDB["lectures"] + lectures = request.app.db["lectures"] lecture = lectures.find_one({"lecture_id": lecture_id}) @@ -105,13 +101,12 @@ async def update_lecture(lecture_object: Lecture, lecture_id: str, current_user: status_code=status.HTTP_409_CONFLICT, detail="lecture does not exist") -async def delete_lecture(lecture_id: str, current_user: PublicUser): - await check_database() +async def delete_lecture(request: Request,lecture_id: str, current_user: PublicUser): # verify course rights - await verify_user_rights_with_roles("delete", current_user.user_id, lecture_id) + await verify_user_rights_with_roles(request,"delete", current_user.user_id, lecture_id) - lectures = learnhouseDB["lectures"] + lectures = request.app.db["lectures"] lecture = lectures.find_one({"lecture_id": lecture_id}) @@ -132,12 +127,11 @@ async def delete_lecture(lecture_id: str, current_user: PublicUser): #################################################### -async def get_lectures(coursechapter_id: str, current_user: PublicUser): - await check_database() - lectures = learnhouseDB["lectures"] +async def get_lectures(request: Request,coursechapter_id: str, current_user: PublicUser): + lectures = request.app.db["lectures"] # verify course rights - await verify_user_rights_with_roles("read", current_user.user_id, coursechapter_id) + await verify_user_rights_with_roles(request,"read", current_user.user_id, coursechapter_id) lectures = lectures.find({"coursechapter_id": coursechapter_id}) diff --git a/src/services/courses/lectures/video.py b/src/services/courses/lectures/video.py index 41a593a6..de1d9821 100644 --- a/src/services/courses/lectures/video.py +++ b/src/services/courses/lectures/video.py @@ -1,18 +1,16 @@ from pydantic import BaseModel -from src.services.database import check_database, learnhouseDB from src.services.security import verify_user_rights_with_roles from src.services.courses.lectures.uploads.videos import upload_video from src.services.users import PublicUser from src.services.courses.lectures.lectures import LectureInDB -from fastapi import HTTPException, status, UploadFile +from fastapi import HTTPException, status, UploadFile, Request from uuid import uuid4 from datetime import datetime -async def create_video_lecture(name: str, coursechapter_id: str, current_user: PublicUser, video_file: UploadFile | None = None): - await check_database() - lectures = learnhouseDB["lectures"] - coursechapters = learnhouseDB["coursechapters"] +async def create_video_lecture(request: Request,name: str, coursechapter_id: str, current_user: PublicUser, video_file: UploadFile | None = None): + lectures = request.app.db["lectures"] + coursechapters = request.app.db["coursechapters"] # generate lecture_id lecture_id = str(f"lecture_{uuid4()}") @@ -38,7 +36,7 @@ async def create_video_lecture(name: str, coursechapter_id: str, current_user: updateDate=str(datetime.now()), ) - hasRoleRights = await verify_user_rights_with_roles("create", current_user.user_id, lecture_id) + hasRoleRights = await verify_user_rights_with_roles(request,"create", current_user.user_id, lecture_id) if not hasRoleRights: raise HTTPException( diff --git a/src/services/database.py b/src/services/database.py index 4e92f092..e69de29b 100644 --- a/src/services/database.py +++ b/src/services/database.py @@ -1,27 +0,0 @@ -import pymongo - -# MongoDB -client = pymongo.MongoClient("mongodb://learnhouse:learnhouse@mongo:27017/") # type: ignore -learnhouseDB = client["learnhouse"] - - -async def create_database(): - learnhouseDB = client["learnhouse"] - - -async def check_database(): - # Check if database learnhouse exists - - if "learnhouse" in client.list_database_names(): - return True - else: - await create_database() - - -async def create_config_collection(): - # Create config collection if it doesn't exist - - learnhouseDB = client["learnhouse"] - config = learnhouseDB["config"] - config.insert_one({"name": "LearnHouse", "date": "2022"}) - return config.find_one() diff --git a/src/services/files/pictures.py b/src/services/files/pictures.py index a825101a..7bbf890b 100644 --- a/src/services/files/pictures.py +++ b/src/services/files/pictures.py @@ -1,7 +1,6 @@ from uuid import uuid4 from pydantic import BaseModel -from src.services.database import check_database, learnhouseDB, learnhouseDB -from fastapi import HTTPException, status, UploadFile +from fastapi import HTTPException, status, UploadFile, Request from fastapi.responses import StreamingResponse import os @@ -17,9 +16,8 @@ class PhotoFile(BaseModel): lecture_id: str -async def create_picture_file(picture_file: UploadFile, lecture_id: str): - await check_database() - photos = learnhouseDB["files"] +async def create_picture_file(request: Request,picture_file: UploadFile, lecture_id: str): + photos = request.app.db["files"] # generate file_id file_id = str(f"file_{uuid4()}") @@ -73,9 +71,8 @@ async def create_picture_file(picture_file: UploadFile, lecture_id: str): return uploadable_file -async def get_picture_object(file_id: str): - await check_database() - photos = learnhouseDB["files"] +async def get_picture_object(request: Request,file_id: str): + photos = request.app.db["files"] photo_file = photos.find_one({"file_id": file_id}) @@ -88,9 +85,8 @@ async def get_picture_object(file_id: str): status_code=status.HTTP_409_CONFLICT, detail="Photo file does not exist") -async def get_picture_file(file_id: str, current_user: PublicUser): - await check_database() - photos = learnhouseDB["files"] +async def get_picture_file(request: Request,file_id: str, current_user: PublicUser): + photos = request.app.db["files"] photo_file = photos.find_one({"file_id": file_id}) diff --git a/src/services/files/videos.py b/src/services/files/videos.py index dd84625d..dd194c1d 100644 --- a/src/services/files/videos.py +++ b/src/services/files/videos.py @@ -1,8 +1,7 @@ from uuid import uuid4 from pydantic import BaseModel import os -from src.services.database import check_database, learnhouseDB, learnhouseDB -from fastapi import HTTPException, status, UploadFile +from fastapi import HTTPException, status, UploadFile,Request from fastapi.responses import StreamingResponse from src.services.users import PublicUser @@ -17,9 +16,8 @@ class VideoFile(BaseModel): lecture_id: str -async def create_video_file(video_file: UploadFile, lecture_id: str): - await check_database() - files = learnhouseDB["files"] +async def create_video_file(request: Request,video_file: UploadFile, lecture_id: str): + files = request.app.db["files"] # generate file_id file_id = str(f"file_{uuid4()}") @@ -73,9 +71,8 @@ async def create_video_file(video_file: UploadFile, lecture_id: str): return uploadable_file -async def get_video_object(file_id: str, current_user: PublicUser): - await check_database() - photos = learnhouseDB["files"] +async def get_video_object(request: Request,file_id: str, current_user: PublicUser): + photos = request.app.db["files"] video_file = photos.find_one({"file_id": file_id}) @@ -88,9 +85,8 @@ async def get_video_object(file_id: str, current_user: PublicUser): status_code=status.HTTP_409_CONFLICT, detail="Photo file does not exist") -async def get_video_file(file_id: str, current_user: PublicUser): - await check_database() - photos = learnhouseDB["files"] +async def get_video_file(request: Request,file_id: str, current_user: PublicUser): + photos = request.app.db["files"] video_file = photos.find_one({"file_id": file_id}) diff --git a/src/services/houses.py b/src/services/houses.py index 9464dbb4..75ebd90d 100644 --- a/src/services/houses.py +++ b/src/services/houses.py @@ -3,7 +3,6 @@ from typing import List from uuid import uuid4 from pydantic import BaseModel from src.services.users import PublicUser, User -from src.services.database import check_database, create_database, learnhouseDB, learnhouseDB from src.services.security import * from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks from datetime import datetime @@ -28,14 +27,13 @@ class HouseInDB(House): # TODO : Add house photo upload and delete -async def get_house(house_id: str, current_user: PublicUser): - await check_database() - houses = learnhouseDB["houses"] +async def get_house(request: Request, house_id: str, current_user: PublicUser): + houses = request.app.db["houses"] house = houses.find_one({"house_id": house_id}) # verify house rights - await verify_house_rights(house_id, current_user, "read") + await verify_house_rights(request,house_id, current_user, "read") if not house: raise HTTPException( @@ -45,9 +43,8 @@ async def get_house(house_id: str, current_user: PublicUser): return house -async def create_house(house_object: House, current_user: PublicUser): - await check_database() - houses = learnhouseDB["houses"] +async def create_house(request: Request,house_object: House, current_user: PublicUser): + houses = request.app.db["houses"] # find if house already exists using name isHouseAvailable = houses.find_one({"name": house_object.name}) @@ -59,7 +56,7 @@ async def create_house(house_object: House, current_user: PublicUser): # generate house_id with uuid4 house_id = str(f"house_{uuid4()}") - hasRoleRights = await verify_user_rights_with_roles("create", current_user.user_id, house_id) + hasRoleRights = await verify_user_rights_with_roles(request, "create", current_user.user_id, house_id) if not hasRoleRights: raise HTTPException( @@ -78,13 +75,12 @@ async def create_house(house_object: House, current_user: PublicUser): return house.dict() -async def update_house(house_object: House, house_id: str, current_user: PublicUser): - await check_database() +async def update_house(request: Request,house_object: House, house_id: str, current_user: PublicUser): # verify house rights - await verify_house_rights(house_id, current_user, "update") + await verify_house_rights(request,house_id, current_user, "update") - houses = learnhouseDB["houses"] + houses = request.app.db["houses"] house = houses.find_one({"house_id": house_id}) @@ -107,13 +103,12 @@ async def update_house(house_object: House, house_id: str, current_user: PublicU -async def delete_house(house_id: str, current_user: PublicUser): - await check_database() +async def delete_house(request: Request,house_id: str, current_user: PublicUser): # verify house rights - await verify_house_rights(house_id, current_user, "delete") + await verify_house_rights(request,house_id, current_user, "delete") - houses = learnhouseDB["houses"] + houses = request.app.db["houses"] house = houses.find_one({"house_id": house_id}) @@ -130,9 +125,8 @@ async def delete_house(house_id: str, current_user: PublicUser): status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Unavailable database") -async def get_houses(page: int = 1, limit: int = 10): - await check_database() - houses = learnhouseDB["houses"] +async def get_houses(request: Request,page: int = 1, limit: int = 10): + houses = request.app.db["houses"] # TODO : Get only houses that user is admin/has roles of # get all houses from database all_houses = houses.find().sort("name", 1).skip(10 * (page - 1)).limit(limit) @@ -142,9 +136,8 @@ async def get_houses(page: int = 1, limit: int = 10): #### Security #################################################### -async def verify_house_rights(house_id: str, current_user: PublicUser, action: str): - await check_database() - houses = learnhouseDB["houses"] +async def verify_house_rights(request: Request,house_id: str, current_user: PublicUser, action: str): + houses = request.app.db["houses"] house = houses.find_one({"house_id": house_id}) @@ -152,7 +145,7 @@ async def verify_house_rights(house_id: str, current_user: PublicUser, action: s raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="House does not exist") - hasRoleRights = await verify_user_rights_with_roles(action, current_user.user_id, house_id) + hasRoleRights = await verify_user_rights_with_roles(request,action, current_user.user_id, house_id) isOwner = current_user.user_id in house["owners"] if not hasRoleRights and not isOwner: diff --git a/src/services/mocks/initial.py b/src/services/mocks/initial.py index 19940db0..ba8744b7 100644 --- a/src/services/mocks/initial.py +++ b/src/services/mocks/initial.py @@ -3,12 +3,12 @@ from datetime import datetime from fileinput import filename from pprint import pprint from uuid import uuid4 -from fastapi import File, UploadFile +from fastapi import File, UploadFile, Request from src.services.courses.chapters import CourseChapter, create_coursechapter from src.services.courses.lectures.lectures import Lecture, create_lecture from src.services.courses.thumbnails import upload_thumbnail from src.services.users import PublicUser, User, UserInDB, UserWithPassword -from src.services.database import learnhouseDB + from src.services.orgs import OrganizationInDB, Organization, create_org from src.services.roles import Permission, Elements, create_role from src.services.users import create_user @@ -17,7 +17,7 @@ from src.services.roles import Role from faker import Faker -async def create_initial_data(): +async def create_initial_data(request: Request): fake = Faker(['en_US']) fake_multilang = Faker( ['en_US', 'de_DE', 'ja_JP', 'es_ES', 'it_IT', 'pt_BR', 'ar_PS']) @@ -25,7 +25,7 @@ async def create_initial_data(): # Create users ######################################## - database_users = learnhouseDB["users"] + database_users = request.app.db["users"] database_users.delete_many({}) users = [] @@ -36,7 +36,7 @@ async def create_initial_data(): user_type="isOwner", ) - admin_user = await create_user(admin_user) + admin_user = await create_user(request, admin_user) for i in range(0, 20): user = UserWithPassword( @@ -49,10 +49,10 @@ async def create_initial_data(): users.append(user) for user in users: - await create_user(user) + await create_user(request, user) # find admin user - users = learnhouseDB["users"] + users = request.app.db["users"] admin_user = users.find_one({"username": "admin"}) if admin_user: @@ -64,7 +64,7 @@ async def create_initial_data(): # Create organizations ######################################## - database_orgs = learnhouseDB["organizations"] + database_orgs = request.app.db["organizations"] database_orgs.delete_many({}) organizations = [] @@ -79,12 +79,12 @@ async def create_initial_data(): slug=slug, ) organizations.append(org) - await create_org(org, current_user) + await create_org(request, org, current_user) # Create roles ######################################## - database_roles = learnhouseDB["roles"] + database_roles = request.app.db["roles"] database_roles.delete_many({}) roles = [] @@ -110,18 +110,18 @@ async def create_initial_data(): ) roles.append(admin_role) - await create_role(admin_role, current_user) + await create_role(request, admin_role, current_user) # Generate Courses and CourseChapters ######################################## - database_courses = learnhouseDB["courses"] - database_chapters = learnhouseDB["coursechapters"] + database_courses = request.app.db["courses"] + database_chapters = request.app.db["coursechapters"] database_courses.delete_many({}) database_chapters.delete_many({}) courses = [] - orgs = learnhouseDB["organizations"] + orgs = request.app.db["organizations"] if orgs.count_documents({}) > 0: for org in orgs.find(): @@ -150,7 +150,7 @@ async def create_initial_data(): authors=[current_user.user_id], ) - courses = learnhouseDB["courses"] + courses = request.app.db["courses"] name_in_disk = f"test_mock{course_id}.jpeg" image = requests.get( @@ -170,7 +170,7 @@ async def create_initial_data(): description=fake_multilang.unique.text(), lectures=[], ) - coursechapter = await create_coursechapter(coursechapter, course_id, current_user) + coursechapter = await create_coursechapter(request,coursechapter, course_id, current_user) pprint(coursechapter) if coursechapter: # create lectures @@ -180,4 +180,4 @@ async def create_initial_data(): type="dynamic", content={}, ) - lecture = await create_lecture(lecture, coursechapter['coursechapter_id'], current_user) + lecture = await create_lecture(request,lecture, coursechapter['coursechapter_id'], current_user) diff --git a/src/services/orgs.py b/src/services/orgs.py index d9287429..4c16e15a 100644 --- a/src/services/orgs.py +++ b/src/services/orgs.py @@ -3,7 +3,6 @@ from typing import List from uuid import uuid4 from pydantic import BaseModel from src.services.users import PublicUser, User -from src.services.database import check_database, create_database, learnhouseDB, learnhouseDB from src.services.security import * from fastapi import FastAPI, HTTPException, status, Request, Response, BackgroundTasks from datetime import datetime @@ -113,7 +112,6 @@ async def update_org(request: Request, org_object: Organization, org_id: str, cu async def delete_org(request: Request, org_id: str, current_user: PublicUser): - await check_database() await verify_org_rights(request, org_id, current_user, "delete") diff --git a/src/services/roles.py b/src/services/roles.py index 8f032d73..53642002 100644 --- a/src/services/roles.py +++ b/src/services/roles.py @@ -3,10 +3,9 @@ from typing import List from uuid import uuid4 from pydantic import BaseModel from src.services.users import PublicUser, User -from src.services.database import check_database, learnhouseDB, learnhouseDB from src.services.security import * from src.services.houses import House -from fastapi import HTTPException, status +from fastapi import HTTPException, status, Request from datetime import datetime #### Classes #################################################### @@ -45,9 +44,8 @@ class RoleInDB(Role): #### Classes #################################################### -async def get_role(role_id: str): - await check_database() - roles = learnhouseDB["roles"] +async def get_role(request: Request,role_id: str): + roles = request.app.db["roles"] role = roles.find_one({"role_id": role_id}) @@ -59,9 +57,8 @@ async def get_role(role_id: str): return role -async def create_role(role_object: Role, current_user: PublicUser): - await check_database() - roles = learnhouseDB["roles"] +async def create_role(request: Request,role_object: Role, current_user: PublicUser): + roles = request.app.db["roles"] # find if house already exists using name isRoleAvailable = roles.find_one({"name": role_object.name}) @@ -70,7 +67,7 @@ async def create_role(role_object: Role, current_user: PublicUser): raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="Role name already exists") - await verify_user_permissions_on_roles("create", current_user) + await verify_user_permissions_on_roles(request, "create", current_user) # generate house_id with uuid4 role_id = str(f"role_{uuid4()}") @@ -87,13 +84,12 @@ async def create_role(role_object: Role, current_user: PublicUser): return role.dict() -async def update_role(role_object: Role, role_id: str, current_user: PublicUser): - await check_database() +async def update_role(request: Request,role_object: Role, role_id: str, current_user: PublicUser): # verify house rights - await verify_user_permissions_on_roles("update", current_user) + await verify_user_permissions_on_roles(request, "update", current_user) - roles = learnhouseDB["roles"] + roles = request.app.db["roles"] role = roles.find_one({"role_id": role_id}) @@ -109,13 +105,12 @@ async def update_role(role_object: Role, role_id: str, current_user: PublicUser) return RoleInDB(**updated_role.dict()) -async def delete_role(role_id: str, current_user: PublicUser): - await check_database() +async def delete_role(request: Request,role_id: str, current_user: PublicUser): # verify house rights - await verify_user_permissions_on_roles("delete", current_user) + await verify_user_permissions_on_roles(request, "delete", current_user) - roles = learnhouseDB["roles"] + roles = request.app.db["roles"] role = roles.find_one({"role_id": role_id}) @@ -132,9 +127,8 @@ async def delete_role(role_id: str, current_user: PublicUser): status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Unavailable database") -async def get_roles(page: int = 1, limit: int = 10): - await check_database() - roles = learnhouseDB["roles"] +async def get_roles(request: Request,page: int = 1, limit: int = 10): + roles = request.app.db["roles"] # get all roles from database all_roles = roles.find().sort("name", 1).skip(10 * (page - 1)).limit(limit) @@ -144,9 +138,8 @@ async def get_roles(page: int = 1, limit: int = 10): #### Security #################################################### -async def verify_user_permissions_on_roles(action: str, current_user: PublicUser): - await check_database() - users = learnhouseDB["users"] +async def verify_user_permissions_on_roles(request: Request,action: str, current_user: PublicUser): + users = request.app.db["users"] user = users.find_one({"user_id": current_user.user_id}) diff --git a/src/services/security.py b/src/services/security.py index 16c40fbd..c9ae871b 100644 --- a/src/services/security.py +++ b/src/services/security.py @@ -1,10 +1,6 @@ -from fastapi import HTTPException, status +from fastapi import HTTPException, status, Request from passlib.context import CryptContext -from jose import JWTError, jwt -import logging from passlib.hash import pbkdf2_sha256 -from src.services.database import check_database -from src.services.database import check_database, learnhouseDB, learnhouseDB ### 🔒 JWT ############################################################## @@ -31,12 +27,11 @@ async def security_verify_password(plain_password: str, hashed_password: str): ### 🔒 Roles checking ############################################################## -async def verify_user_rights_with_roles(action: str, user_id: str, element_id: str): +async def verify_user_rights_with_roles(request: Request,action: str, user_id: str, element_id: str): """ Check if the user has the right to perform the action on the element """ - await check_database() - roles = learnhouseDB["roles"] + roles = request.app.db["roles"] # find data where user_id is in linked_users or * is in linked_users user_roles_cursor = roles.find({"$or": [{"linked_users": user_id}, {"linked_users": "*"}]}) diff --git a/src/services/users.py b/src/services/users.py index 1831931a..57f2829e 100644 --- a/src/services/users.py +++ b/src/services/users.py @@ -1,8 +1,7 @@ from uuid import uuid4 from pydantic import BaseModel -from src.services.database import check_database, learnhouseDB, learnhouseDB from src.services.security import * -from fastapi import HTTPException, status +from fastapi import HTTPException, status, Request from datetime import datetime #### Classes #################################################### @@ -41,6 +40,8 @@ class UserProfileMetadata(BaseModel): roles = list # TODO : terrible, export role classes from one single source of truth + + class Role(BaseModel): name: str description: str @@ -53,9 +54,8 @@ class Role(BaseModel): # TODO : avatar upload and update -async def get_user(username: str): - await check_database() - users = learnhouseDB["users"] +async def get_user(request: Request, username: str): + users = request.app.db["users"] user = users.find_one({"username": username}) @@ -67,10 +67,9 @@ async def get_user(username: str): return user -async def get_profile_metadata(user): - await check_database() - users = learnhouseDB["users"] - roles = learnhouseDB["roles"] +async def get_profile_metadata(request: Request, user): + users = request.app.db["users"] + roles = request.app.db["roles"] user = users.find_one({"user_id": user['user_id']}) @@ -92,9 +91,8 @@ async def get_profile_metadata(user): } -async def get_user_by_userid(user_id: str): - await check_database() - users = learnhouseDB["users"] +async def get_user_by_userid(request: Request, user_id: str): + users = request.app.db["users"] user = users.find_one({"user_id": user_id}) @@ -106,9 +104,8 @@ async def get_user_by_userid(user_id: str): return user -async def security_get_user(email: str): - await check_database() - users = learnhouseDB["users"] +async def security_get_user(request: Request, email: str): + users = request.app.db["users"] user = users.find_one({"email": email}) @@ -119,9 +116,8 @@ async def security_get_user(email: str): return UserInDB(**user) -async def get_userid_by_username(username: str): - await check_database() - users = learnhouseDB["users"] +async def get_userid_by_username(request: Request, username: str): + users = request.app.db["users"] user = users.find_one({"username": username}) @@ -132,9 +128,8 @@ async def get_userid_by_username(username: str): return user["user_id"] -async def update_user(user_id: str, user_object: UserWithPassword): - await check_database() - users = learnhouseDB["users"] +async def update_user(request: Request, user_id: str, user_object: UserWithPassword): + users = request.app.db["users"] isUserExists = users.find_one({"user_id": user_id}) isUsernameAvailable = users.find_one({"username": user_object.username}) @@ -155,9 +150,8 @@ async def update_user(user_id: str, user_object: UserWithPassword): return User(**user_object.dict()) -async def delete_user(user_id: str): - await check_database() - users = learnhouseDB["users"] +async def delete_user(request: Request, user_id: str): + users = request.app.db["users"] isUserAvailable = users.find_one({"user_id": user_id}) @@ -170,9 +164,8 @@ async def delete_user(user_id: str): return {"detail": "User deleted"} -async def create_user(user_object: UserWithPassword): - await check_database() - users = learnhouseDB["users"] +async def create_user(request: Request, user_object: UserWithPassword): + users = request.app.db["users"] isUserAvailable = users.find_one({"username": user_object.username})