Skip to content

Commit

Permalink
Fix role inheritance (#5)
Browse files Browse the repository at this point in the history
* Fix role inheritance

* Drop python 3.6 and add django 4.0

* blacked

* Fix django 4.0 requirements
  • Loading branch information
sevdog authored Dec 14, 2021
1 parent ceeb214 commit 313f141
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 12 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ['3.6', '3.7', '3.8', '3.9', '3.10']
python-version: ['3.7', '3.8', '3.9', '3.10']

steps:
- uses: actions/checkout@v2
Expand Down
11 changes: 9 additions & 2 deletions django_group_role/management/commands/populate_roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,20 @@


def _fuzzy_search(rolenames):
fuzzy_rolenames = [name.lower().replace('-', ' ').replace('_', ' ') for name in rolenames]
fuzzy_rolenames = [
name.lower().replace("-", " ").replace("_", " ") for name in rolenames
]

def search(name):
return not rolenames or name in rolenames or name.lower().replace('-', ' ').replace('_', ' ') in fuzzy_rolenames
return (
not rolenames
or name in rolenames
or name.lower().replace("-", " ").replace("_", " ") in fuzzy_rolenames
)

return search


def _standard_search(rolenames):
def search(name):
return not rolenames or name in rolenames
Expand Down
4 changes: 2 additions & 2 deletions django_group_role/roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def _get_declared_permissions(cls, bases, classdict):
permissions = [permissions]
if bases:
permissions = reduce(
lambda a, b: a + [getattr(b, "permissions", None)], bases, permissions
lambda a, b: a + [getattr(b, "_permissions", None)], bases, permissions
)
permissions = map_permissions(*permissions)
assert not bases or permissions, "A Role must specify at least 1 permission"
Expand Down Expand Up @@ -119,7 +119,7 @@ def setup_permissions(self, clear=False):

# wrappers for group methods
def _wrap_group_method(self, method, *args, **kwargs):
method = getattr(self.group, method)
method = getattr(self.group.user_set, method)
return method(*args, **kwargs)

add = partialmethod(_wrap_group_method, method="add")
Expand Down
11 changes: 7 additions & 4 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ project_urls =
classifiers =
Programming Language :: Python
Programming Language :: Python :: 3
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Expand All @@ -21,13 +20,14 @@ classifiers =
Framework :: Django :: 3.0
Framework :: Django :: 3.1
Framework :: Django :: 3.2
Framework :: Django :: 4.0
License :: OSI Approved :: Apache Software License
Operating System :: OS Independent
Intended Audience :: Developers

[options]
packages = find:
python_requires = >=3.6
python_requires = >=3.7
setup_requires=
pytest-runner
install_requires =
Expand Down Expand Up @@ -64,7 +64,8 @@ DJANGO_SETTINGS_MODULE = tests.example_project.settings

[tox:tox]
envlist =
py{36,37,38,39,310}-django{22,30,31,32}
py{37,38,39,310}-django{22,30,31,32}
py{38,39,310}-django40

[testenv]
usedevelop = true
Expand All @@ -74,4 +75,6 @@ deps=
django22: Django>=2.2,<2.23
django30: Django>=3.0,<3.1
django31: Django>=3.1,<3.2
django32: Django>=3.2,<3.3
django32: Django>=3.2,<3.3
django32: Django>=3.2,<3.3
django40: Django>=4.0,<4.1
9 changes: 9 additions & 0 deletions tests/example_project/roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ class GroupManagers(BasicRole):
permissions = ["auth.add_group", "auth.view_group", "auth.delete_group"]


class GroupPermManagers(GroupManagers):
name = "Top-Managers"
permissions = [
"auth.add_permission",
"auth.view_permission",
"auth.delete_permission",
]


class AbstractRole(Role):
name = "Abstract"
abstract = True
Expand Down
42 changes: 39 additions & 3 deletions tests/test_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,16 @@ def test_apply_every_role(self):
'Role "User-Managers" setup completed!',
'Setting permissions for role "Group Managers"...',
'Role "Group Managers" setup completed!',
'Setting permissions for role "Top-Managers"...',
'Role "Top-Managers" setup completed!',
'Setting permissions for role "Erasers"...',
'Unable to bound permission to "Erasers" (Permission broken (auth) cannot be bound to role)',
'Setting permissions for role "Broken"...',
'Unable to bound permission to "Broken" (Permission auth.non_existing_perm cannot be bound to role)',
"",
],
)
self.assertEqual(Group.objects.all().count(), 6)
self.assertEqual(Group.objects.all().count(), 7)
group = Group.objects.get_by_natural_key("Users")
self.assertQuerysetEqual(
group.permissions.all(),
Expand Down Expand Up @@ -75,6 +77,21 @@ def test_apply_every_role(self):
transform=lambda p: p.natural_key(),
ordered=False,
)
group = Group.objects.get_by_natural_key("Top-Managers")
self.assertQuerysetEqual(
group.permissions.all(),
[
("view_user", "auth", "user"),
("view_group", "auth", "group"),
("add_group", "auth", "group"),
("delete_group", "auth", "group"),
("view_permission", "auth", "permission"),
("add_permission", "auth", "permission"),
("delete_permission", "auth", "permission"),
],
transform=lambda p: p.natural_key(),
ordered=False,
)

