0001-natural_key-fix-get_by_natural_key_json-for-objects-.patch
src/authentic2/a2_rbac/models.py | ||
---|---|---|
115 | 115 |
object_id_field='admin_scope_id') |
116 | 116 | |
117 | 117 | |
118 |
Permission._meta.natural_key = ['operation', 'ou', 'target'] |
|
118 |
Permission._meta.natural_key = [ |
|
119 |
['operation', 'ou', 'target'], |
|
120 |
['operation', 'ou__isnull', 'target'], |
|
121 |
] |
|
119 | 122 | |
120 | 123 | |
121 | 124 |
class Role(RoleAbstractBase): |
... | ... | |
247 | 250 | |
248 | 251 | |
249 | 252 |
Role._meta.natural_key = [ |
250 |
['uuid'], ['slug', 'ou'], ['name', 'ou'], ['slug', 'service'], ['name', 'service'] |
|
253 |
['uuid'], |
|
254 |
['slug', 'ou__isnull', 'service__isnull'], |
|
255 |
['name', 'ou__isnull', 'service__isnull'], |
|
256 |
['slug', 'ou', 'service'], |
|
257 |
['name', 'ou', 'service'], |
|
258 |
['slug', 'ou', 'service__isnull'], |
|
259 |
['name', 'ou', 'service__isnull'], |
|
251 | 260 |
] |
252 | 261 | |
253 | 262 |
src/authentic2/natural_key.py | ||
---|---|---|
24 | 24 |
names.add(key) |
25 | 25 | |
26 | 26 |
for name in names: |
27 |
if name.endswith('__isnull'): |
|
28 |
name = name.split('__isnull')[0] |
|
27 | 29 |
field = self._meta.get_field(name) |
28 | 30 |
if not (field.concrete or isinstance(field, GenericForeignKey)): |
29 | 31 |
raise ValueError('field %s is not concrete' % name) |
... | ... | |
49 | 51 |
for natural_key in natural_keys: |
50 | 52 |
get_kwargs = {} |
51 | 53 |
for name in natural_key: |
54 |
isnull = name.endswith('__isnull') |
|
55 |
if isnull: |
|
56 |
name = name.split('__isnull')[0] |
|
52 | 57 |
field = model._meta.get_field(name) |
53 | 58 |
if not (field.concrete or isinstance(field, GenericForeignKey)): |
54 | 59 |
raise ValueError('field %s is not concrete' % name) |
... | ... | |
57 | 62 |
try: |
58 | 63 |
value = d[name] |
59 | 64 |
except KeyError: |
60 |
break |
|
61 |
if isinstance(field, GenericForeignKey): |
|
62 |
try: |
|
63 |
ct_nk = d[field.ct_field] |
|
64 |
except KeyError: |
|
65 |
break |
|
66 |
try: |
|
67 |
ct = ContentType.objects.get_by_natural_key_json(ct_nk) |
|
68 |
except ContentType.DoesNotExist: |
|
65 |
if not isnull: |
|
69 | 66 |
break |
70 |
related_model = ct.model_class() |
|
71 |
try: |
|
72 |
value = related_model._default_manager.get_by_natural_key_json(value) |
|
73 |
except related_model.DoesNotExist: |
|
67 |
value = None |
|
68 |
if isinstance(field, GenericForeignKey): |
|
69 |
if isnull and value: |
|
74 | 70 |
break |
75 |
get_kwargs[field.ct_field] = ct |
|
76 |
name = field.fk_field |
|
77 |
value = value.pk |
|
71 |
elif not isnull: |
|
72 |
if not value: |
|
73 |
break |
|
74 |
try: |
|
75 |
ct_nk = d[field.ct_field] |
|
76 |
except KeyError: |
|
77 |
break |
|
78 |
try: |
|
79 |
ct = ContentType.objects.get_by_natural_key_json(ct_nk) |
|
80 |
except ContentType.DoesNotExist: |
|
81 |
break |
|
82 |
related_model = ct.model_class() |
|
83 |
try: |
|
84 |
value = related_model._default_manager.get_by_natural_key_json(value) |
|
85 |
except related_model.DoesNotExist: |
|
86 |
break |
|
87 |
name = field.fk_field |
|
88 |
value = value.pk |
|
78 | 89 |
elif field.is_relation: |
79 |
if value is None: |
|
80 |
name = '%s__isnull' % name |
|
81 |
value = True |
|
82 |
else: |
|
90 |
if isnull and value: |
|
91 |
break |
|
92 |
elif not isnull: |
|
93 |
if not value: |
|
94 |
break |
|
83 | 95 |
try: |
84 | 96 |
value = field.related_model._default_manager.get_by_natural_key_json(value) |
85 | 97 |
except field.related_model.DoesNotExist: |
86 | 98 |
break |
87 |
get_kwargs[name] = value |
|
99 |
if isnull: |
|
100 |
get_kwargs[name + '__isnull'] = True |
|
101 |
else: |
|
102 |
get_kwargs[name] = value |
|
88 | 103 |
else: |
89 | 104 |
try: |
90 | 105 |
return self.get(**get_kwargs) |
tests/test_natural_key.py | ||
---|---|---|
1 |
import pytest |
|
2 | ||
1 | 3 |
from django.contrib.contenttypes.models import ContentType |
2 | 4 |
from authentic2.a2_rbac.models import Role, OrganizationalUnit as OU, Permission |
3 | 5 | |
... | ... | |
29 | 31 |
} |
30 | 32 |
assert role == Role.objects.get_by_natural_key_json(nk) |
31 | 33 |
assert role == Role.objects.get_by_natural_key_json({'uuid': role.uuid}) |
32 |
assert role == Role.objects.get_by_natural_key_json({'slug': role.slug, 'ou': ou_nk}) |
|
33 |
assert role == Role.objects.get_by_natural_key_json({'name': role.name, 'ou': ou_nk}) |
|
34 |
if service_nk: |
|
35 |
with pytest.raises(Role.DoesNotExist): |
|
36 |
Role.objects.get_by_natural_key_json({'slug': role.slug, 'ou': ou_nk}) |
|
37 |
else: |
|
38 |
assert Role.objects.get_by_natural_key_json({'slug': role.slug, 'ou': ou_nk}) == role |
|
39 |
if service_nk: |
|
40 |
with pytest.raises(Role.DoesNotExist): |
|
41 |
assert Role.objects.get_by_natural_key_json({'name': role.name, 'ou': ou_nk}) |
|
42 |
else: |
|
43 |
assert Role.objects.get_by_natural_key_json({'name': role.name, 'ou': ou_nk}) == role |
|
34 | 44 |
assert role == Role.objects.get_by_natural_key_json( |
35 |
{'slug': role.slug, 'service': service_nk}) |
|
45 |
{'slug': role.slug, 'ou': ou_nk, 'service': service_nk})
|
|
36 | 46 |
assert role == Role.objects.get_by_natural_key_json( |
37 |
{'name': role.name, 'service': service_nk}) |
|
47 |
{'name': role.name, 'ou': ou_nk, 'service': service_nk})
|
|
38 | 48 | |
39 | 49 |
for permission in Permission.objects.all(): |
40 | 50 |
ou_nk = permission.ou and permission.ou.natural_key_json() |
41 |
- |