diff --git a/backend/app/api/deps.py b/backend/app/api/deps.py index 6177c71..ada5f24 100644 --- a/backend/app/api/deps.py +++ b/backend/app/api/deps.py @@ -61,7 +61,7 @@ def get_user_permissions( current_user: CurrentUser, rights: PermissionRight = None, ) -> User: - if not current_user.has_permission(module, part, rights): + if not current_user.has_permissions(module, part, rights): raise HTTPException( status_code=403, detail="The user doesn't have enough privileges" ) diff --git a/backend/app/api/routes/events.py b/backend/app/api/routes/events.py index 4d8c026..201b661 100644 --- a/backend/app/api/routes/events.py +++ b/backend/app/api/routes/events.py @@ -42,7 +42,7 @@ def read_events( Retrieve events. """ - if current_user.has_permission( + if current_user.has_permissions( module=PermissionModule.EVENT, part=PermissionPart.ADMIN, rights=PermissionRight.READ, @@ -84,7 +84,7 @@ def read_event(session: SessionDep, current_user: CurrentUser, id: RowId) -> Any if not event: raise HTTPException(status_code=404, detail="Event not found") - if not current_user.has_permission( + if not current_user.has_permissions( module=PermissionModule.EVENT, part=PermissionPart.ADMIN, rights=PermissionRight.READ, @@ -100,7 +100,7 @@ def create_event( """ Create new event. """ - if not current_user.has_permission( + if not current_user.has_permissions( module=PermissionModule.EVENT, part=PermissionPart.ADMIN, rights=PermissionRight.CREATE, @@ -127,7 +127,7 @@ def update_event( if not event: raise HTTPException(status_code=404, detail="Event not found") - if not current_user.has_permission( + if not current_user.has_permissions( module=PermissionModule.EVENT, part=PermissionPart.ADMIN, rights=PermissionRight.UPDATE, @@ -150,7 +150,7 @@ def delete_event( if not event: raise HTTPException(status_code=404, detail="Event not found") - if not current_user.has_permission( + if not current_user.has_permissions( module=PermissionModule.EVENT, part=PermissionPart.ADMIN, rights=PermissionRight.DELETE, @@ -183,7 +183,7 @@ def add_user_to_event( if not event: raise HTTPException(status_code=404, detail="Event not found") - if not current_user.has_permission( + if not current_user.has_permissions( module=PermissionModule.EVENT, part=PermissionPart.ADMIN, rights=PermissionRight.MANAGE_USERS, @@ -215,7 +215,7 @@ def remove_user_from_event( if not event: raise HTTPException(status_code=404, detail="Event not found") - if not current_user.has_permission( + if not current_user.has_permissions( module=PermissionModule.EVENT, part=PermissionPart.ADMIN, rights=PermissionRight.MANAGE_USERS, @@ -256,7 +256,7 @@ def read_event_teams( module=PermissionModule.EVENT, part=PermissionPart.ADMIN, rights=(PermissionRight.READ | PermissionRight.MANGE_TEAMS), - ) and ( event and (event.user_has_rights(user=current_user, rights=(PermissionRight.READ | PermissionRight.MANGE_TEAMS)))): + ) and ( event and (event.user_has_right(user=current_user, rights=(PermissionRight.READ | PermissionRight.MANGE_TEAMS)))): raise HTTPException(status_code=400, detail="Not enough permissions") # Get list @@ -287,7 +287,7 @@ def create_event_team( event = session.get(Event, id) - if not current_user.has_permission( + if not current_user.has_permissions( module=PermissionModule.EVENT, part=PermissionPart.ADMIN, rights=PermissionRight.MANGE_TEAMS, @@ -306,7 +306,7 @@ def read_event_teams( Retrieve all event teams. """ - if not current_user.has_permission( + if not current_user.has_permissions( module=PermissionModule.EVENT, part=PermissionPart.ADMIN, rights=PermissionRight.MANGE_TEAMS, @@ -340,7 +340,7 @@ def read_event_team(session: SessionDep, current_user: CurrentUser, id: RowId) - event = session.get(Event, event_team.event_id) - if not current_user.has_permission( + if not current_user.has_permissions( module=PermissionModule.EVENT, part=PermissionPart.ADMIN, rights=PermissionRight.MANGE_TEAMS, @@ -363,7 +363,7 @@ def create_event_team( event = session.get(Event, event_team.event_id) - if not current_user.has_permission( + if not current_user.has_permissions( module=PermissionModule.EVENT, part=PermissionPart.ADMIN, rights=PermissionRight.MANGE_TEAMS, @@ -385,7 +385,7 @@ def delete_event_team(session: SessionDep,current_user: CurrentUser, id: RowId) event = session.get(Event, event_team.event_id) - if not current_user.has_permission( + if not current_user.has_permissions( module=PermissionModule.EVENT, part=PermissionPart.ADMIN, rights=PermissionRight.MANGE_TEAMS, diff --git a/backend/app/api/routes/users.py b/backend/app/api/routes/users.py index f91e25b..6920a6c 100644 --- a/backend/app/api/routes/users.py +++ b/backend/app/api/routes/users.py @@ -200,7 +200,7 @@ def delete_user_me(session: SessionDep, current_user: CurrentUser) -> Any: """ Delete own user. """ - if current_user.has_permission( + if current_user.has_permissions( module=PermissionModule.SYSTEM, part=PermissionPart.ADMIN, rights=PermissionRight.DELETE, @@ -239,7 +239,7 @@ def read_user_by_id( user = session.get(User, user_id) if user == current_user: return user - if not current_user.has_permission( + if not current_user.has_permissions( module=PermissionModule.USER, part=PermissionPart.ADMIN, rights=PermissionRight.READ, diff --git a/backend/app/models/event.py b/backend/app/models/event.py index 1a0c6b5..da329c6 100644 --- a/backend/app/models/event.py +++ b/backend/app/models/event.py @@ -138,6 +138,9 @@ class Event(mixin.RowId, EventBase, table=True): user: User, rights: PermissionRight | None = None, ) -> bool: + """ + Check if all rights are present for the user + """ return any( ( link.user == user @@ -147,6 +150,23 @@ class Event(mixin.RowId, EventBase, table=True): for link in self.user_links ) + def user_has_right( + self, + user: User, + rights: PermissionRight | None = None, + ) -> bool: + """ + Check if at least one right is present for the user + """ + return any( + ( + link.user == user + and link.rights + and (not rights or (link.rights & rights)) + ) + for link in self.user_links + ) + # Properties to return via API, id is always required class EventPublic(mixin.RowIdPublic, EventBase): diff --git a/backend/app/models/user.py b/backend/app/models/user.py index 709f047..a41c8bc 100644 --- a/backend/app/models/user.py +++ b/backend/app/models/user.py @@ -207,12 +207,15 @@ class User(mixin.RowId, UserBase, table=True): return self - def has_permission( + def has_permissions( self, module: PermissionModule, part: PermissionPart, rights: PermissionRight | None = None, ) -> bool: + """ + Check if all rights are present for the user for the given permission + """ return any( any( ( @@ -227,6 +230,29 @@ class User(mixin.RowId, UserBase, table=True): for role in self.roles ) + def has_permission( + self, + module: PermissionModule, + part: PermissionPart, + rights: PermissionRight | None = None, + ) -> bool: + """ + Check if at least one right is present for the user for the given permission + """ + return any( + any( + ( + link.permission.module == module + and link.permission.part == part + and link.permission.is_active + and (not rights or (link.rights & rights)) + ) + for link in role.permission_links + if role.is_active + ) + for role in self.roles + ) + # Properties to return via API, id is always required class UserPublic(mixin.RowIdPublic, UserBase): diff --git a/backend/app/tests/crud/test_user.py b/backend/app/tests/crud/test_user.py index 4100407..596ce41 100644 --- a/backend/app/tests/crud/test_user.py +++ b/backend/app/tests/crud/test_user.py @@ -61,7 +61,7 @@ def test_check_if_user_is_superuser(db: Session) -> None: user = User.create(session=db, create_obj=user_in) user.add_role(name="Admin", session=db) assert ( - user.has_permission(module=PermissionModule.SYSTEM, part=PermissionPart.ADMIN) + user.has_permissions(module=PermissionModule.SYSTEM, part=PermissionPart.ADMIN) is True ) @@ -73,7 +73,7 @@ def test_check_if_user_is_superuser_normal_user(db: Session) -> None: user = User.create(session=db, create_obj=user_in) user.add_role(name="User", session=db) assert ( - user.has_permission(module=PermissionModule.SYSTEM, part=PermissionPart.ADMIN) + user.has_permissions(module=PermissionModule.SYSTEM, part=PermissionPart.ADMIN) is False )