def test_apply_every_role_clear(self):
self.assertEqual(Group.objects.all().count(), 3)
Expand All @@ -90,14 +107,16 @@ def test_apply_every_role_clear(self):
'Role "User-Managers" setup completed!',
'Setting permissions for role "Group Managers"...',
'Role "Group Managers" setup completed!',
'Setting permissions for role "Top-Managers"...',
'Role "Top-Managers" setup completed!',
'Setting permissions for role "Erasers"...',
'Unable to bound permission to "Erasers" (Permission broken (auth) cannot be bound to role)',
'Setting permissions for role "Broken"...',
'Unable to bound permission to "Broken" (Permission auth.non_existing_perm cannot be bound to role)',
"",
],
)
self.assertEqual(Group.objects.all().count(), 6)
self.assertEqual(Group.objects.all().count(), 7)
group = Group.objects.get_by_natural_key("Users")
self.assertQuerysetEqual(
group.permissions.all(),
Expand Down Expand Up @@ -132,6 +151,21 @@ def test_apply_every_role_clear(self):
transform=lambda p: p.natural_key(),
ordered=False,
)
group = Group.objects.get_by_natural_key("Top-Managers")
self.assertQuerysetEqual(
group.permissions.all(),
[
("view_user", "auth", "user"),
("view_group", "auth", "group"),
("add_group", "auth", "group"),
("delete_group", "auth", "group"),
("view_permission", "auth", "permission"),
("add_permission", "auth", "permission"),
("delete_permission", "auth", "permission"),
],
transform=lambda p: p.natural_key(),
ordered=False,
)

def test_apply_single_role_clear(self):
self.assertEqual(Group.objects.all().count(), 3)
Expand Down Expand Up @@ -175,7 +209,9 @@ def test_apply_single_role_clear(self):
def test_apply_single_role_fuzzy_dash(self):
self.assertEqual(Group.objects.all().count(), 3)
out = StringIO()
call_command("populate_roles", "group-managers", clear=True, fuzzy=True, stdout=out)
call_command(
"populate_roles", "group-managers", clear=True, fuzzy=True, stdout=out
)
self.assertEqual(
out.getvalue().split("\n"),
[
Expand Down
29 changes: 29 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,32 @@ def test_map_permissions_list_plus_dict(self):
},
},
)

def test_map_permissions_dict_plus_dict(self):
perm_map = map_permissions(
{
"auth": {"user": ["view_user"]},
"myapp": {"mymodel": ["delete_mymodel"]},
"otherapp.element": ["view_element"],
},
{
"auth.user": ["view_user", "change_user"],
"auth": {"group": ["view_group"]},
"myapp.mymodel": ["view_mymodel", "change_mymodel"],
},
)
self.assertEqual(
perm_map,
{
"auth": {
"user": {"view_user", "change_user"},
"group": {"view_group"},
},
"myapp": {
"mymodel": {"view_mymodel", "change_mymodel", "delete_mymodel"},
},
"otherapp": {
"element": {"view_element"},
},
},
)

0 comments on commit 313f141

Please sign in to comment.