mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: roles init
This commit is contained in:
parent
a50fc67104
commit
aa0eda5682
5 changed files with 113 additions and 109 deletions
|
|
@ -19,12 +19,18 @@ class RoleBase(SQLModel):
|
||||||
class Role(RoleBase, table=True):
|
class Role(RoleBase, table=True):
|
||||||
id: Optional[int] = Field(default=None, primary_key=True)
|
id: Optional[int] = Field(default=None, primary_key=True)
|
||||||
org_id: int = Field(default=None, foreign_key="organization.id")
|
org_id: int = Field(default=None, foreign_key="organization.id")
|
||||||
role_type: RoleTypeEnum = RoleTypeEnum.GLOBAL
|
role_type: RoleTypeEnum = RoleTypeEnum.ORGANIZATION
|
||||||
role_uuid: str
|
role_uuid: str = ""
|
||||||
creation_date: str
|
creation_date: str = ""
|
||||||
update_date: str
|
update_date: str = ""
|
||||||
|
|
||||||
|
|
||||||
class RoleCreate(RoleBase):
|
class RoleCreate(RoleBase):
|
||||||
org_id: int = Field(default=None, foreign_key="organization.id")
|
org_id: int = Field(default=None, foreign_key="organization.id")
|
||||||
pass
|
|
||||||
|
|
||||||
|
class RoleUpdate(SQLModel):
|
||||||
|
role_id: int = Field(default=None, foreign_key="role.id")
|
||||||
|
name: Optional[str] = ""
|
||||||
|
description: Optional[str] = ""
|
||||||
|
rights: Optional[dict] = Field(default={}, sa_column=Column(JSON))
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
from fastapi import APIRouter, Depends, Request
|
from fastapi import APIRouter, Depends, Request
|
||||||
|
from sqlmodel import Session
|
||||||
|
from src.core.events.database import get_db_session
|
||||||
|
from src.db.roles import RoleCreate, RoleUpdate
|
||||||
from src.security.auth import get_current_user
|
from src.security.auth import get_current_user
|
||||||
from src.services.roles.schemas.roles import Role
|
from src.services.roles.schemas.roles import Role
|
||||||
from src.services.roles.roles import create_role, delete_role, read_role, update_role
|
from src.services.roles.roles import create_role, delete_role, read_role, update_role
|
||||||
|
|
@ -9,33 +12,53 @@ router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
@router.post("/")
|
@router.post("/")
|
||||||
async def api_create_role(request: Request, role_object: Role, current_user: PublicUser = Depends(get_current_user)):
|
async def api_create_role(
|
||||||
|
request: Request,
|
||||||
|
role_object: RoleCreate,
|
||||||
|
current_user: PublicUser = Depends(get_current_user),
|
||||||
|
db_session: Session = Depends(get_db_session),
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Create new role
|
Create new role
|
||||||
"""
|
"""
|
||||||
return await create_role(request, role_object, current_user)
|
return await create_role(request, db_session, role_object, current_user)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{role_id}")
|
@router.get("/{role_id}")
|
||||||
async def api_get_role(request: Request, role_id: str, current_user: PublicUser = Depends(get_current_user)):
|
async def api_get_role(
|
||||||
|
request: Request,
|
||||||
|
role_id: str,
|
||||||
|
current_user: PublicUser = Depends(get_current_user),
|
||||||
|
db_session: Session = Depends(get_db_session),
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Get single role by role_id
|
Get single role by role_id
|
||||||
"""
|
"""
|
||||||
return await read_role(request, role_id, current_user)
|
return await read_role(request, db_session, role_id, current_user)
|
||||||
|
|
||||||
|
|
||||||
@router.put("/{role_id}")
|
@router.put("/{role_id}")
|
||||||
async def api_update_role(request: Request, role_object: Role, role_id: str, current_user: PublicUser = Depends(get_current_user)):
|
async def api_update_role(
|
||||||
|
request: Request,
|
||||||
|
role_object: RoleUpdate,
|
||||||
|
current_user: PublicUser = Depends(get_current_user),
|
||||||
|
db_session: Session = Depends(get_db_session),
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Update role by role_id
|
Update role by role_id
|
||||||
"""
|
"""
|
||||||
return await update_role(request, role_id, role_object, current_user)
|
return await update_role(request, db_session, role_object, current_user)
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/{role_id}")
|
@router.delete("/{role_id}")
|
||||||
async def api_delete_role(request: Request, 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),
|
||||||
|
db_session: Session = Depends(get_db_session),
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Delete role by ID
|
Delete role by ID
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return await delete_role(request, role_id, current_user)
|
return await delete_role(request, db_session, role_id, current_user)
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,6 @@ async def api_create_user_without_org(
|
||||||
request: Request,
|
request: Request,
|
||||||
db_session: Session = Depends(get_db_session),
|
db_session: Session = Depends(get_db_session),
|
||||||
user_object: UserCreate,
|
user_object: UserCreate,
|
||||||
org_id: int,
|
|
||||||
) -> UserRead:
|
) -> UserRead:
|
||||||
"""
|
"""
|
||||||
Create User
|
Create User
|
||||||
|
|
|
||||||
|
|
@ -1,127 +1,99 @@
|
||||||
from typing import Literal
|
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
from sqlmodel import Session, select
|
||||||
|
from src.db.roles import Role, RoleCreate, RoleUpdate
|
||||||
from src.security.rbac.rbac import authorization_verify_if_user_is_anon
|
from src.security.rbac.rbac import authorization_verify_if_user_is_anon
|
||||||
from src.services.roles.schemas.roles import Role, RoleInDB
|
|
||||||
from src.services.users.schemas.users import PublicUser
|
from src.services.users.schemas.users import PublicUser
|
||||||
from fastapi import HTTPException, status, Request
|
from fastapi import HTTPException, status, Request
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
async def create_role(request: Request, role_object: Role, current_user: PublicUser):
|
async def create_role(
|
||||||
roles = request.app.db["roles"]
|
request: Request,
|
||||||
|
db_session: Session,
|
||||||
|
role_object: RoleCreate,
|
||||||
|
current_user: PublicUser,
|
||||||
|
):
|
||||||
|
role = Role.from_orm(role_object)
|
||||||
|
|
||||||
await verify_user_permissions_on_roles(request, current_user, "create", None)
|
# Complete the role object
|
||||||
|
role.role_uuid = f"role_{uuid4()}"
|
||||||
|
role.creation_date = str(datetime.now())
|
||||||
|
role.update_date = str(datetime.now())
|
||||||
|
|
||||||
# create the role object in the database and return the object
|
db_session.add(role)
|
||||||
role_id = "role_" + str(uuid4())
|
db_session.commit()
|
||||||
|
db_session.refresh(role)
|
||||||
role = RoleInDB(
|
|
||||||
role_id=role_id,
|
|
||||||
created_at=str(datetime.now()),
|
|
||||||
updated_at=str(datetime.now()),
|
|
||||||
**role_object.dict()
|
|
||||||
)
|
|
||||||
|
|
||||||
await roles.insert_one(role.dict())
|
|
||||||
|
|
||||||
return role
|
return role
|
||||||
|
|
||||||
|
|
||||||
async def read_role(request: Request, role_id: str, current_user: PublicUser):
|
async def read_role(
|
||||||
roles = request.app.db["roles"]
|
request: Request, db_session: Session, role_id: str, current_user: PublicUser
|
||||||
|
):
|
||||||
|
statement = select(Role).where(Role.id == role_id)
|
||||||
|
result = db_session.exec(statement)
|
||||||
|
|
||||||
await verify_user_permissions_on_roles(request, current_user, "read", role_id)
|
role = result.first()
|
||||||
|
|
||||||
role = RoleInDB(**await roles.find_one({"role_id": role_id}))
|
if not role:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail="Role not found",
|
||||||
|
)
|
||||||
|
|
||||||
return role
|
return role
|
||||||
|
|
||||||
|
|
||||||
async def update_role(
|
async def update_role(
|
||||||
request: Request, role_id: str, role_object: Role, current_user: PublicUser
|
|
||||||
):
|
|
||||||
roles = request.app.db["roles"]
|
|
||||||
|
|
||||||
await verify_user_permissions_on_roles(request, current_user, "update", role_id)
|
|
||||||
|
|
||||||
role_object.updated_at = datetime.now()
|
|
||||||
|
|
||||||
# Update the role object in the database and return the object
|
|
||||||
updated_role = RoleInDB(
|
|
||||||
**await roles.find_one_and_update(
|
|
||||||
{"role_id": role_id}, {"$set": role_object.dict()}, return_document=True
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return updated_role
|
|
||||||
|
|
||||||
|
|
||||||
async def delete_role(request: Request, role_id: str, current_user: PublicUser):
|
|
||||||
roles = request.app.db["roles"]
|
|
||||||
|
|
||||||
await verify_user_permissions_on_roles(request, current_user, "delete", role_id)
|
|
||||||
|
|
||||||
# Delete the role object in the database and return the object
|
|
||||||
deleted_role = RoleInDB(**await roles.find_one_and_delete({"role_id": role_id}))
|
|
||||||
|
|
||||||
return deleted_role
|
|
||||||
|
|
||||||
|
|
||||||
#### Security ####################################################
|
|
||||||
|
|
||||||
|
|
||||||
async def verify_user_permissions_on_roles(
|
|
||||||
request: Request,
|
request: Request,
|
||||||
|
db_session: Session,
|
||||||
|
role_object: RoleUpdate,
|
||||||
current_user: PublicUser,
|
current_user: PublicUser,
|
||||||
action: Literal["create", "read", "update", "delete"],
|
|
||||||
role_id: str | None,
|
|
||||||
):
|
):
|
||||||
request.app.db["users"]
|
statement = select(Role).where(Role.id == role_object.role_id)
|
||||||
roles = request.app.db["roles"]
|
result = db_session.exec(statement)
|
||||||
|
|
||||||
# If current user is not authenticated
|
role = result.first()
|
||||||
|
|
||||||
if not current_user:
|
if not role:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED, detail="Roles : Not authenticated"
|
status_code=404,
|
||||||
|
detail="Role not found",
|
||||||
)
|
)
|
||||||
|
|
||||||
await authorization_verify_if_user_is_anon(current_user.user_id)
|
# Complete the role object
|
||||||
|
role.update_date = str(datetime.now())
|
||||||
|
|
||||||
if action == "create":
|
# Remove the role_id from the role_object
|
||||||
if "owner" in [org.org_role for org in current_user.orgs]:
|
del role_object.role_id
|
||||||
return True
|
|
||||||
|
|
||||||
if role_id is not None:
|
# Update only the fields that were passed in
|
||||||
role = RoleInDB(**await roles.find_one({"role_id": role_id}))
|
for var, value in vars(role_object).items():
|
||||||
|
if value is not None:
|
||||||
|
setattr(role, var, value)
|
||||||
|
|
||||||
if action == "read":
|
db_session.add(role)
|
||||||
if "owner" in [org.org_role for org in current_user.orgs]:
|
db_session.commit()
|
||||||
return True
|
db_session.refresh(role)
|
||||||
|
|
||||||
for org in current_user.orgs:
|
return role
|
||||||
if org.org_id == role.org_id:
|
|
||||||
return True
|
|
||||||
|
|
||||||
if action == "update":
|
|
||||||
for org in current_user.orgs:
|
|
||||||
# If the user is an owner of the organization
|
|
||||||
if org.org_id == role.org_id:
|
|
||||||
if org.org_role == "owner" or org.org_role == "editor":
|
|
||||||
return True
|
|
||||||
# Can't update a global role
|
|
||||||
if role.org_id == "*":
|
|
||||||
return False
|
|
||||||
|
|
||||||
if action == "delete":
|
|
||||||
for org in current_user.orgs:
|
|
||||||
# If the user is an owner of the organization
|
|
||||||
if org.org_id == role.org_id:
|
|
||||||
if org.org_role == "owner":
|
|
||||||
return True
|
|
||||||
# Can't delete a global role
|
|
||||||
if role.org_id == "*":
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
#### Security ####################################################
|
async def delete_role(
|
||||||
|
request: Request, db_session: Session, role_id: str, current_user: PublicUser
|
||||||
|
):
|
||||||
|
statement = select(Role).where(Role.id == role_id)
|
||||||
|
result = db_session.exec(statement)
|
||||||
|
|
||||||
|
role = result.first()
|
||||||
|
|
||||||
|
if not role:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail="Role not found",
|
||||||
|
)
|
||||||
|
|
||||||
|
db_session.delete(role)
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
return "Role deleted"
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,8 @@ async def update_user(
|
||||||
for key, value in user_data.items():
|
for key, value in user_data.items():
|
||||||
setattr(user, key, value)
|
setattr(user, key, value)
|
||||||
|
|
||||||
|
user.update_date = str(datetime.now())
|
||||||
|
|
||||||
# Update user in database
|
# Update user in database
|
||||||
db_session.add(user)
|
db_session.add(user)
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
|
|
@ -197,6 +199,8 @@ async def update_user_password(
|
||||||
|
|
||||||
# Update user
|
# Update user
|
||||||
user.password = await security_hash_password(form.new_password)
|
user.password = await security_hash_password(form.new_password)
|
||||||
|
user.update_date = str(datetime.now())
|
||||||
|
|
||||||
|
|
||||||
# Update user in database
|
# Update user in database
|
||||||
db_session.add(user)
|
db_session.add(user)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue