Skip to content

Commit 193d9e7

Browse files
committed
Automatically set DAB types to id of content type to make life easier
1 parent 7f466c2 commit 193d9e7

File tree

6 files changed

+48
-16
lines changed

6 files changed

+48
-16
lines changed

ansible_base/rbac/management/create_types.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,38 @@ def create_DAB_contenttypes(
3030
comes from the permission registry.
3131
"""
3232
DABContentType = apps.get_model("dab_rbac", "DABContentType")
33+
ContentType = apps.get_model("contenttypes", "ContentType")
3334

3435
content_types = get_local_DAB_contenttypes(using, DABContentType)
3536

3637
# TODO: add api_slug field when added
37-
cts = []
38+
ct_data = []
3839
for model in permission_registry.all_registered_models:
3940
service = get_resource_prefix(model)
4041
if (service, model._meta.model_name) not in content_types:
4142
# The content type is not seen in existing entries, add to list for creation
42-
cts.append(
43-
DABContentType(
44-
service=service,
45-
app_label=model._meta.app_label,
46-
model=model._meta.model_name,
47-
)
43+
ct_item_data = dict(
44+
service=service,
45+
app_label=model._meta.app_label,
46+
model=model._meta.model_name,
4847
)
49-
if not cts:
48+
# To make usage earier in a transitional period, we will set the content type
49+
# of any new entries created here to the id of its corresponding ContentType
50+
# from the actual contenttypes app, allowing many filters to work
51+
real_ct = ContentType.objects.get_for_model(model)
52+
if not DABContentType.objects.filter(id=real_ct.id).exists():
53+
ct_item_data['id'] = real_ct.id
54+
ct_data.append(ct_item_data)
55+
if not ct_data:
5056
return
51-
DABContentType.objects.using(using).bulk_create(cts)
57+
58+
# To make usage earier in a transitional period, we will set the content type
59+
# of any new entries created here to the id of its corresponding ContentType
60+
# from the actual contenttypes app, allowing many filters to work
61+
cts = []
62+
for ct_item_data in ct_data:
63+
cts.append(DABContentType.objects.create(**ct_item_data))
64+
5265
if verbosity >= 2:
5366
for ct in cts:
5467
logger.debug("Adding DAB content type " f"'{ct.service}:{ct.app_label} | {ct.model}'")

ansible_base/rbac/models/content_type.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,15 @@ def get_by_natural_key(self, *args: str) -> "DABContentType":
143143
if len(args) == 2:
144144
service = get_local_resource_prefix()
145145
app_label, model = args
146+
kwargs = {'service__in': [get_local_resource_prefix(), 'shared'], 'app_label': app_label, 'model': model}
146147
else:
147148
service, app_label, model = args
149+
kwargs = {'service': service, 'app_label': app_label, 'model': model}
148150
key = (service, app_label, model)
149151
try:
150152
return self._cache[self.db][key]
151153
except KeyError:
152-
ct = self.get(service=service, app_label=app_label, model=model)
154+
ct = self.get(**kwargs)
153155
self._add_to_cache(self.db, ct)
154156
return ct
155157

@@ -230,7 +232,7 @@ def get_object_for_this_type(self, **kwargs: Any) -> Union[django_models.Model,
230232
"""Return the object referenced by this content type."""
231233
model = self.model_class()
232234

233-
from .fields import get_remote_base_class
235+
from ..remote import get_remote_base_class
234236

235237
remote_base = get_remote_base_class()
236238

@@ -246,7 +248,7 @@ def get_all_objects_for_this_type(self, **kwargs: Any) -> Union[django_models.Qu
246248
"""Return all objects referenced by this content type."""
247249
model = self.model_class()
248250

249-
from .fields import get_remote_base_class
251+
from ..remote import get_remote_base_class
250252

251253
remote_base = get_remote_base_class()
252254
if issubclass(model, remote_base):

ansible_base/rbac/models/role.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22
from collections.abc import Iterable
33
from typing import Optional, Type, Union
4+
from uuid import UUID
45

56
# Django
67
from django.conf import settings
@@ -524,7 +525,7 @@ def descendent_roles(self):
524525
descendents.update(set(target_team.has_roles.all()))
525526
return descendents
526527

527-
def expected_direct_permissions(self, types_prefetch=None) -> set[tuple[str, int, Union[int, str]]]:
528+
def expected_direct_permissions(self, types_prefetch=None) -> set[tuple[str, int, Union[int, str, UUID]]]:
528529
"""The expected permissions that holding this ObjectRole confers to the holder
529530
530531
This is given in the form of tuples, which represent RoleEvaluation entries.

ansible_base/rbac/remote.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import inspect
22
from typing import Type, Union
33

4+
from django.apps import apps
45
from django.conf import settings
56
from django.db import models
67
from django.utils.module_loading import import_string
@@ -28,6 +29,13 @@ def __init__(self, content_type: models.Model, object_id: Union[int, str]):
2829
def __repr__(self):
2930
return f"<RemoteObject {self.content_type} id={self.object_id}>"
3031

32+
@classmethod
33+
def get_ct_from_type(cls):
34+
if not hasattr(cls, '_meta'):
35+
raise ValueError('Generlized RemoteObject can not obtain content_type from its class')
36+
ct_model = apps.get_model('dab_rbac', 'DABContentType')
37+
return ct_model.objects.get_by_natural_key(cls._meta.service, cls._meta.app_label, cls._meta.model)
38+
3139

3240
def get_remote_base_class() -> Type[RemoteObject]:
3341
"""Return the class which represents remote objects.
@@ -103,6 +111,7 @@ def get_remote_standin_class(content_type: models.Model) -> Type:
103111

104112
class StandinMeta:
105113
def __init__(self, ct: models.Model):
114+
self.service = ct.service
106115
self.model_name = ct.model
107116
self.app_label = ct.app_label
108117

test_app/tests/rbac/models/test_content_type.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import pytest
2+
from django.contrib.contenttypes.models import ContentType
23
from django.db import models
34
from django.test import TestCase
45
from django.test.utils import isolate_apps
@@ -8,6 +9,14 @@
89
from test_app.models import Inventory, Organization
910

1011

12+
@pytest.mark.django_db
13+
def test_migration_shadows_real_contenttype():
14+
assert DABContentType.objects.count() > 0 # sanity
15+
for dab_ct in DABContentType.objects.all():
16+
ct = ContentType.objects.get_by_natural_key(dab_ct.app_label, dab_ct.model)
17+
assert ct.id == dab_ct.id
18+
19+
1120
@pytest.mark.django_db
1221
def test_auto_create_content_type():
1322
DABContentType.objects.all().delete()

test_app/tests/rbac/remote/test_remote_models.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@
88
def test_give_remote_permission(rando):
99
foo_type = DABContentType.objects.create(service='foo', model='foo', app_label='foo')
1010
assert foo_type.service == 'foo'
11-
# TODO:
12-
# assert foo_type.model_class() is not None
13-
foo_foo = DABPermission.objects.create(codename='foo_foo', content_type=foo_type)
11+
DABPermission.objects.create(codename='foo_foo', content_type=foo_type)
1412
rd = RoleDefinition.objects.create_from_permissions(name='Foo fooers for the foos in foo service', permissions=['foo.foo_foo'], content_type=foo_type)
1513
a_foo = RemoteObject(content_type=foo_type, object_id=42)
1614
rd.give_permission(rando, a_foo)

0 commit comments

Comments
 (0)