Skip to content

Commit 4998593

Browse files
committed
feat(access): Support updating role permissions in format <app>.<permission>_<model>
ref: #1190 #1160 nofusscomputing/ansible_collection_centurion#47
1 parent f275d75 commit 4998593

4 files changed

Lines changed: 99 additions & 0 deletions

File tree

app/access/serializers/role.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1+
from functools import reduce
2+
3+
from operator import or_
4+
5+
from django.db import models
6+
17
from rest_framework import serializers
8+
from rest_framework.exceptions import ParseError
29

310
from drf_spectacular.utils import extend_schema_serializer
411

@@ -98,6 +105,47 @@ class Meta:
98105

99106

100107

108+
def to_internal_value(self, data):
109+
"""Convert Permission Names
110+
111+
Permission may be added in format `<app>.<permission>_<model>` this
112+
function converts to the permission pk.
113+
"""
114+
115+
if(
116+
'permissions' in data
117+
and isinstance(data['permissions'][0], str)
118+
):
119+
120+
filters = [
121+
models.Q(
122+
content_type__app_label=app, codename=codename
123+
) for app, codename in (
124+
perm.split(".", 1) for perm in data['permissions']
125+
)
126+
]
127+
128+
PermissionModel = self.Meta.model.permissions.field.related_model
129+
130+
permissions_id = [
131+
permission.id for permission in PermissionModel.objects.filter(
132+
reduce(or_, filters)
133+
)
134+
]
135+
136+
137+
if len(permissions_id) != len(data['permissions']):
138+
raise ParseError(
139+
detail = 'A Permission was supplied that could not be found',
140+
code = 'supplied_permission_does_not_exist'
141+
)
142+
143+
data['permissions'] = permissions_id
144+
145+
return super().to_internal_value(data)
146+
147+
148+
101149
@extend_schema_serializer(component_name = 'RoleViewSerializer')
102150
class ViewSerializer(ModelSerializer):
103151
"""Role Base View Model"""

app/access/tests/unit/role/test_unit_role_serializer.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,39 @@ def test_serializer_validation_no_name(self,
4747

4848

4949

50+
@pytest.mark.skip( reason = 'Test to be written' )
51+
def test_serializer_function_to_internal_value_permissions_as_int(self):
52+
"""Serializer Function Check
53+
54+
Ensure that function `to_internal_value` accepts permissions as a list
55+
of int
56+
"""
57+
pass
58+
59+
60+
61+
@pytest.mark.skip( reason = 'Test to be written' )
62+
def test_serializer_function_to_internal_value_permissions_to_int(self):
63+
"""Serializer Function Check
64+
65+
Ensure that function `to_internal_value` converts the permission
66+
strings list to a list of int.
67+
"""
68+
pass
69+
70+
71+
72+
@pytest.mark.skip( reason = 'Test to be written' )
73+
def test_serializer_function_to_internal_value_permissions_not_exist(self):
74+
"""Serializer Function Check
75+
76+
Ensure that function `to_internal_value` raises an exception when a
77+
permission supplied does not exist.
78+
"""
79+
pass
80+
81+
82+
5083
class RoleSerializerInheritedCases(
5184
RoleSerializerTestCases
5285
):

app/api/tests/unit/test_unit_serializer.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,16 @@ def test_only_base_defines__urls_object(self,
138138
"""
139139

140140
assert model_serializer['model']._declared_fields['_urls'].method_name == 'get_url_fields'
141+
142+
143+
144+
@pytest.mark.skip( reason = 'Test to be written' )
145+
def test_role_serializer_accepts_permissions_as_str(self,
146+
serializer_role, model
147+
):
148+
"""RoleSerializer Function Check
149+
150+
Ensure that role function `to_internal_value` accepts models
151+
permissions as a list of str. format `<app>.<permission>_<model>`.
152+
"""
153+
pass

docs/projects/centurion_erp/user/access/role.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,8 @@ Unlike filesystem based permssions, Centurion ERP permissions are not inclusive,
2828
- To `view` an item you must have its corresponding `view` permission
2929

3030
The exclusitvity is that each of the permissions listed above, dont include an assumed permission. For instance if you have the `add` permission for an item, you will not be able to view it. That would require the `view` permission.
31+
32+
33+
## Updating Role Permissions
34+
35+
Roles like all objects can be updated via the API. However role permissions additionally support supplying the permission(s) as a string. The format for the permission is `<app>.<permission>_<model>`. This has been added as a feature so it's easier to see what permission is being used as normally an API list would only contain numbers.

0 commit comments

Comments
 (0)