Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write RoleAssignment.get_permissions_per_folder classmethod #962

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions backend/iam/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,15 @@ def get_folder(obj: Any):
# If no folder is found after trying all paths, handle this case (e.g., return None or raise an error).
return None

def tree(self):
"""Return the tree structure of the folder"""
tree = {}
tree[str(self.id)] = {
"name": self.name,
"children": [f.tree() for f in self.folder_set.all()],
}
return tree


class FolderMixin(models.Model):
"""
Expand Down Expand Up @@ -773,3 +782,47 @@ def has_role(user: AbstractBaseUser | AnonymousUser, role: Role):
if ra.role == role:
return True
return False

@classmethod
def get_permissions_per_folder(
cls, principal: AbstractBaseUser | AnonymousUser | UserGroup, recursive=False
):
"""
Get all permissions attached to a user directly or indirectly, grouped by folder.
If recursive is set to True, permissions from recursive role assignments are transmitted
to the children of its perimeter folders.
"""
permissions = defaultdict(set)
for ra in cls.get_role_assignments(principal):
for folder in ra.perimeter_folders.all():
permissions[str(folder.id)] |= set(
ra.role.permissions.all().values_list("codename", flat=True)
)
if recursive and ra.is_recursive:
for f in folder.sub_folders():
permissions[str(f.id)] |= set(
ra.role.permissions.all().values_list("codename", flat=True)
)
return permissions

@classmethod
def get_permission_folder_tree(
cls, principal: AbstractBaseUser | AnonymousUser | UserGroup
):
def recurse(folder, permissions):
id = list(folder.keys())[0]
_folder = folder[list(folder.keys())[0]]
return {
id: {
"name": _folder["name"],
"permissions": permissions.get(id, []),
"children": [recurse(f, permissions) for f in _folder["children"]],
}
}

folder_tree = Folder.get_root_folder().tree()
permissions = cls.get_permissions_per_folder(principal, recursive=True)
for folder_id, folder in folder_tree.items():
folder["permissions"] = permissions.get(folder_id, [])
folder["children"] = [recurse(f, permissions) for f in folder["children"]]
return folder_tree
3 changes: 2 additions & 1 deletion backend/iam/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
ResetPasswordConfirmSerializer,
)

from .models import Role, RoleAssignment
from .models import Folder, Role, RoleAssignment

import structlog

Expand Down Expand Up @@ -77,6 +77,7 @@ def get(self, request) -> Response:
"user_groups": request.user.get_user_groups(),
"roles": request.user.get_roles(),
"permissions": request.user.permissions,
"folders": RoleAssignment.get_permission_folder_tree(request.user),
"is_third_party": request.user.is_third_party,
"is_admin": request.user.is_admin(),
}
Expand Down
Loading