diff --git a/src/routers/users.py b/src/routers/users.py index 0a913ec0..39a2021d 100644 --- a/src/routers/users.py +++ b/src/routers/users.py @@ -26,26 +26,34 @@ async def api_get_user_by_username(username: str): return await get_user(username) +@router.get("/user_id/{user_id}") +async def api_get_user_by_userid(user_id: str): + """ + Get single user by user_id + """ + return await get_user_by_userid(user_id) + + @router.post("/") -async def api_create_user(user_object: UserInDB): +async def api_create_user(user_object: UserWithPassword): """ Create new user """ return await create_user(user_object) -@router.delete("/username/{username}") -async def api_delete_user(username: str): +@router.delete("/user_id/{user_id}") +async def api_delete_user(user_id: str): """ Delete user by ID """ - - return await delete_user(username) + + return await delete_user(user_id) -@router.put("/username/{username}") -async def api_update_user(user_object: UserInDB): +@router.put("/user_id/{user_id}") +async def api_update_user(user_object: UserWithPassword, user_id: str): """ Update user by ID """ - return await update_user(user_object) + return await update_user(user_id, user_object) diff --git a/src/services/auth.py b/src/services/auth.py index f6f8e76b..d3dcc4ee 100644 --- a/src/services/auth.py +++ b/src/services/auth.py @@ -23,7 +23,6 @@ class TokenData(BaseModel): #### Classes #################################################### - async def authenticate_user(username: str, password: str): user = await security_get_user(username) if not user: @@ -58,7 +57,7 @@ async def get_current_user(token: str = Depends(oauth2_scheme)): token_data = TokenData(username=username) except JWTError: raise credentials_exception - user = await get_user(username=token_data.username) + user = await security_get_user(username=token_data.username) if user is None: raise credentials_exception - return User(**user.dict()) + return PublicUser(**user.dict()) diff --git a/src/services/courses.py b/src/services/courses.py index f5019c9b..a141e482 100644 --- a/src/services/courses.py +++ b/src/services/courses.py @@ -78,14 +78,14 @@ async def create_course(course_object: Course, current_user: User): # generate course_id with uuid4 course_id = str(f"course_{uuid4()}") - hasRoleRights = await verify_user_rights_with_roles("create", current_user.username, course_id) + hasRoleRights = await verify_user_rights_with_roles("create", current_user.user_id, course_id) if not hasRoleRights: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="Roles : Insufficient rights to perform this action") course = CourseInDB(course_id=course_id, authors=[ - current_user.username], creationDate=str(datetime.now()), updateDate=str(datetime.now()), **course_object.dict()) + current_user.user_id], creationDate=str(datetime.now()), updateDate=str(datetime.now()), **course_object.dict()) course_in_db = courses.insert_one(course.dict()) @@ -185,7 +185,7 @@ async def create_coursechapter(coursechapter_object: CourseChapter, course_id: s # generate coursechapter_id with uuid4 coursechapter_id = str(f"coursechapter_{uuid4()}") - hasRoleRights = await verify_user_rights_with_roles("create", current_user.username, coursechapter_id) + hasRoleRights = await verify_user_rights_with_roles("create", current_user.user_id, coursechapter_id) if not hasRoleRights: raise HTTPException( @@ -209,7 +209,7 @@ async def update_coursechapter(coursechapter_object: CourseChapter, coursechapt coursechapter = coursechapters.find_one( {"coursechapter_id": coursechapter_id}) - + # verify course rights await verify_rights(coursechapter["course_id"], current_user, "update") creationDate = coursechapter["creationDate"] @@ -237,8 +237,8 @@ async def delete_coursechapter(coursechapter_id: str, current_user: User): coursechapter = coursechapters.find_one( {"coursechapter_id": coursechapter_id}) - - # verify course rights + + # verify course rights await verify_rights(coursechapter["course_id"], current_user, "delete") if not coursechapter: @@ -278,8 +278,8 @@ async def verify_rights(course_id: str, current_user: User, 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.username, course_id) - isAuthor = current_user.username in course["authors"] + hasRoleRights = await verify_user_rights_with_roles(action, current_user.user_id, course_id) + isAuthor = current_user.user_id in course["authors"] if not hasRoleRights and not isAuthor: raise HTTPException( diff --git a/src/services/houses.py b/src/services/houses.py index 8b5fd982..473b577f 100644 --- a/src/services/houses.py +++ b/src/services/houses.py @@ -34,7 +34,7 @@ async def get_house(house_id: str, current_user: User): house = houses.find_one({"house_id": house_id}) # verify house rights - await verify_house_rights(house_id, current_user,"read") + await verify_house_rights(house_id, current_user, "read") if not house: raise HTTPException( @@ -58,15 +58,15 @@ async def create_house(house_object: House, current_user: User): # generate house_id with uuid4 house_id = str(f"house_{uuid4()}") - hasRoleRights = await verify_user_rights_with_roles("create", current_user.username, house_id) + hasRoleRights = await verify_user_rights_with_roles("create", current_user.user_id, house_id) if not hasRoleRights: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="Roles : Insufficient rights to perform this action") house = HouseInDB(house_id=house_id, owners=[ - current_user.username], admins=[ - current_user.username], **house_object.dict()) + current_user.user_id], admins=[ + current_user.user_id], **house_object.dict()) house_in_db = houses.insert_one(house.dict()) @@ -81,7 +81,7 @@ async def update_house(house_object: House, house_id: str, current_user: User): await check_database() # verify house rights - await verify_house_rights(house_id, current_user,"update") + await verify_house_rights(house_id, current_user, "update") houses = learnhouseDB["houses"] @@ -107,7 +107,7 @@ async def delete_house(house_id: str, current_user: User): await check_database() # verify house rights - await verify_house_rights(house_id, current_user,"delete") + await verify_house_rights(house_id, current_user, "delete") houses = learnhouseDB["houses"] @@ -148,8 +148,8 @@ async def verify_house_rights(house_id: str, current_user: User, action: str): raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="House does not exist") - hasRoleRights = await verify_user_rights_with_roles(action, current_user.username, house_id) - isOwner = current_user.username in house["owners"] + hasRoleRights = await verify_user_rights_with_roles(action, current_user.user_id, house_id) + isOwner = current_user.user_id in house["owners"] if not hasRoleRights and not isOwner: raise HTTPException( diff --git a/src/services/orgs.py b/src/services/orgs.py index 53ccf493..4eafe5bb 100644 --- a/src/services/orgs.py +++ b/src/services/orgs.py @@ -55,8 +55,8 @@ async def create_org(org_object: Organization, current_user: User): org_id = str(f"org_{uuid4()}") org = OrganizationInDB(org_id=org_id, owners=[ - current_user.username], admins=[ - current_user.username], **org_object.dict()) + current_user.user_id], admins=[ + current_user.user_id], **org_object.dict()) org_in_db = orgs.insert_one(org.dict()) @@ -128,7 +128,7 @@ async def get_orgs(page: int = 1, limit: int = 10): #### Security #################################################### -async def verify_org_rights(org_id: str, current_user: User, action:str,): +async def verify_org_rights(org_id: str, current_user: User, action: str,): await check_database() orgs = learnhouseDB["organizations"] @@ -138,8 +138,8 @@ async def verify_org_rights(org_id: str, current_user: User, action:str,): raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="Organization does not exist") - isOwner = current_user.username in org["owners"] - hasRoleRights = await verify_user_rights_with_roles(action,current_user.username,org_id) + isOwner = current_user.user_id in org["owners"] + hasRoleRights = await verify_user_rights_with_roles(action, current_user.user_id, org_id) if not hasRoleRights and not isOwner: raise HTTPException( diff --git a/src/services/roles.py b/src/services/roles.py index 1992bd64..cfd1c638 100644 --- a/src/services/roles.py +++ b/src/services/roles.py @@ -2,7 +2,7 @@ import json from typing import List from uuid import uuid4 from pydantic import BaseModel -from src.services.users import User +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 @@ -25,7 +25,7 @@ class Elements(BaseModel): houses: List[str] collections: List[str] organizations: List[str] - coursechapters : List[str] + coursechapters: List[str] class Role(BaseModel): @@ -69,7 +69,7 @@ async def create_role(role_object: Role, current_user: User): raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="Role name already exists") - await verify_user_permissions("create", current_user) + await verify_user_permissions_on_roles("create", current_user) # generate house_id with uuid4 role_id = str(f"role_{uuid4()}") @@ -90,7 +90,7 @@ async def update_role(role_object: House, role_id: str, current_user: User): await check_database() # verify house rights - await verify_user_permissions("update", current_user) + await verify_user_permissions_on_roles("update", current_user) roles = learnhouseDB["roles"] @@ -112,7 +112,7 @@ async def delete_role(role_id: str, current_user: User): await check_database() # verify house rights - await verify_user_permissions("delete", current_user) + await verify_user_permissions_on_roles("delete", current_user) roles = learnhouseDB["roles"] @@ -143,11 +143,11 @@ async def get_roles(page: int = 1, limit: int = 10): #### Security #################################################### -async def verify_user_permissions(action: str, current_user: User): +async def verify_user_permissions_on_roles(action: str, current_user: PublicUser): await check_database() users = learnhouseDB["users"] - user = users.find_one({"username": current_user.username}) + user = users.find_one({"user_id": current_user.user_id}) if not user: raise HTTPException( @@ -155,8 +155,8 @@ async def verify_user_permissions(action: str, current_user: User): isOwner = "owner" in user["user_type"] isEditor = "editor" in user["user_type"] - - # TODO: verify for all actions. + + # TODO: verify for all actions. if action == "delete": if isEditor: raise HTTPException( diff --git a/src/services/users.py b/src/services/users.py index d1c8bd89..7296848c 100644 --- a/src/services/users.py +++ b/src/services/users.py @@ -1,3 +1,4 @@ +from uuid import uuid4 from pydantic import BaseModel from src.services.database import check_database, learnhouseDB, learnhouseDB from src.services.security import * @@ -14,17 +15,30 @@ class User(BaseModel): disabled: bool | None = None avatar_url: str | None = None verified: bool - created_date: str user_type: str bio: str | None = None -class UserInDB(User): +class UserWithPassword(User): password: str + +class PublicUser(User): + user_id: str + creationDate: str + updateDate: str + + +class UserInDB(UserWithPassword): + user_id: str + password: str + creationDate: str + updateDate: str + #### Classes #################################################### -# TODO : user actions security +# TODO : user actions security + async def get_user(username: str): check_database() @@ -40,6 +54,20 @@ async def get_user(username: str): return user +async def get_user_by_userid(user_id: str): + check_database() + users = learnhouseDB["users"] + + user = users.find_one({"user_id": user_id}) + + if not user: + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, detail="User does not exist") + + user = User(**user) + return user + + async def security_get_user(username: str): check_database() users = learnhouseDB["users"] @@ -53,40 +81,58 @@ async def security_get_user(username: str): return UserInDB(**user) -async def update_user(user_object: UserInDB): +async def get_userid_by_username(username: str): check_database() users = learnhouseDB["users"] - isUserAvailable = users.find_one({"username": user_object.username}) + user = users.find_one({"username": username}) - if not isUserAvailable: + if not user: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="User does not exist") + return user["user_id"] + + +async def update_user(user_id: str, user_object: UserWithPassword): + check_database() + users = learnhouseDB["users"] + + isUserExists = users.find_one({"user_id": user_id}) + isUsernameAvailable = users.find_one({"username": user_object.username}) + + if not isUserExists: + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, detail="User does not exist") + + if isUsernameAvailable: + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, detail="Username already used") + user_object.password = await security_hash_password(user_object.password) updated_user = {"$set": user_object.dict()} - users.update_one({"username": user_object.username}, updated_user) + users.update_one({"user_id": user_id}, updated_user) return User(**user_object.dict()) -async def delete_user(username: str): +async def delete_user(user_id: str): check_database() users = learnhouseDB["users"] - isUserAvailable = users.find_one({"username": username}) + isUserAvailable = users.find_one({"user_id": user_id}) if not isUserAvailable: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="User does not exist") - users.delete_one({"username": username}) + users.delete_one({"user_id": user_id}) return {"detail": "User deleted"} -async def create_user(user_object: UserInDB): +async def create_user(user_object: UserWithPassword): check_database() users = learnhouseDB["users"] @@ -94,15 +140,19 @@ async def create_user(user_object: UserInDB): if isUserAvailable: raise HTTPException( - status_code=status.HTTP_409_CONFLICT, detail="User already exists") + status_code=status.HTTP_409_CONFLICT, detail="Username already exists") + + # generate house_id with uuid4 + user_id = str(f"user_{uuid4()}") # lowercase username user_object.username = user_object.username.lower() - user_object.created_date = str(datetime.now()) - user_object.password = await security_hash_password(user_object.password) - users.insert_one(user_object.dict()) + user = UserInDB(user_id=user_id, creationDate=str(datetime.now()), + updateDate=str(datetime.now()), **user_object.dict()) - return User(**user_object.dict()) + user_in_db = users.insert_one(user.dict()) + + return User(**user.dict())