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

feat: add utility method on SM for fetching all roles and perms for a user #1950

Merged
merged 2 commits into from
Nov 9, 2022
Merged
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
9 changes: 9 additions & 0 deletions flask_appbuilder/security/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1455,6 +1455,15 @@ def get_user_roles(self, user) -> List[object]:
return [self.get_public_role()]
return user.roles

def get_user_roles_permissions(self, user) -> Dict[str, List[Tuple[str, str]]]:
"""
Utility method just implemented for SQLAlchemy.
Take a look to: flask_appbuilder.security.sqla.manager
:param user:
:return:
"""
raise NotImplementedError()

def get_role_permissions(self, role) -> Set[Tuple[str, str]]:
"""
Get all permissions for a certain role
Expand Down
53 changes: 52 additions & 1 deletion flask_appbuilder/security/sqla/manager.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from datetime import datetime
import json
import logging
from typing import List, Optional, Union
from typing import Dict, List, Optional, Tuple, Union
import uuid

from sqlalchemy import and_, func, literal, update
Expand Down Expand Up @@ -395,6 +395,57 @@ def find_roles_permission_view_menus(
)
).all()

def get_user_roles_permissions(self, user) -> Dict[str, List[Tuple[str, str]]]:
"""
Utility method for fetching all roles and permissions for a specific user.
Example of the returned data:
```
{
'Admin': [
('can_this_form_get', 'ResetPasswordView'),
('can_this_form_post', 'ResetPasswordView'),
...
]
'EmptyRole': [],
}
```
"""
if not user.roles:
raise AttributeError("User object does not have roles")

result: Dict[str, List[Tuple[str, str]]] = {}
db_roles_ids = []
for role in user.roles:
# Make sure all db roles are included on the result
result[role.name] = []
if role.name in self.builtin_roles:
for permission in self.builtin_roles[role.name]:
result[role.name].append((permission[1], permission[0]))
else:
db_roles_ids.append(role.id)

permission_views = (
self.appbuilder.get_session.query(PermissionView)
.join(Permission)
.join(ViewMenu)
.join(PermissionView.role)
.filter(Role.id.in_(db_roles_ids))
.options(contains_eager(PermissionView.permission))
.options(contains_eager(PermissionView.view_menu))
.options(contains_eager(PermissionView.role))
).all()

for permission_view in permission_views:
for role_item in permission_view.role:
if role_item.name in result:
result[role_item.name].append(
(
permission_view.permission.name,
permission_view.view_menu.name,
)
)
return result

def get_db_role_permissions(self, role_id: int) -> List[PermissionView]:
"""
Get all DB permissions from a role (one single query)
Expand Down
22 changes: 22 additions & 0 deletions flask_appbuilder/tests/test_security_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,25 @@ def test_get_role_permissions_db(self):
("can_show", "ModelDBView"),
("can_delete", "ModelDBView"),
} == self.appbuilder.sm.get_role_permissions(role)

def test_get_user_roles_permissions_one_db_role(self):
assert {
"DB_ROLE1": [("can_show", "ModelDBView"), ("can_delete", "ModelDBView")]
} == self.appbuilder.sm.get_user_roles_permissions(self._user02)

def test_get_user_roles_permissions_mixed_roles(self):
assert {
"FAB_ROLE1": [("can_list", "Model1View"), ("can_list", "Model2View")],
"DB_ROLE1": [("can_show", "ModelDBView"), ("can_delete", "ModelDBView")],
} == self.appbuilder.sm.get_user_roles_permissions(self._user01)

def test_get_user_roles_permissions_one_builtin_roles(self):
assert {
"FAB_ROLE2": [("can_list", "Model3View"), ("can_list", "Model4View")]
} == self.appbuilder.sm.get_user_roles_permissions(self._user03)

def test_get_user_roles_permissions_mul_builtin_roles(self):
assert {
"FAB_ROLE1": [("can_list", "Model1View"), ("can_list", "Model2View")],
"FAB_ROLE2": [("can_list", "Model3View"), ("can_list", "Model4View")],
} == self.appbuilder.sm.get_user_roles_permissions(self._user04)