mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: revamp authorization mechanism across app
This commit is contained in:
parent
72c5d13028
commit
3c2f6b3a98
14 changed files with 648 additions and 371 deletions
40
app.py
40
app.py
|
|
@ -8,6 +8,9 @@ from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi_jwt_auth.exceptions import AuthJWTException
|
from fastapi_jwt_auth.exceptions import AuthJWTException
|
||||||
from fastapi.middleware.gzip import GZipMiddleware
|
from fastapi.middleware.gzip import GZipMiddleware
|
||||||
|
|
||||||
|
from src.security.rbac.rbac import authorization_verify_based_on_roles, authorization_verify_if_element_is_public, authorization_verify_if_user_is_author
|
||||||
|
from src.services.users.schemas.users import UserRolesInOrganization
|
||||||
|
|
||||||
|
|
||||||
# from src.services.mocks.initial import create_initial_data
|
# from src.services.mocks.initial import create_initial_data
|
||||||
|
|
||||||
|
|
@ -66,3 +69,40 @@ app.include_router(v1_router)
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
async def root():
|
async def root():
|
||||||
return {"Message": "Welcome to LearnHouse ✨"}
|
return {"Message": "Welcome to LearnHouse ✨"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/test")
|
||||||
|
async def rootd(request: Request):
|
||||||
|
res = await authorization_verify_based_on_roles(
|
||||||
|
request=request,
|
||||||
|
user_id="user_c441e47e-5c04-4b03-9886-b0f5cb333c06",
|
||||||
|
action="read",
|
||||||
|
roles_list=[
|
||||||
|
UserRolesInOrganization(
|
||||||
|
org_id="org_e7085838-2efc-48f3-b414-77318572d9f5", role_id="role_admin"
|
||||||
|
),
|
||||||
|
],
|
||||||
|
element_id="collection_1c277b46-5a4b-440a-ac29-94b874ef7cf4",
|
||||||
|
)
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/test2")
|
||||||
|
async def rootds(request: Request):
|
||||||
|
res = await authorization_verify_if_user_is_author(
|
||||||
|
request=request,
|
||||||
|
user_id="user_c441e47e-5c04-4b03-9886-b0f5cb333c06",
|
||||||
|
action="read",
|
||||||
|
element_id="course_1c277b46-5a4b-440a-ac29-94b874ef7cf4",
|
||||||
|
)
|
||||||
|
return res
|
||||||
|
|
||||||
|
@app.get("/test3")
|
||||||
|
async def rootdsc(request: Request):
|
||||||
|
res = await authorization_verify_if_element_is_public(
|
||||||
|
request=request,
|
||||||
|
user_id="anonymous",
|
||||||
|
action="read",
|
||||||
|
element_id="course_1c277b46-5a4b-440a-ac29-94b874ef7cf4",
|
||||||
|
)
|
||||||
|
return res
|
||||||
|
|
@ -40,6 +40,7 @@ function NewCollection(params: any) {
|
||||||
name: name,
|
name: name,
|
||||||
description: description,
|
description: description,
|
||||||
courses: selectedCourses,
|
courses: selectedCourses,
|
||||||
|
public: true,
|
||||||
org_id: org.org_id,
|
org_id: org.org_id,
|
||||||
};
|
};
|
||||||
await createCollection(collection);
|
await createCollection(collection);
|
||||||
|
|
|
||||||
127
src/security/rbac/rbac.py
Normal file
127
src/security/rbac/rbac.py
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
from typing import Literal
|
||||||
|
from fastapi import HTTPException, status, Request
|
||||||
|
from src.security.rbac.utils import check_element_type, get_id_identifier_of_element
|
||||||
|
from src.services.roles.schemas.roles import RoleInDB
|
||||||
|
from src.services.users.schemas.users import UserRolesInOrganization
|
||||||
|
|
||||||
|
|
||||||
|
async def authorization_verify_if_element_is_public(
|
||||||
|
request,
|
||||||
|
element_id: str,
|
||||||
|
user_id: str,
|
||||||
|
action: Literal["read"],
|
||||||
|
):
|
||||||
|
element_nature = await check_element_type(element_id)
|
||||||
|
|
||||||
|
# Verifies if the element is public
|
||||||
|
if (
|
||||||
|
element_nature == ("courses" or "collections")
|
||||||
|
and action == "read"
|
||||||
|
and user_id == "anonymous"
|
||||||
|
):
|
||||||
|
if element_nature == "courses":
|
||||||
|
courses = request.app.db["courses"]
|
||||||
|
course = await courses.find_one({"course_id": element_id})
|
||||||
|
|
||||||
|
if course["public"]:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
|
detail="User rights (public content) : You don't have the right to perform this action",
|
||||||
|
)
|
||||||
|
|
||||||
|
if element_nature == "collections":
|
||||||
|
collections = request.app.db["collections"]
|
||||||
|
collection = await collections.find_one({"collection_id": element_id})
|
||||||
|
|
||||||
|
if collection["public"]:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
|
detail="User rights (public content) : You don't have the right to perform this action",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
|
detail="User rights (public content) : You don't have the right to perform this action",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def authorization_verify_if_user_is_author(
|
||||||
|
request,
|
||||||
|
user_id: str,
|
||||||
|
action: Literal["read", "update", "delete", "create"],
|
||||||
|
element_id: str,
|
||||||
|
):
|
||||||
|
if action == "update" or "delete" or "read":
|
||||||
|
element_nature = await check_element_type(element_id)
|
||||||
|
elements = request.app.db[element_nature]
|
||||||
|
element_identifier = await get_id_identifier_of_element(element_id)
|
||||||
|
element = await elements.find_one({element_identifier: element_id})
|
||||||
|
if user_id in element["authors"]:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
|
detail="User rights (author) : You don't have the right to perform this action",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
async def authorization_verify_based_on_roles(
|
||||||
|
request: Request,
|
||||||
|
user_id: str,
|
||||||
|
action: Literal["read", "update", "delete", "create"],
|
||||||
|
roles_list: list[UserRolesInOrganization],
|
||||||
|
element_id: str,
|
||||||
|
):
|
||||||
|
element_type = await check_element_type(element_id)
|
||||||
|
print(element_type)
|
||||||
|
element = request.app.db[element_type]
|
||||||
|
roles = request.app.db["roles"]
|
||||||
|
|
||||||
|
# Get the element
|
||||||
|
element_identifier = await get_id_identifier_of_element(element_id)
|
||||||
|
element = await element.find_one({element_identifier: element_id})
|
||||||
|
|
||||||
|
# Get the roles of the user
|
||||||
|
roles_id_list = [role["role_id"] for role in roles_list]
|
||||||
|
roles = await roles.find({"role_id": {"$in": roles_id_list}}).to_list(length=100)
|
||||||
|
|
||||||
|
# Get the rights of the roles
|
||||||
|
for role in roles:
|
||||||
|
role = RoleInDB(**role)
|
||||||
|
if role.elements[element_type][f"action_{action}"] is True:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
|
detail="User rights (roles) : You don't have the right to perform this action",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def authorization_verify_based_on_roles_and_authorship(
|
||||||
|
request: Request,
|
||||||
|
user_id: str,
|
||||||
|
action: Literal["read", "update", "delete", "create"],
|
||||||
|
roles_list: list[UserRolesInOrganization],
|
||||||
|
element_id: str,
|
||||||
|
):
|
||||||
|
isAuthor = await authorization_verify_if_user_is_author(
|
||||||
|
request, user_id, action, element_id
|
||||||
|
)
|
||||||
|
|
||||||
|
isRole = await authorization_verify_based_on_roles(
|
||||||
|
request, user_id, action, roles_list, element_id
|
||||||
|
)
|
||||||
|
|
||||||
|
if isAuthor or isRole:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
|
detail="User rights (roles & authorship) : You don't have the right to perform this action",
|
||||||
|
)
|
||||||
45
src/security/rbac/utils.py
Normal file
45
src/security/rbac/utils.py
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
from fastapi import HTTPException, status
|
||||||
|
|
||||||
|
|
||||||
|
async def check_element_type(element_id):
|
||||||
|
"""
|
||||||
|
Check if the element is a course, a user, a house or a collection, by checking its prefix
|
||||||
|
"""
|
||||||
|
if element_id.startswith("course_"):
|
||||||
|
return "courses"
|
||||||
|
elif element_id.startswith("user_"):
|
||||||
|
return "users"
|
||||||
|
elif element_id.startswith("house_"):
|
||||||
|
return "houses"
|
||||||
|
elif element_id.startswith("org_"):
|
||||||
|
return "organizations"
|
||||||
|
elif element_id.startswith("coursechapter_"):
|
||||||
|
return "coursechapters"
|
||||||
|
elif element_id.startswith("collection_"):
|
||||||
|
return "collections"
|
||||||
|
elif element_id.startswith("activity_"):
|
||||||
|
return "activities"
|
||||||
|
else:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_409_CONFLICT,
|
||||||
|
detail="User rights : Issue verifying element nature",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def get_singular_form_of_element(element_id):
|
||||||
|
element_type = await check_element_type(element_id)
|
||||||
|
|
||||||
|
if element_type == "activities":
|
||||||
|
return "activity"
|
||||||
|
else:
|
||||||
|
singular_form_element = element_type[:-1]
|
||||||
|
return singular_form_element
|
||||||
|
|
||||||
|
|
||||||
|
async def get_id_identifier_of_element(element_id):
|
||||||
|
singular_form_element = await get_singular_form_of_element(element_id)
|
||||||
|
|
||||||
|
if singular_form_element == "ogranizations":
|
||||||
|
return "org_id"
|
||||||
|
else:
|
||||||
|
return str(singular_form_element) + "_id"
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
from fastapi import HTTPException, status, Request
|
|
||||||
from passlib.context import CryptContext
|
from passlib.context import CryptContext
|
||||||
from passlib.hash import pbkdf2_sha256
|
from passlib.hash import pbkdf2_sha256
|
||||||
from config.config import get_learnhouse_config
|
from config.config import get_learnhouse_config
|
||||||
from src.services.roles.schemas.roles import RoleInDB
|
|
||||||
|
|
||||||
from src.services.users.schemas.users import UserInDB, UserRolesInOrganization
|
|
||||||
|
|
||||||
### 🔒 JWT ##############################################################
|
### 🔒 JWT ##############################################################
|
||||||
|
|
||||||
|
|
@ -30,122 +27,4 @@ async def security_verify_password(plain_password: str, hashed_password: str):
|
||||||
|
|
||||||
### 🔒 Passwords Hashing ##############################################################
|
### 🔒 Passwords Hashing ##############################################################
|
||||||
|
|
||||||
### 🔒 Roles checking ##############################################################
|
|
||||||
|
|
||||||
|
|
||||||
async def verify_user_rights_with_roles(
|
|
||||||
request: Request, action: str, user_id: str, element_id: str, element_org_id: str
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
Check if the user has the right to perform the action on the element
|
|
||||||
"""
|
|
||||||
request.app.db["roles"]
|
|
||||||
users = request.app.db["users"]
|
|
||||||
|
|
||||||
user = await users.find_one({"user_id": user_id})
|
|
||||||
|
|
||||||
#########
|
|
||||||
# Users existence verification
|
|
||||||
#########
|
|
||||||
|
|
||||||
if not user and user_id != "anonymous":
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_404_NOT_FOUND, detail="User rights : User not found"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check if user is anonymous
|
|
||||||
if user_id == "anonymous":
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Get User
|
|
||||||
user: UserInDB = UserInDB(**await users.find_one({"user_id": user_id}))
|
|
||||||
|
|
||||||
#########
|
|
||||||
# Organization Roles verification
|
|
||||||
#########
|
|
||||||
|
|
||||||
for org in user.orgs:
|
|
||||||
if org.org_id == element_org_id:
|
|
||||||
# Check if user is owner or reader of the organization
|
|
||||||
if org.org_role == ("owner" or "editor"):
|
|
||||||
return True
|
|
||||||
|
|
||||||
#########
|
|
||||||
# Roles verification
|
|
||||||
#########
|
|
||||||
user_roles = user.roles
|
|
||||||
|
|
||||||
if action != "create":
|
|
||||||
return await check_user_role_org_with_element_org(
|
|
||||||
request, element_id, user_roles, action
|
|
||||||
)
|
|
||||||
|
|
||||||
# If no role is found, raise an error
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
detail="User rights : You don't have the right to perform this action",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def check_element_type(element_id):
|
|
||||||
"""
|
|
||||||
Check if the element is a course, a user, a house or a collection, by checking its prefix
|
|
||||||
"""
|
|
||||||
if element_id.startswith("course_"):
|
|
||||||
return "courses"
|
|
||||||
elif element_id.startswith("user_"):
|
|
||||||
return "users"
|
|
||||||
elif element_id.startswith("house_"):
|
|
||||||
return "houses"
|
|
||||||
elif element_id.startswith("org_"):
|
|
||||||
return "organizations"
|
|
||||||
elif element_id.startswith("coursechapter_"):
|
|
||||||
return "coursechapters"
|
|
||||||
elif element_id.startswith("collection_"):
|
|
||||||
return "collections"
|
|
||||||
elif element_id.startswith("activity_"):
|
|
||||||
return "activities"
|
|
||||||
else:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_409_CONFLICT,
|
|
||||||
detail="User rights : Issue verifying element nature",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def check_user_role_org_with_element_org(
|
|
||||||
request: Request,
|
|
||||||
element_id: str,
|
|
||||||
roles_list: list[UserRolesInOrganization],
|
|
||||||
action: str,
|
|
||||||
):
|
|
||||||
element_type = await check_element_type(element_id)
|
|
||||||
element = request.app.db[element_type]
|
|
||||||
roles = request.app.db["roles"]
|
|
||||||
|
|
||||||
# get singular element type
|
|
||||||
singular_form_element = element_type[:-1]
|
|
||||||
|
|
||||||
element_type_id = singular_form_element + "_id"
|
|
||||||
|
|
||||||
element_org = await element.find_one({element_type_id: element_id})
|
|
||||||
|
|
||||||
for role in roles_list:
|
|
||||||
# Check if The role belongs to the same organization as the element
|
|
||||||
role_db = await roles.find_one({"role_id": role.role_id})
|
|
||||||
role = RoleInDB(**role_db)
|
|
||||||
if (role.org_id == element_org["org_id"]) or role.org_id == "*":
|
|
||||||
# Check if user has the right role
|
|
||||||
for role in roles_list:
|
|
||||||
role_db = await roles.find_one({"role_id": role.role_id})
|
|
||||||
role = RoleInDB(**role_db)
|
|
||||||
if role.elements[element_type][f"action_{action}"]:
|
|
||||||
return True
|
|
||||||
|
|
||||||
else:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
detail="User rights (roles) : You don't have the right to perform this action",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
### 🔒 Roles checking ##############################################################
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
|
from typing import Literal
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from src.security.security import verify_user_rights_with_roles
|
from src.security.rbac.rbac import (
|
||||||
from src.services.users.schemas.users import PublicUser
|
authorization_verify_based_on_roles,
|
||||||
|
authorization_verify_if_element_is_public,
|
||||||
|
)
|
||||||
|
from src.services.users.schemas.users import AnonymousUser, PublicUser
|
||||||
from fastapi import HTTPException, status, Request
|
from fastapi import HTTPException, status, Request
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
@ -40,23 +44,26 @@ async def create_activity(
|
||||||
):
|
):
|
||||||
activities = request.app.db["activities"]
|
activities = request.app.db["activities"]
|
||||||
courses = request.app.db["courses"]
|
courses = request.app.db["courses"]
|
||||||
|
users = request.app.db["users"]
|
||||||
|
|
||||||
|
# get user
|
||||||
|
user = await users.find_one({"user_id": current_user.user_id})
|
||||||
|
|
||||||
# generate activity_id
|
# generate activity_id
|
||||||
activity_id = str(f"activity_{uuid4()}")
|
activity_id = str(f"activity_{uuid4()}")
|
||||||
|
|
||||||
hasRoleRights = await verify_user_rights_with_roles(
|
# verify activity rights
|
||||||
request, "create", current_user.user_id, activity_id, org_id
|
await authorization_verify_based_on_roles(
|
||||||
|
request,
|
||||||
|
current_user.user_id,
|
||||||
|
"create",
|
||||||
|
user["roles"],
|
||||||
|
activity_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
# get course_id from activity
|
# get course_id from activity
|
||||||
course = await courses.find_one({"chapters": coursechapter_id})
|
course = await courses.find_one({"chapters": coursechapter_id})
|
||||||
|
|
||||||
if not hasRoleRights:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_409_CONFLICT,
|
|
||||||
detail="Roles : Insufficient rights to perform this action",
|
|
||||||
)
|
|
||||||
|
|
||||||
# create activity
|
# create activity
|
||||||
activity = ActivityInDB(
|
activity = ActivityInDB(
|
||||||
**activity_object.dict(),
|
**activity_object.dict(),
|
||||||
|
|
@ -86,29 +93,10 @@ async def get_activity(request: Request, activity_id: str, current_user: PublicU
|
||||||
|
|
||||||
# get course_id from activity
|
# get course_id from activity
|
||||||
coursechapter_id = activity["coursechapter_id"]
|
coursechapter_id = activity["coursechapter_id"]
|
||||||
course = await courses.find_one({"chapters": coursechapter_id})
|
await courses.find_one({"chapters": coursechapter_id})
|
||||||
|
|
||||||
isCoursePublic = course["public"]
|
|
||||||
isAuthor = current_user.user_id in course["authors"]
|
|
||||||
|
|
||||||
if isAuthor:
|
|
||||||
activity = ActivityInDB(**activity)
|
|
||||||
return activity
|
|
||||||
|
|
||||||
# verify course rights
|
# verify course rights
|
||||||
hasRoleRights = await verify_user_rights_with_roles(
|
await verify_rights(request, activity["course_id"], current_user, "read")
|
||||||
request,
|
|
||||||
"read",
|
|
||||||
current_user.user_id,
|
|
||||||
activity_id,
|
|
||||||
element_org_id=activity["org_id"],
|
|
||||||
)
|
|
||||||
|
|
||||||
if not hasRoleRights and not isCoursePublic:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_409_CONFLICT,
|
|
||||||
detail="Roles : Insufficient rights to perform this action",
|
|
||||||
)
|
|
||||||
|
|
||||||
if not activity:
|
if not activity:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|
@ -128,14 +116,9 @@ async def update_activity(
|
||||||
activities = request.app.db["activities"]
|
activities = request.app.db["activities"]
|
||||||
|
|
||||||
activity = await activities.find_one({"activity_id": activity_id})
|
activity = await activities.find_one({"activity_id": activity_id})
|
||||||
|
|
||||||
# verify course rights
|
# verify course rights
|
||||||
await verify_user_rights_with_roles(
|
await verify_rights(request, activity_id, current_user, "update")
|
||||||
request,
|
|
||||||
"update",
|
|
||||||
current_user.user_id,
|
|
||||||
activity_id,
|
|
||||||
element_org_id=activity["org_id"],
|
|
||||||
)
|
|
||||||
|
|
||||||
if activity:
|
if activity:
|
||||||
creationDate = activity["creationDate"]
|
creationDate = activity["creationDate"]
|
||||||
|
|
@ -171,13 +154,7 @@ async def delete_activity(request: Request, activity_id: str, current_user: Publ
|
||||||
activity = await activities.find_one({"activity_id": activity_id})
|
activity = await activities.find_one({"activity_id": activity_id})
|
||||||
|
|
||||||
# verify course rights
|
# verify course rights
|
||||||
await verify_user_rights_with_roles(
|
await verify_rights(request, activity_id, current_user, "delete")
|
||||||
request,
|
|
||||||
"delete",
|
|
||||||
current_user.user_id,
|
|
||||||
activity_id,
|
|
||||||
element_org_id=activity["org_id"],
|
|
||||||
)
|
|
||||||
|
|
||||||
if not activity:
|
if not activity:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|
@ -217,3 +194,44 @@ async def get_activities(
|
||||||
]
|
]
|
||||||
|
|
||||||
return activities
|
return activities
|
||||||
|
|
||||||
|
|
||||||
|
#### Security ####################################################
|
||||||
|
|
||||||
|
|
||||||
|
async def verify_rights(
|
||||||
|
request: Request,
|
||||||
|
activity_id: str, # course_id in case of read
|
||||||
|
current_user: PublicUser | AnonymousUser,
|
||||||
|
action: Literal["create", "read", "update", "delete"],
|
||||||
|
):
|
||||||
|
if action == "read":
|
||||||
|
if current_user.user_id == "anonymous":
|
||||||
|
await authorization_verify_if_element_is_public(
|
||||||
|
request, activity_id, current_user.user_id, action
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
users = request.app.db["users"]
|
||||||
|
user = await users.find_one({"user_id": current_user.user_id})
|
||||||
|
|
||||||
|
await authorization_verify_based_on_roles(
|
||||||
|
request,
|
||||||
|
current_user.user_id,
|
||||||
|
action,
|
||||||
|
user["roles"],
|
||||||
|
activity_id,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
users = request.app.db["users"]
|
||||||
|
user = await users.find_one({"user_id": current_user.user_id})
|
||||||
|
|
||||||
|
await authorization_verify_based_on_roles(
|
||||||
|
request,
|
||||||
|
current_user.user_id,
|
||||||
|
action,
|
||||||
|
user["roles"],
|
||||||
|
activity_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#### Security ####################################################
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from src.security.security import verify_user_rights_with_roles
|
from src.security.rbac.rbac import authorization_verify_based_on_roles
|
||||||
from src.services.courses.activities.uploads.pdfs import upload_pdf
|
from src.services.courses.activities.uploads.pdfs import upload_pdf
|
||||||
from src.services.users.users import PublicUser
|
from src.services.users.users import PublicUser
|
||||||
from src.services.courses.activities.activities import ActivityInDB
|
from src.services.courses.activities.activities import ActivityInDB
|
||||||
|
|
@ -16,6 +16,10 @@ async def create_documentpdf_activity(
|
||||||
):
|
):
|
||||||
activities = request.app.db["activities"]
|
activities = request.app.db["activities"]
|
||||||
courses = request.app.db["courses"]
|
courses = request.app.db["courses"]
|
||||||
|
users = request.app.db["users"]
|
||||||
|
|
||||||
|
# get user
|
||||||
|
user = await users.find_one({"user_id": current_user.user_id})
|
||||||
|
|
||||||
# generate activity_id
|
# generate activity_id
|
||||||
activity_id = str(f"activity_{uuid4()}")
|
activity_id = str(f"activity_{uuid4()}")
|
||||||
|
|
@ -64,14 +68,12 @@ async def create_documentpdf_activity(
|
||||||
updateDate=str(datetime.now()),
|
updateDate=str(datetime.now()),
|
||||||
)
|
)
|
||||||
|
|
||||||
hasRoleRights = await verify_user_rights_with_roles(
|
await authorization_verify_based_on_roles(
|
||||||
request, "create", current_user.user_id, activity_id, element_org_id=org_id
|
request,
|
||||||
)
|
current_user.user_id,
|
||||||
|
"create",
|
||||||
if not hasRoleRights:
|
user["roles"],
|
||||||
raise HTTPException(
|
activity_id,
|
||||||
status_code=status.HTTP_409_CONFLICT,
|
|
||||||
detail="Roles : Insufficient rights to perform this action",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# create activity
|
# create activity
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from src.security.security import verify_user_rights_with_roles
|
from src.security.rbac.rbac import (
|
||||||
|
authorization_verify_based_on_roles,
|
||||||
|
)
|
||||||
from src.services.courses.activities.uploads.videos import upload_video
|
from src.services.courses.activities.uploads.videos import upload_video
|
||||||
from src.services.users.users import PublicUser
|
from src.services.users.users import PublicUser
|
||||||
from src.services.courses.activities.activities import ActivityInDB
|
from src.services.courses.activities.activities import ActivityInDB
|
||||||
|
|
@ -19,6 +21,10 @@ async def create_video_activity(
|
||||||
):
|
):
|
||||||
activities = request.app.db["activities"]
|
activities = request.app.db["activities"]
|
||||||
courses = request.app.db["courses"]
|
courses = request.app.db["courses"]
|
||||||
|
users = request.app.db["users"]
|
||||||
|
|
||||||
|
# get user
|
||||||
|
user = await users.find_one({"user_id": current_user.user_id})
|
||||||
|
|
||||||
# generate activity_id
|
# generate activity_id
|
||||||
activity_id = str(f"activity_{uuid4()}")
|
activity_id = str(f"activity_{uuid4()}")
|
||||||
|
|
@ -75,14 +81,12 @@ async def create_video_activity(
|
||||||
updateDate=str(datetime.now()),
|
updateDate=str(datetime.now()),
|
||||||
)
|
)
|
||||||
|
|
||||||
hasRoleRights = await verify_user_rights_with_roles(
|
await authorization_verify_based_on_roles(
|
||||||
request, "create", current_user.user_id, activity_id, element_org_id=org_id
|
request,
|
||||||
)
|
current_user.user_id,
|
||||||
|
"create",
|
||||||
if not hasRoleRights:
|
user["roles"],
|
||||||
raise HTTPException(
|
activity_id,
|
||||||
status_code=status.HTTP_409_CONFLICT,
|
|
||||||
detail="Roles : Insufficient rights to perform this action",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# create activity
|
# create activity
|
||||||
|
|
@ -122,6 +126,10 @@ async def create_external_video_activity(
|
||||||
):
|
):
|
||||||
activities = request.app.db["activities"]
|
activities = request.app.db["activities"]
|
||||||
courses = request.app.db["courses"]
|
courses = request.app.db["courses"]
|
||||||
|
users = request.app.db["users"]
|
||||||
|
|
||||||
|
# get user
|
||||||
|
user = await users.find_one({"user_id": current_user.user_id})
|
||||||
|
|
||||||
# generate activity_id
|
# generate activity_id
|
||||||
activity_id = str(f"activity_{uuid4()}")
|
activity_id = str(f"activity_{uuid4()}")
|
||||||
|
|
@ -157,14 +165,12 @@ async def create_external_video_activity(
|
||||||
updateDate=str(datetime.now()),
|
updateDate=str(datetime.now()),
|
||||||
)
|
)
|
||||||
|
|
||||||
hasRoleRights = await verify_user_rights_with_roles(
|
await authorization_verify_based_on_roles(
|
||||||
request, "create", current_user.user_id, activity_id, element_org_id=org_id
|
request,
|
||||||
)
|
current_user.user_id,
|
||||||
|
"create",
|
||||||
if not hasRoleRights:
|
user["roles"],
|
||||||
raise HTTPException(
|
activity_id,
|
||||||
status_code=status.HTTP_409_CONFLICT,
|
|
||||||
detail="Roles : Insufficient rights to perform this action",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# create activity
|
# create activity
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import List
|
from typing import List, Literal
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from src.security.auth import non_public_endpoint
|
from src.security.auth import non_public_endpoint
|
||||||
|
from src.security.rbac.rbac import (
|
||||||
|
authorization_verify_based_on_roles,
|
||||||
|
authorization_verify_based_on_roles_and_authorship,
|
||||||
|
authorization_verify_if_element_is_public,
|
||||||
|
)
|
||||||
from src.services.courses.courses import Course
|
from src.services.courses.courses import Course
|
||||||
from src.services.courses.activities.activities import ActivityInDB
|
from src.services.courses.activities.activities import ActivityInDB
|
||||||
from src.security.security import verify_user_rights_with_roles
|
|
||||||
from src.services.users.users import PublicUser
|
from src.services.users.users import PublicUser
|
||||||
from fastapi import HTTPException, status, Request
|
from fastapi import HTTPException, status, Request
|
||||||
|
|
||||||
|
|
@ -29,6 +33,7 @@ class CourseChapterMetaData(BaseModel):
|
||||||
chapters: dict
|
chapters: dict
|
||||||
activities: object
|
activities: object
|
||||||
|
|
||||||
|
|
||||||
#### Classes ####################################################
|
#### Classes ####################################################
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
|
|
@ -36,35 +41,60 @@ class CourseChapterMetaData(BaseModel):
|
||||||
####################################################
|
####################################################
|
||||||
|
|
||||||
|
|
||||||
async def create_coursechapter(request: Request, coursechapter_object: CourseChapter, course_id: str, current_user: PublicUser):
|
async def create_coursechapter(
|
||||||
|
request: Request,
|
||||||
|
coursechapter_object: CourseChapter,
|
||||||
|
course_id: str,
|
||||||
|
current_user: PublicUser,
|
||||||
|
):
|
||||||
courses = request.app.db["courses"]
|
courses = request.app.db["courses"]
|
||||||
print(course_id)
|
users = request.app.db["users"]
|
||||||
# get course org_id and verify rights
|
# get course org_id and verify rights
|
||||||
course = await courses.find_one({"course_id": course_id})
|
await courses.find_one({"course_id": course_id})
|
||||||
|
user = await users.find_one({"user_id": current_user.user_id})
|
||||||
|
|
||||||
# generate coursechapter_id with uuid4
|
# generate coursechapter_id with uuid4
|
||||||
coursechapter_id = str(f"coursechapter_{uuid4()}")
|
coursechapter_id = str(f"coursechapter_{uuid4()}")
|
||||||
|
|
||||||
hasRoleRights = await verify_user_rights_with_roles(request, "create", current_user.user_id, coursechapter_id, course["org_id"])
|
hasRoleRights = await authorization_verify_based_on_roles(
|
||||||
|
request, current_user.user_id, "create", user["roles"], course_id
|
||||||
|
)
|
||||||
|
|
||||||
if not hasRoleRights:
|
if not hasRoleRights:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="Roles : Insufficient rights to perform this action")
|
status_code=status.HTTP_409_CONFLICT,
|
||||||
|
detail="Roles : Insufficient rights to perform this action",
|
||||||
|
)
|
||||||
|
|
||||||
coursechapter = CourseChapterInDB(coursechapter_id=coursechapter_id, creationDate=str(
|
coursechapter = CourseChapterInDB(
|
||||||
datetime.now()), updateDate=str(datetime.now()), course_id=course_id, **coursechapter_object.dict())
|
coursechapter_id=coursechapter_id,
|
||||||
|
creationDate=str(datetime.now()),
|
||||||
|
updateDate=str(datetime.now()),
|
||||||
|
course_id=course_id,
|
||||||
|
**coursechapter_object.dict(),
|
||||||
|
)
|
||||||
|
|
||||||
courses.update_one({"course_id": course_id}, {
|
courses.update_one(
|
||||||
"$addToSet": {"chapters": coursechapter_id, "chapters_content": coursechapter.dict()}})
|
{"course_id": course_id},
|
||||||
|
{
|
||||||
|
"$addToSet": {
|
||||||
|
"chapters": coursechapter_id,
|
||||||
|
"chapters_content": coursechapter.dict(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
return coursechapter.dict()
|
return coursechapter.dict()
|
||||||
|
|
||||||
|
|
||||||
async def get_coursechapter(request: Request, coursechapter_id: str, current_user: PublicUser):
|
async def get_coursechapter(
|
||||||
|
request: Request, coursechapter_id: str, current_user: PublicUser
|
||||||
|
):
|
||||||
courses = request.app.db["courses"]
|
courses = request.app.db["courses"]
|
||||||
|
|
||||||
coursechapter = await courses.find_one(
|
coursechapter = await courses.find_one(
|
||||||
{"chapters_content.coursechapter_id": coursechapter_id})
|
{"chapters_content.coursechapter_id": coursechapter_id}
|
||||||
|
)
|
||||||
|
|
||||||
if coursechapter:
|
if coursechapter:
|
||||||
# verify course rights
|
# verify course rights
|
||||||
|
|
@ -75,64 +105,87 @@ async def get_coursechapter(request: Request, coursechapter_id: str, current_use
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="CourseChapter does not exist")
|
status_code=status.HTTP_409_CONFLICT, detail="CourseChapter does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def update_coursechapter(request: Request, coursechapter_object: CourseChapter, coursechapter_id: str, current_user: PublicUser):
|
async def update_coursechapter(
|
||||||
|
request: Request,
|
||||||
|
coursechapter_object: CourseChapter,
|
||||||
|
coursechapter_id: str,
|
||||||
|
current_user: PublicUser,
|
||||||
|
):
|
||||||
courses = request.app.db["courses"]
|
courses = request.app.db["courses"]
|
||||||
|
|
||||||
coursechapter = await courses.find_one(
|
coursechapter = await courses.find_one(
|
||||||
{"chapters_content.coursechapter_id": coursechapter_id})
|
{"chapters_content.coursechapter_id": coursechapter_id}
|
||||||
|
)
|
||||||
|
|
||||||
if coursechapter:
|
if coursechapter:
|
||||||
|
|
||||||
# verify course rights
|
# verify course rights
|
||||||
await verify_rights(request, coursechapter["course_id"], current_user, "update")
|
await verify_rights(request, coursechapter["course_id"], current_user, "update")
|
||||||
|
|
||||||
coursechapter = CourseChapterInDB(coursechapter_id=coursechapter_id, creationDate=str(
|
coursechapter = CourseChapterInDB(
|
||||||
datetime.now()), updateDate=str(datetime.now()), course_id=coursechapter["course_id"], **coursechapter_object.dict())
|
coursechapter_id=coursechapter_id,
|
||||||
|
creationDate=str(datetime.now()),
|
||||||
|
updateDate=str(datetime.now()),
|
||||||
|
course_id=coursechapter["course_id"],
|
||||||
|
**coursechapter_object.dict(),
|
||||||
|
)
|
||||||
|
|
||||||
courses.update_one({"chapters_content.coursechapter_id": coursechapter_id}, {
|
courses.update_one(
|
||||||
"$set": {"chapters_content.$": coursechapter.dict()}})
|
{"chapters_content.coursechapter_id": coursechapter_id},
|
||||||
|
{"$set": {"chapters_content.$": coursechapter.dict()}},
|
||||||
|
)
|
||||||
|
|
||||||
return coursechapter
|
return coursechapter
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="Coursechapter does not exist")
|
status_code=status.HTTP_409_CONFLICT, detail="Coursechapter does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def delete_coursechapter(request: Request, coursechapter_id: str, current_user: PublicUser):
|
async def delete_coursechapter(
|
||||||
|
request: Request, coursechapter_id: str, current_user: PublicUser
|
||||||
|
):
|
||||||
courses = request.app.db["courses"]
|
courses = request.app.db["courses"]
|
||||||
|
|
||||||
course = await courses.find_one(
|
course = await courses.find_one(
|
||||||
{"chapters_content.coursechapter_id": coursechapter_id})
|
{"chapters_content.coursechapter_id": coursechapter_id}
|
||||||
|
)
|
||||||
|
|
||||||
if course:
|
if course:
|
||||||
# verify course rights
|
# verify course rights
|
||||||
await verify_rights(request, course["course_id"], current_user, "delete")
|
await verify_rights(request, course["course_id"], current_user, "delete")
|
||||||
|
|
||||||
# Remove coursechapter from course
|
# Remove coursechapter from course
|
||||||
await courses.update_one({"course_id": course["course_id"]}, {
|
await courses.update_one(
|
||||||
"$pull": {"chapters": coursechapter_id}})
|
{"course_id": course["course_id"]},
|
||||||
|
{"$pull": {"chapters": coursechapter_id}},
|
||||||
await courses.update_one({"chapters_content.coursechapter_id": coursechapter_id}, {
|
)
|
||||||
"$pull": {"chapters_content": {"coursechapter_id": coursechapter_id}}})
|
|
||||||
|
|
||||||
|
|
||||||
|
await courses.update_one(
|
||||||
|
{"chapters_content.coursechapter_id": coursechapter_id},
|
||||||
|
{"$pull": {"chapters_content": {"coursechapter_id": coursechapter_id}}},
|
||||||
|
)
|
||||||
|
|
||||||
return {"message": "Coursechapter deleted"}
|
return {"message": "Coursechapter deleted"}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist")
|
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
# Misc
|
# Misc
|
||||||
####################################################
|
####################################################
|
||||||
|
|
||||||
|
|
||||||
async def get_coursechapters(request: Request, course_id: str, page: int = 1, limit: int = 10):
|
async def get_coursechapters(
|
||||||
|
request: Request, course_id: str, page: int = 1, limit: int = 10
|
||||||
|
):
|
||||||
courses = request.app.db["courses"]
|
courses = request.app.db["courses"]
|
||||||
|
|
||||||
course = await courses.find_one({"course_id": course_id})
|
course = await courses.find_one({"course_id": course_id})
|
||||||
|
|
@ -144,19 +197,26 @@ async def get_coursechapters(request: Request, course_id: str, page: int = 1, li
|
||||||
return coursechapters
|
return coursechapters
|
||||||
|
|
||||||
|
|
||||||
async def get_coursechapters_meta(request: Request, course_id: str, current_user: PublicUser):
|
async def get_coursechapters_meta(
|
||||||
|
request: Request, course_id: str, current_user: PublicUser
|
||||||
|
):
|
||||||
courses = request.app.db["courses"]
|
courses = request.app.db["courses"]
|
||||||
activities = request.app.db["activities"]
|
activities = request.app.db["activities"]
|
||||||
|
|
||||||
await non_public_endpoint(current_user)
|
await non_public_endpoint(current_user)
|
||||||
|
|
||||||
coursechapters = await courses.find_one({"course_id": course_id}, {"chapters": 1, "chapters_content": 1, "_id": 0})
|
await verify_rights(request, course_id, current_user, "read")
|
||||||
|
|
||||||
|
coursechapters = await courses.find_one(
|
||||||
|
{"course_id": course_id}, {"chapters": 1, "chapters_content": 1, "_id": 0}
|
||||||
|
)
|
||||||
|
|
||||||
coursechapters = coursechapters
|
coursechapters = coursechapters
|
||||||
|
|
||||||
if not coursechapters:
|
if not coursechapters:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist")
|
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
# activities
|
# activities
|
||||||
coursechapter_activityIds_global = []
|
coursechapter_activityIds_global = []
|
||||||
|
|
@ -165,7 +225,6 @@ async def get_coursechapters_meta(request: Request, course_id: str, current_user
|
||||||
chapters = {}
|
chapters = {}
|
||||||
if coursechapters["chapters_content"]:
|
if coursechapters["chapters_content"]:
|
||||||
for coursechapter in coursechapters["chapters_content"]:
|
for coursechapter in coursechapters["chapters_content"]:
|
||||||
|
|
||||||
coursechapter = CourseChapterInDB(**coursechapter)
|
coursechapter = CourseChapterInDB(**coursechapter)
|
||||||
coursechapter_activityIds = []
|
coursechapter_activityIds = []
|
||||||
|
|
||||||
|
|
@ -174,37 +233,55 @@ async def get_coursechapters_meta(request: Request, course_id: str, current_user
|
||||||
coursechapter_activityIds_global.append(activity)
|
coursechapter_activityIds_global.append(activity)
|
||||||
|
|
||||||
chapters[coursechapter.coursechapter_id] = {
|
chapters[coursechapter.coursechapter_id] = {
|
||||||
"id": coursechapter.coursechapter_id, "name": coursechapter.name, "activityIds": coursechapter_activityIds
|
"id": coursechapter.coursechapter_id,
|
||||||
|
"name": coursechapter.name,
|
||||||
|
"activityIds": coursechapter_activityIds,
|
||||||
}
|
}
|
||||||
|
|
||||||
# activities
|
# activities
|
||||||
activities_list = {}
|
activities_list = {}
|
||||||
for activity in await activities.find({"activity_id": {"$in": coursechapter_activityIds_global}}).to_list(length=100):
|
for activity in await activities.find(
|
||||||
|
{"activity_id": {"$in": coursechapter_activityIds_global}}
|
||||||
|
).to_list(length=100):
|
||||||
activity = ActivityInDB(**activity)
|
activity = ActivityInDB(**activity)
|
||||||
activities_list[activity.activity_id] = {
|
activities_list[activity.activity_id] = {
|
||||||
"id": activity.activity_id, "name": activity.name, "type": activity.type, "content": activity.content
|
"id": activity.activity_id,
|
||||||
|
"name": activity.name,
|
||||||
|
"type": activity.type,
|
||||||
|
"content": activity.content,
|
||||||
}
|
}
|
||||||
|
|
||||||
final = {
|
final = {
|
||||||
"chapters": chapters,
|
"chapters": chapters,
|
||||||
"chapterOrder": coursechapters["chapters"],
|
"chapterOrder": coursechapters["chapters"],
|
||||||
"activities": activities_list
|
"activities": activities_list,
|
||||||
}
|
}
|
||||||
|
|
||||||
return final
|
return final
|
||||||
|
|
||||||
|
|
||||||
async def update_coursechapters_meta(request: Request, course_id: str, coursechapters_metadata: CourseChapterMetaData, current_user: PublicUser):
|
async def update_coursechapters_meta(
|
||||||
|
request: Request,
|
||||||
|
course_id: str,
|
||||||
|
coursechapters_metadata: CourseChapterMetaData,
|
||||||
|
current_user: PublicUser,
|
||||||
|
):
|
||||||
courses = request.app.db["courses"]
|
courses = request.app.db["courses"]
|
||||||
|
|
||||||
|
await verify_rights(request, course_id, current_user, "update")
|
||||||
|
|
||||||
# update chapters in course
|
# update chapters in course
|
||||||
await courses.update_one({"course_id": course_id}, {
|
await courses.update_one(
|
||||||
"$set": {"chapters": coursechapters_metadata.chapterOrder}})
|
{"course_id": course_id},
|
||||||
|
{"$set": {"chapters": coursechapters_metadata.chapterOrder}},
|
||||||
|
)
|
||||||
|
|
||||||
if coursechapters_metadata.chapters is not None:
|
if coursechapters_metadata.chapters is not None:
|
||||||
for coursechapter_id, chapter_metadata in coursechapters_metadata.chapters.items():
|
for (
|
||||||
filter_query = {
|
coursechapter_id,
|
||||||
"chapters_content.coursechapter_id": coursechapter_id}
|
chapter_metadata,
|
||||||
|
) in coursechapters_metadata.chapters.items():
|
||||||
|
filter_query = {"chapters_content.coursechapter_id": coursechapter_id}
|
||||||
update_query = {
|
update_query = {
|
||||||
"$set": {
|
"$set": {
|
||||||
"chapters_content.$.activities": chapter_metadata["activityIds"]
|
"chapters_content.$.activities": chapter_metadata["activityIds"]
|
||||||
|
|
@ -213,30 +290,57 @@ async def update_coursechapters_meta(request: Request, course_id: str, coursecha
|
||||||
result = await courses.update_one(filter_query, update_query)
|
result = await courses.update_one(filter_query, update_query)
|
||||||
if result.matched_count == 0:
|
if result.matched_count == 0:
|
||||||
# handle error when no documents are matched by the filter query
|
# handle error when no documents are matched by the filter query
|
||||||
print(
|
print(f"No documents found for course chapter ID {coursechapter_id}")
|
||||||
f"No documents found for course chapter ID {coursechapter_id}")
|
|
||||||
|
|
||||||
return {"detail": "coursechapters metadata updated"}
|
return {"detail": "coursechapters metadata updated"}
|
||||||
|
|
||||||
|
|
||||||
#### Security ####################################################
|
#### Security ####################################################
|
||||||
|
|
||||||
|
|
||||||
async def verify_rights(request: Request, course_id: str, current_user: PublicUser, action: str):
|
async def verify_rights(
|
||||||
|
request: Request,
|
||||||
|
course_id: str,
|
||||||
|
current_user: PublicUser,
|
||||||
|
action: Literal["read", "update", "delete"],
|
||||||
|
):
|
||||||
courses = request.app.db["courses"]
|
courses = request.app.db["courses"]
|
||||||
|
users = request.app.db["users"]
|
||||||
|
user = await users.find_one({"user_id": current_user.user_id})
|
||||||
course = await courses.find_one({"course_id": course_id})
|
course = await courses.find_one({"course_id": course_id})
|
||||||
|
|
||||||
if not course:
|
if not course:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist")
|
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
hasRoleRights = await verify_user_rights_with_roles(request, action, current_user.user_id, course_id, course["org_id"])
|
if action == "read":
|
||||||
isAuthor = current_user.user_id in course["authors"]
|
if current_user.user_id == "anonymous":
|
||||||
|
await authorization_verify_if_element_is_public(
|
||||||
|
request, course_id, current_user.user_id, action
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
users = request.app.db["users"]
|
||||||
|
user = await users.find_one({"user_id": current_user.user_id})
|
||||||
|
|
||||||
if not hasRoleRights and not isAuthor:
|
await authorization_verify_based_on_roles_and_authorship(
|
||||||
raise HTTPException(
|
request,
|
||||||
status_code=status.HTTP_403_FORBIDDEN, detail="Roles/Ownership : Insufficient rights to perform this action")
|
current_user.user_id,
|
||||||
|
action,
|
||||||
|
user["roles"],
|
||||||
|
course_id,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
users = request.app.db["users"]
|
||||||
|
user = await users.find_one({"user_id": current_user.user_id})
|
||||||
|
|
||||||
|
await authorization_verify_based_on_roles_and_authorship(
|
||||||
|
request,
|
||||||
|
current_user.user_id,
|
||||||
|
action,
|
||||||
|
user["roles"],
|
||||||
|
course_id,
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
#### Security ####################################################
|
#### Security ####################################################
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
from typing import List
|
from typing import List, Literal
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
from src.security.rbac.rbac import authorization_verify_based_on_roles_and_authorship
|
||||||
from src.services.users.users import PublicUser
|
from src.services.users.users import PublicUser
|
||||||
from src.security.security import verify_user_rights_with_roles
|
|
||||||
from fastapi import HTTPException, status, Request
|
from fastapi import HTTPException, status, Request
|
||||||
|
|
||||||
#### Classes ####################################################
|
#### Classes ####################################################
|
||||||
|
|
@ -12,11 +12,13 @@ class Collection(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
description: str
|
description: str
|
||||||
courses: List[str] # course_id
|
courses: List[str] # course_id
|
||||||
|
public: bool
|
||||||
org_id: str # org_id
|
org_id: str # org_id
|
||||||
|
|
||||||
|
|
||||||
class CollectionInDB(Collection):
|
class CollectionInDB(Collection):
|
||||||
collection_id: str
|
collection_id: str
|
||||||
|
authors: List[str] # user_id
|
||||||
|
|
||||||
|
|
||||||
#### Classes ####################################################
|
#### Classes ####################################################
|
||||||
|
|
@ -81,7 +83,11 @@ async def create_collection(
|
||||||
# generate collection_id with uuid4
|
# generate collection_id with uuid4
|
||||||
collection_id = str(f"collection_{uuid4()}")
|
collection_id = str(f"collection_{uuid4()}")
|
||||||
|
|
||||||
collection = CollectionInDB(collection_id=collection_id, **collection_object.dict())
|
collection = CollectionInDB(
|
||||||
|
collection_id=collection_id,
|
||||||
|
authors=[current_user.user_id],
|
||||||
|
**collection_object.dict(),
|
||||||
|
)
|
||||||
|
|
||||||
collection_in_db = await collections.insert_one(collection.dict())
|
collection_in_db = await collections.insert_one(collection.dict())
|
||||||
|
|
||||||
|
|
@ -169,6 +175,11 @@ async def get_collections(
|
||||||
|
|
||||||
print(org_id)
|
print(org_id)
|
||||||
|
|
||||||
|
if current_user.user_id == "anonymous":
|
||||||
|
all_collections = collections.find(
|
||||||
|
{"org_id": org_id, "public": True}, {"_id": 0}
|
||||||
|
)
|
||||||
|
else:
|
||||||
# get all collections from database without ObjectId
|
# get all collections from database without ObjectId
|
||||||
all_collections = (
|
all_collections = (
|
||||||
collections.find({"org_id": org_id})
|
collections.find({"org_id": org_id})
|
||||||
|
|
@ -177,8 +188,6 @@ async def get_collections(
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
)
|
)
|
||||||
|
|
||||||
await verify_collection_rights(request, "*", current_user, "read", org_id)
|
|
||||||
|
|
||||||
# create list of collections and include courses in each collection
|
# create list of collections and include courses in each collection
|
||||||
collections_list = []
|
collections_list = []
|
||||||
for collection in await all_collections.to_list(length=100):
|
for collection in await all_collections.to_list(length=100):
|
||||||
|
|
@ -207,11 +216,12 @@ async def verify_collection_rights(
|
||||||
request: Request,
|
request: Request,
|
||||||
collection_id: str,
|
collection_id: str,
|
||||||
current_user: PublicUser,
|
current_user: PublicUser,
|
||||||
action: str,
|
action: Literal["create", "read", "update", "delete"],
|
||||||
org_id: str,
|
org_id: str,
|
||||||
):
|
):
|
||||||
collections = request.app.db["collections"]
|
collections = request.app.db["collections"]
|
||||||
|
users = request.app.db["users"]
|
||||||
|
user = await users.find_one({"user_id": current_user.user_id})
|
||||||
collection = await collections.find_one({"collection_id": collection_id})
|
collection = await collections.find_one({"collection_id": collection_id})
|
||||||
|
|
||||||
if not collection and action != "create" and collection_id != "*":
|
if not collection and action != "create" and collection_id != "*":
|
||||||
|
|
@ -223,17 +233,9 @@ async def verify_collection_rights(
|
||||||
if current_user.user_id == "anonymous" and action == "read":
|
if current_user.user_id == "anonymous" and action == "read":
|
||||||
return True
|
return True
|
||||||
|
|
||||||
hasRoleRights = await verify_user_rights_with_roles(
|
await authorization_verify_based_on_roles_and_authorship(
|
||||||
request, action, current_user.user_id, collection_id, org_id
|
request, current_user.user_id, action, user["roles"], collection_id
|
||||||
)
|
)
|
||||||
|
|
||||||
if not hasRoleRights:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
detail="You do not have rights to this Collection",
|
|
||||||
)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
#### Security ####################################################
|
#### Security ####################################################
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
import json
|
import json
|
||||||
from typing import List, Optional
|
from typing import List, Literal, Optional
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
from src.security.rbac.rbac import (
|
||||||
|
authorization_verify_based_on_roles,
|
||||||
|
authorization_verify_based_on_roles_and_authorship,
|
||||||
|
authorization_verify_if_element_is_public,
|
||||||
|
)
|
||||||
from src.services.courses.activities.activities import ActivityInDB
|
from src.services.courses.activities.activities import ActivityInDB
|
||||||
from src.services.courses.thumbnails import upload_thumbnail
|
from src.services.courses.thumbnails import upload_thumbnail
|
||||||
from src.services.users.schemas.users import AnonymousUser
|
from src.services.users.schemas.users import AnonymousUser
|
||||||
from src.services.users.users import PublicUser
|
from src.services.users.users import PublicUser
|
||||||
from src.security.security import verify_user_rights_with_roles
|
|
||||||
from fastapi import HTTPException, Request, status, UploadFile
|
from fastapi import HTTPException, Request, status, UploadFile
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
@ -144,7 +148,6 @@ async def get_course_meta(request: Request, course_id: str, current_user: Public
|
||||||
trail = await trails.find_one(
|
trail = await trails.find_one(
|
||||||
{"courses.course_id": course_id, "user_id": current_user.user_id}
|
{"courses.course_id": course_id, "user_id": current_user.user_id}
|
||||||
)
|
)
|
||||||
print(trail)
|
|
||||||
if trail:
|
if trail:
|
||||||
# get only the course where course_id == course_id
|
# get only the course where course_id == course_id
|
||||||
trail_course = next(
|
trail_course = next(
|
||||||
|
|
@ -169,6 +172,8 @@ async def create_course(
|
||||||
thumbnail_file: UploadFile | None = None,
|
thumbnail_file: UploadFile | None = None,
|
||||||
):
|
):
|
||||||
courses = request.app.db["courses"]
|
courses = request.app.db["courses"]
|
||||||
|
users = request.app.db["users"]
|
||||||
|
user = await users.find_one({"user_id": current_user.user_id})
|
||||||
|
|
||||||
# generate course_id with uuid4
|
# generate course_id with uuid4
|
||||||
course_id = str(f"course_{uuid4()}")
|
course_id = str(f"course_{uuid4()}")
|
||||||
|
|
@ -176,10 +181,16 @@ async def create_course(
|
||||||
# TODO(fix) : the implementation here is clearly not the best one (this entire function)
|
# TODO(fix) : the implementation here is clearly not the best one (this entire function)
|
||||||
course_object.org_id = org_id
|
course_object.org_id = org_id
|
||||||
course_object.chapters_content = []
|
course_object.chapters_content = []
|
||||||
await verify_user_rights_with_roles(
|
|
||||||
request, "create", current_user.user_id, course_id, org_id
|
await authorization_verify_based_on_roles(
|
||||||
|
request,
|
||||||
|
current_user.user_id,
|
||||||
|
"create",
|
||||||
|
user["roles"],
|
||||||
|
course_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if thumbnail_file and thumbnail_file.filename:
|
if thumbnail_file and thumbnail_file.filename:
|
||||||
name_in_disk = (
|
name_in_disk = (
|
||||||
f"{course_id}_thumbnail_{uuid4()}.{thumbnail_file.filename.split('.')[-1]}"
|
f"{course_id}_thumbnail_{uuid4()}.{thumbnail_file.filename.split('.')[-1]}"
|
||||||
|
|
@ -214,12 +225,13 @@ async def update_course_thumbnail(
|
||||||
current_user: PublicUser,
|
current_user: PublicUser,
|
||||||
thumbnail_file: UploadFile | None = None,
|
thumbnail_file: UploadFile | None = None,
|
||||||
):
|
):
|
||||||
# verify course rights
|
|
||||||
await verify_rights(request, course_id, current_user, "update")
|
|
||||||
|
|
||||||
courses = request.app.db["courses"]
|
courses = request.app.db["courses"]
|
||||||
|
|
||||||
course = await courses.find_one({"course_id": course_id})
|
course = await courses.find_one({"course_id": course_id})
|
||||||
|
|
||||||
|
# verify course rights
|
||||||
|
await verify_rights(request, course_id, current_user, "update")
|
||||||
|
|
||||||
# TODO(fix) : the implementation here is clearly not the best one
|
# TODO(fix) : the implementation here is clearly not the best one
|
||||||
if course:
|
if course:
|
||||||
creationDate = course["creationDate"]
|
creationDate = course["creationDate"]
|
||||||
|
|
@ -254,13 +266,13 @@ async def update_course_thumbnail(
|
||||||
async def update_course(
|
async def update_course(
|
||||||
request: Request, course_object: Course, course_id: str, current_user: PublicUser
|
request: Request, course_object: Course, course_id: str, current_user: PublicUser
|
||||||
):
|
):
|
||||||
# verify course rights
|
|
||||||
await verify_rights(request, course_id, current_user, "update")
|
|
||||||
|
|
||||||
courses = request.app.db["courses"]
|
courses = request.app.db["courses"]
|
||||||
|
|
||||||
course = await courses.find_one({"course_id": course_id})
|
course = await courses.find_one({"course_id": course_id})
|
||||||
|
|
||||||
|
# verify course rights
|
||||||
|
await verify_rights(request, course_id, current_user, "update")
|
||||||
|
|
||||||
if course:
|
if course:
|
||||||
creationDate = course["creationDate"]
|
creationDate = course["creationDate"]
|
||||||
authors = course["authors"]
|
authors = course["authors"]
|
||||||
|
|
@ -289,13 +301,13 @@ async def update_course(
|
||||||
|
|
||||||
|
|
||||||
async def delete_course(request: Request, course_id: str, current_user: PublicUser):
|
async def delete_course(request: Request, course_id: str, current_user: PublicUser):
|
||||||
# verify course rights
|
|
||||||
await verify_rights(request, course_id, current_user, "delete")
|
|
||||||
|
|
||||||
courses = request.app.db["courses"]
|
courses = request.app.db["courses"]
|
||||||
|
|
||||||
course = await courses.find_one({"course_id": course_id})
|
course = await courses.find_one({"course_id": course_id})
|
||||||
|
|
||||||
|
# verify course rights
|
||||||
|
await verify_rights(request, course_id, current_user, "delete")
|
||||||
|
|
||||||
if not course:
|
if not course:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist"
|
status_code=status.HTTP_409_CONFLICT, detail="Course does not exist"
|
||||||
|
|
@ -364,41 +376,35 @@ async def verify_rights(
|
||||||
request: Request,
|
request: Request,
|
||||||
course_id: str,
|
course_id: str,
|
||||||
current_user: PublicUser | AnonymousUser,
|
current_user: PublicUser | AnonymousUser,
|
||||||
action: str,
|
action: Literal["create", "read", "update", "delete"],
|
||||||
):
|
):
|
||||||
courses = request.app.db["courses"]
|
if action == "read":
|
||||||
|
if current_user.user_id == "anonymous":
|
||||||
course = await courses.find_one({"course_id": course_id})
|
await authorization_verify_if_element_is_public(
|
||||||
|
request, course_id, current_user.user_id, action
|
||||||
isAuthor = current_user.user_id in course["authors"]
|
|
||||||
|
|
||||||
if isAuthor:
|
|
||||||
return True
|
|
||||||
|
|
||||||
if (
|
|
||||||
current_user.user_id == "anonymous"
|
|
||||||
and course["public"] is True
|
|
||||||
and action == "read"
|
|
||||||
):
|
|
||||||
return True
|
|
||||||
|
|
||||||
if not course:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_409_CONFLICT,
|
|
||||||
detail="Course/CourseChapter does not exist",
|
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
users = request.app.db["users"]
|
||||||
|
user = await users.find_one({"user_id": current_user.user_id})
|
||||||
|
|
||||||
hasRoleRights = await verify_user_rights_with_roles(
|
await authorization_verify_based_on_roles_and_authorship(
|
||||||
request, action, current_user.user_id, course_id, course["org_id"]
|
request,
|
||||||
|
current_user.user_id,
|
||||||
|
action,
|
||||||
|
user["roles"],
|
||||||
|
course_id,
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
users = request.app.db["users"]
|
||||||
|
user = await users.find_one({"user_id": current_user.user_id})
|
||||||
|
|
||||||
if not hasRoleRights and not isAuthor:
|
await authorization_verify_based_on_roles_and_authorship(
|
||||||
raise HTTPException(
|
request,
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
current_user.user_id,
|
||||||
detail="Roles/Ownership : Insufficient rights to perform this action",
|
action,
|
||||||
|
user["roles"],
|
||||||
|
course_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
#### Security ####################################################
|
#### Security ####################################################
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import json
|
import json
|
||||||
|
from typing import Literal
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
from src.security.rbac.rbac import authorization_verify_based_on_roles
|
||||||
from src.services.orgs.logos import upload_org_logo
|
from src.services.orgs.logos import upload_org_logo
|
||||||
from src.services.orgs.schemas.orgs import (
|
from src.services.orgs.schemas.orgs import (
|
||||||
Organization,
|
Organization,
|
||||||
|
|
@ -8,7 +10,6 @@ from src.services.orgs.schemas.orgs import (
|
||||||
)
|
)
|
||||||
from src.services.users.schemas.users import UserOrganization
|
from src.services.users.schemas.users import UserOrganization
|
||||||
from src.services.users.users import PublicUser
|
from src.services.users.users import PublicUser
|
||||||
from src.security.security import verify_user_rights_with_roles
|
|
||||||
from fastapi import HTTPException, UploadFile, status, Request
|
from fastapi import HTTPException, UploadFile, status, Request
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -197,9 +198,12 @@ async def verify_org_rights(
|
||||||
request: Request,
|
request: Request,
|
||||||
org_id: str,
|
org_id: str,
|
||||||
current_user: PublicUser,
|
current_user: PublicUser,
|
||||||
action: str,
|
action: Literal["create", "read", "update", "delete"],
|
||||||
):
|
):
|
||||||
orgs = request.app.db["organizations"]
|
orgs = request.app.db["organizations"]
|
||||||
|
users = request.app.db["users"]
|
||||||
|
|
||||||
|
user = await users.find_one({"user_id": current_user.user_id})
|
||||||
|
|
||||||
org = await orgs.find_one({"org_id": org_id})
|
org = await orgs.find_one({"org_id": org_id})
|
||||||
|
|
||||||
|
|
@ -208,17 +212,9 @@ async def verify_org_rights(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="Organization does not exist"
|
status_code=status.HTTP_409_CONFLICT, detail="Organization does not exist"
|
||||||
)
|
)
|
||||||
|
|
||||||
hasRoleRights = await verify_user_rights_with_roles(
|
await authorization_verify_based_on_roles(
|
||||||
request, action, current_user.user_id, org_id, org_id
|
request, current_user.user_id, action, user["roles"], org_id
|
||||||
)
|
)
|
||||||
|
|
||||||
if not hasRoleRights:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
detail="You do not have rights to this organization",
|
|
||||||
)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
#### Security ####################################################
|
#### Security ####################################################
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,9 @@ class UserInDB(User):
|
||||||
creation_date: str
|
creation_date: str
|
||||||
update_date: str
|
update_date: str
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
return getattr(self, item)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,39 @@ from datetime import datetime
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from fastapi import HTTPException, Request, status
|
from fastapi import HTTPException, Request, status
|
||||||
|
from src.security.rbac.rbac import authorization_verify_based_on_roles
|
||||||
from src.security.security import security_hash_password, security_verify_password
|
from src.security.security import security_hash_password, security_verify_password
|
||||||
from src.services.users.schemas.users import PasswordChangeForm, PublicUser, User, UserOrganization, UserRolesInOrganization, UserWithPassword, UserInDB
|
from src.services.users.schemas.users import (
|
||||||
|
PasswordChangeForm,
|
||||||
|
PublicUser,
|
||||||
|
User,
|
||||||
|
UserOrganization,
|
||||||
|
UserRolesInOrganization,
|
||||||
|
UserWithPassword,
|
||||||
|
UserInDB,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def create_user(request: Request, current_user: PublicUser | None, user_object: UserWithPassword, org_slug: str):
|
async def create_user(
|
||||||
|
request: Request,
|
||||||
|
current_user: PublicUser | None,
|
||||||
|
user_object: UserWithPassword,
|
||||||
|
org_slug: str,
|
||||||
|
):
|
||||||
users = request.app.db["users"]
|
users = request.app.db["users"]
|
||||||
|
|
||||||
isUsernameAvailable = await users.find_one({"username": user_object.username})
|
isUsernameAvailable = await users.find_one({"username": user_object.username})
|
||||||
isEmailAvailable = await users.find_one({"email": user_object.email})
|
isEmailAvailable = await users.find_one({"email": user_object.email})
|
||||||
|
|
||||||
|
|
||||||
if isUsernameAvailable:
|
if isUsernameAvailable:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="Username already exists")
|
status_code=status.HTTP_409_CONFLICT, detail="Username already exists"
|
||||||
|
)
|
||||||
|
|
||||||
if isEmailAvailable:
|
if isEmailAvailable:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="Email already exists")
|
status_code=status.HTTP_409_CONFLICT, detail="Email already exists"
|
||||||
|
)
|
||||||
|
|
||||||
# Generate user_id with uuid4
|
# Generate user_id with uuid4
|
||||||
user_id = str(f"user_{uuid4()}")
|
user_id = str(f"user_{uuid4()}")
|
||||||
|
|
@ -42,11 +57,12 @@ async def create_user(request: Request, current_user: PublicUser | None, user_o
|
||||||
# If the org does not exist, raise an error
|
# If the org does not exist, raise an error
|
||||||
if not isOrgExists:
|
if not isOrgExists:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="You are trying to create a user in an organization that does not exist")
|
status_code=status.HTTP_409_CONFLICT,
|
||||||
|
detail="You are trying to create a user in an organization that does not exist",
|
||||||
|
)
|
||||||
|
|
||||||
org_id = isOrgExists["org_id"]
|
org_id = isOrgExists["org_id"]
|
||||||
|
|
||||||
|
|
||||||
# Create initial orgs list with the org_id passed in
|
# Create initial orgs list with the org_id passed in
|
||||||
orgs = [UserOrganization(org_id=org_id, org_role="member")]
|
orgs = [UserOrganization(org_id=org_id, org_role="member")]
|
||||||
|
|
||||||
|
|
@ -54,8 +70,14 @@ async def create_user(request: Request, current_user: PublicUser | None, user_o
|
||||||
roles = [UserRolesInOrganization(role_id="role_member", org_id=org_id)]
|
roles = [UserRolesInOrganization(role_id="role_member", org_id=org_id)]
|
||||||
|
|
||||||
# Create the user
|
# Create the user
|
||||||
user = UserInDB(user_id=user_id, creation_date=str(datetime.now()),
|
user = UserInDB(
|
||||||
update_date=str(datetime.now()), orgs=orgs, roles=roles, **user_object.dict())
|
user_id=user_id,
|
||||||
|
creation_date=str(datetime.now()),
|
||||||
|
update_date=str(datetime.now()),
|
||||||
|
orgs=orgs,
|
||||||
|
roles=roles,
|
||||||
|
**user_object.dict(),
|
||||||
|
)
|
||||||
|
|
||||||
# Insert the user into the database
|
# Insert the user into the database
|
||||||
await users.insert_one(user.dict())
|
await users.insert_one(user.dict())
|
||||||
|
|
@ -75,12 +97,15 @@ async def read_user(request: Request, current_user: PublicUser, user_id: str):
|
||||||
# If the user does not exist, raise an error
|
# If the user does not exist, raise an error
|
||||||
if not isUserExists:
|
if not isUserExists:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="User does not exist")
|
status_code=status.HTTP_409_CONFLICT, detail="User does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
return User(**isUserExists)
|
return User(**isUserExists)
|
||||||
|
|
||||||
|
|
||||||
async def update_user(request: Request, user_id: str, user_object: User,current_user: PublicUser):
|
async def update_user(
|
||||||
|
request: Request, user_id: str, user_object: User, current_user: PublicUser
|
||||||
|
):
|
||||||
users = request.app.db["users"]
|
users = request.app.db["users"]
|
||||||
|
|
||||||
# Verify rights
|
# Verify rights
|
||||||
|
|
@ -92,7 +117,8 @@ async def update_user(request: Request, user_id: str, user_object: User,current
|
||||||
|
|
||||||
if not isUserExists:
|
if not isUserExists:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="User does not exist")
|
status_code=status.HTTP_409_CONFLICT, detail="User does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
# okay if username is not changed
|
# okay if username is not changed
|
||||||
if isUserExists["username"] == user_object.username:
|
if isUserExists["username"] == user_object.username:
|
||||||
|
|
@ -101,11 +127,13 @@ async def update_user(request: Request, user_id: str, user_object: User,current
|
||||||
else:
|
else:
|
||||||
if isUsernameAvailable:
|
if isUsernameAvailable:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="Username already used")
|
status_code=status.HTTP_409_CONFLICT, detail="Username already used"
|
||||||
|
)
|
||||||
|
|
||||||
if isEmailAvailable:
|
if isEmailAvailable:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="Email already used")
|
status_code=status.HTTP_409_CONFLICT, detail="Email already used"
|
||||||
|
)
|
||||||
|
|
||||||
updated_user = {"$set": user_object.dict()}
|
updated_user = {"$set": user_object.dict()}
|
||||||
users.update_one({"user_id": user_id}, updated_user)
|
users.update_one({"user_id": user_id}, updated_user)
|
||||||
|
|
@ -113,8 +141,12 @@ async def update_user(request: Request, user_id: str, user_object: User,current
|
||||||
return User(**user_object.dict())
|
return User(**user_object.dict())
|
||||||
|
|
||||||
|
|
||||||
|
async def update_user_password(
|
||||||
async def update_user_password(request: Request, current_user: PublicUser, user_id: str, password_change_form: PasswordChangeForm):
|
request: Request,
|
||||||
|
current_user: PublicUser,
|
||||||
|
user_id: str,
|
||||||
|
password_change_form: PasswordChangeForm,
|
||||||
|
):
|
||||||
users = request.app.db["users"]
|
users = request.app.db["users"]
|
||||||
|
|
||||||
isUserExists = await users.find_one({"user_id": user_id})
|
isUserExists = await users.find_one({"user_id": user_id})
|
||||||
|
|
@ -124,11 +156,15 @@ async def update_user_password(request: Request, current_user: PublicUser, user_
|
||||||
|
|
||||||
if not isUserExists:
|
if not isUserExists:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="User does not exist")
|
status_code=status.HTTP_409_CONFLICT, detail="User does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
if not await security_verify_password(password_change_form.old_password, isUserExists["password"]):
|
if not await security_verify_password(
|
||||||
|
password_change_form.old_password, isUserExists["password"]
|
||||||
|
):
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED, detail="Wrong password")
|
status_code=status.HTTP_401_UNAUTHORIZED, detail="Wrong password"
|
||||||
|
)
|
||||||
|
|
||||||
new_password = await security_hash_password(password_change_form.new_password)
|
new_password = await security_hash_password(password_change_form.new_password)
|
||||||
|
|
||||||
|
|
@ -148,7 +184,8 @@ async def delete_user(request: Request, current_user: PublicUser, user_id: str):
|
||||||
|
|
||||||
if not isUserExists:
|
if not isUserExists:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="User does not exist")
|
status_code=status.HTTP_409_CONFLICT, detail="User does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
await users.delete_one({"user_id": user_id})
|
await users.delete_one({"user_id": user_id})
|
||||||
|
|
||||||
|
|
@ -157,18 +194,21 @@ async def delete_user(request: Request, current_user: PublicUser, user_id: str):
|
||||||
|
|
||||||
# Utils & Security functions
|
# Utils & Security functions
|
||||||
|
|
||||||
|
|
||||||
async def security_get_user(request: Request, email: str):
|
async def security_get_user(request: Request, email: str):
|
||||||
users = request.app.db["users"]
|
users = request.app.db["users"]
|
||||||
|
|
||||||
|
|
||||||
user = await users.find_one({"email": email})
|
user = await users.find_one({"email": email})
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="User with Email does not exist")
|
status_code=status.HTTP_409_CONFLICT,
|
||||||
|
detail="User with Email does not exist",
|
||||||
|
)
|
||||||
|
|
||||||
return UserInDB(**user)
|
return UserInDB(**user)
|
||||||
|
|
||||||
|
|
||||||
async def get_userid_by_username(request: Request, username: str):
|
async def get_userid_by_username(request: Request, username: str):
|
||||||
users = request.app.db["users"]
|
users = request.app.db["users"]
|
||||||
|
|
||||||
|
|
@ -176,10 +216,12 @@ async def get_userid_by_username(request: Request, username: str):
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="User does not exist")
|
status_code=status.HTTP_409_CONFLICT, detail="User does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
return user["user_id"]
|
return user["user_id"]
|
||||||
|
|
||||||
|
|
||||||
async def get_user_by_userid(request: Request, user_id: str):
|
async def get_user_by_userid(request: Request, user_id: str):
|
||||||
users = request.app.db["users"]
|
users = request.app.db["users"]
|
||||||
|
|
||||||
|
|
@ -187,32 +229,36 @@ async def get_user_by_userid(request: Request, user_id: str):
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="User does not exist")
|
status_code=status.HTTP_409_CONFLICT, detail="User does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
user = User(**user)
|
user = User(**user)
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
async def get_profile_metadata(request: Request, user):
|
async def get_profile_metadata(request: Request, user):
|
||||||
users = request.app.db["users"]
|
users = request.app.db["users"]
|
||||||
request.app.db["roles"]
|
request.app.db["roles"]
|
||||||
|
|
||||||
user = await users.find_one({"user_id": user['user_id']})
|
user = await users.find_one({"user_id": user["user_id"]})
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_409_CONFLICT, detail="User does not exist")
|
status_code=status.HTTP_409_CONFLICT, detail="User does not exist"
|
||||||
|
)
|
||||||
|
|
||||||
|
return {"user_object": PublicUser(**user), "roles": "random"}
|
||||||
|
|
||||||
return {
|
|
||||||
"user_object": PublicUser(**user),
|
|
||||||
"roles": "random"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Verification of the user's permissions on the roles
|
# Verification of the user's permissions on the roles
|
||||||
|
|
||||||
async def verify_user_rights_on_user(request: Request, current_user: PublicUser, action: Literal["create", "read", "update", "delete"], user_id: str):
|
|
||||||
|
async def verify_user_rights_on_user(
|
||||||
|
request: Request,
|
||||||
|
current_user: PublicUser,
|
||||||
|
action: Literal["create", "read", "update", "delete"],
|
||||||
|
user_id: str,
|
||||||
|
):
|
||||||
users = request.app.db["users"]
|
users = request.app.db["users"]
|
||||||
user = UserInDB(**await users.find_one({"user_id": user_id}))
|
user = UserInDB(**await users.find_one({"user_id": user_id}))
|
||||||
|
|
||||||
|
|
@ -235,11 +281,12 @@ async def verify_user_rights_on_user(request: Request, current_user: PublicUser,
|
||||||
|
|
||||||
for org in current_user.orgs:
|
for org in current_user.orgs:
|
||||||
if org.org_id in [org.org_id for org in user.orgs]:
|
if org.org_id in [org.org_id for org in user.orgs]:
|
||||||
|
|
||||||
if org.org_role == "owner":
|
if org.org_role == "owner":
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# TODO: Verify user roles on the org
|
await authorization_verify_based_on_roles(
|
||||||
|
request, current_user.user_id, "update", user["roles"], user_id
|
||||||
|
)
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
@ -249,8 +296,9 @@ async def verify_user_rights_on_user(request: Request, current_user: PublicUser,
|
||||||
|
|
||||||
for org in current_user.orgs:
|
for org in current_user.orgs:
|
||||||
if org.org_id in [org.org_id for org in user.orgs]:
|
if org.org_id in [org.org_id for org in user.orgs]:
|
||||||
|
|
||||||
if org.org_role == "owner":
|
if org.org_role == "owner":
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# TODO: Verify user roles on the org
|
await authorization_verify_based_on_roles(
|
||||||
|
request, current_user.user_id, "update", user["roles"], user_id
|
||||||
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue