Skip to content

Commit 18d07bc

Browse files
authored
[AAP-45443] Default filters for RoleUserAssignmentViewSet (#740)
Fixes bug where the default rest filters were not being enabled for - RoleTeamAssignmentViewSet - RoleUserAssignmentViewSet Because user_ansible_id is not a field on RoleUserAssignment, we also have to add the the following fields to the `ANSIBLE_BASE_REST_FILTERS_RESERVED_NAMES` - user_ansible_id - team_ansible_id - object_ansible_id One negative consequence to this is that `api/v1/role_user_assignments/?team_ansible_id=da0488f5-013b-460c-8a62-c3c10a1d0fad` does not throw any type of field error, even though team_ansible_id is not part of the RoleUserAssignment model.
1 parent 8230929 commit 18d07bc

File tree

4 files changed

+53
-14
lines changed

4 files changed

+53
-14
lines changed

ansible_base/lib/dynamic_config/settings_logic.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ def get_mergeable_dab_settings(settings: dict) -> dict: # NOSONAR
105105
'no_truncate',
106106
'limit',
107107
'validate',
108+
'user_ansible_id',
109+
'team_ansible_id',
110+
'object_ansible_id',
108111
)
109112

110113
# SPECTACULAR SETTINGS

ansible_base/rbac/api/views.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
from ansible_base.lib.utils.views.django_app_api import AnsibleBaseDjangoAppApiView
1414
from ansible_base.lib.utils.views.permissions import try_add_oauth2_scope_permission
15-
from ansible_base.rbac.api.filter_backends import TeamAnsibleIdAliasFilterBackend, UserAnsibleIdAliasFilterBackend
1615
from ansible_base.rbac.api.permissions import RoleDefinitionPermissions
1716
from ansible_base.rbac.api.serializers import (
1817
RoleDefinitionDetailSerializer,
@@ -26,6 +25,7 @@
2625
from ansible_base.rbac.permission_registry import permission_registry
2726
from ansible_base.rbac.policies import check_can_remove_assignment
2827
from ansible_base.rbac.validators import check_locally_managed, permissions_allowed_for_role, system_roles_enabled
28+
from ansible_base.rest_filters.rest_framework.ansible_id_backend import TeamAnsibleIdAliasFilterBackend, UserAnsibleIdAliasFilterBackend
2929

3030

3131
def list_combine_values(data: dict[Type[Model], list[str]]) -> list[str]:
@@ -160,7 +160,9 @@ class RoleTeamAssignmentViewSet(BaseAssignmentViewSet):
160160

161161
serializer_class = RoleTeamAssignmentSerializer
162162
prefetch_related = ('team',)
163-
filter_backends = (TeamAnsibleIdAliasFilterBackend,)
163+
filter_backends = BaseAssignmentViewSet.filter_backends + [
164+
TeamAnsibleIdAliasFilterBackend,
165+
]
164166

165167

166168
class RoleUserAssignmentViewSet(BaseAssignmentViewSet):
@@ -177,4 +179,6 @@ class RoleUserAssignmentViewSet(BaseAssignmentViewSet):
177179

178180
serializer_class = RoleUserAssignmentSerializer
179181
prefetch_related = ('user',)
180-
filter_backends = (UserAnsibleIdAliasFilterBackend,)
182+
filter_backends = BaseAssignmentViewSet.filter_backends + [
183+
UserAnsibleIdAliasFilterBackend,
184+
]

ansible_base/rbac/api/filter_backends.py renamed to ansible_base/rest_filters/rest_framework/ansible_id_backend.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ def filter_queryset(self, request, queryset, view):
2929
resource_obj = Resource.objects.get(ansible_id=object_ansible_id)
3030

3131
# Filter the queryset based on the resource's content_type and object_id
32-
queryset = queryset.filter(
33-
object_role__content_type=resource_obj.content_type, object_role__object_id=str(resource_obj.object_id) # Ensure object_id is string
34-
)
32+
queryset = queryset.filter(object_role__content_type=resource_obj.content_type, object_role__object_id=resource_obj.object_id)
3533
except Resource.DoesNotExist:
3634
# If the resource is not found, return an empty queryset
3735
return queryset.none()

test_app/tests/rbac/test_ansible_id_alias_filter.py

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,29 @@
66
from ansible_base.resource_registry.models import Resource
77

88

9+
@pytest.mark.django_db
910
class TestAnsibleIdAliasFilterBackend:
1011

11-
@pytest.mark.django_db
12-
def test_filter_user_ansible_id(self, admin_api_client, org_inv_rd, inv_rd, inventory, rando, organization):
12+
def test_filter_user_ansible_id(self, admin_api_client, org_inv_rd, inv_rd, inventory, rando, random_user, organization):
1313
'''
1414
Test filtering RoleUserAssignment by user_ansible_id and object_ansible_id.
15+
Also test that other filtering works,
1516
'''
16-
# user - org assigment
17+
# rando - org assigment
1718
user_resource = Resource.objects.get(object_id=rando.pk, content_type=ContentType.objects.get_for_model(rando).pk)
1819
organization_resource = Resource.objects.get(object_id=organization.pk, content_type=ContentType.objects.get_for_model(organization).pk)
1920
url = get_relative_url('roleuserassignment-list')
2021
data = dict(role_definition=org_inv_rd.id, content_type='shared.organization', user_ansible_id=user_resource.ansible_id, object_id=organization.id)
2122
response = admin_api_client.post(url, data=data, format="json")
2223
assert response.status_code == 201, response.data
2324

24-
# user - inventory assignment (just a random assignment to make total count > 1)
25-
data = dict(role_definition=inv_rd.id, content_type='shared.inventory', user_ansible_id=user_resource.ansible_id, object_id=inventory.id)
25+
# random_user - org assigment
26+
data = dict(role_definition=org_inv_rd.id, content_type='shared.organization', user=random_user.id, object_id=organization.id)
27+
response = admin_api_client.post(url, data=data, format="json")
28+
assert response.status_code == 201, response.data
29+
30+
# rando - inventory assignment (an additional assignment to make total count > 1)
31+
data = dict(role_definition=inv_rd.id, content_type='aap.inventory', user_ansible_id=user_resource.ansible_id, object_id=inventory.id)
2632
response = admin_api_client.post(url, data=data, format="json")
2733
assert response.status_code == 201, response.data
2834

@@ -40,15 +46,44 @@ def test_filter_user_ansible_id(self, admin_api_client, org_inv_rd, inv_rd, inve
4046
query_params = {'object_ansible_id': organization_resource.ansible_id}
4147
response = admin_api_client.get(url + '?' + urlencode(query_params))
4248
assert response.status_code == 200, response.data
43-
assert response.data["count"] == 1, response.data
49+
assert response.data["count"] == 2, response.data
4450

4551
# filter by both user_ansible_id and object_ansible_id
4652
query_params = {'user_ansible_id': user_resource.ansible_id, 'object_ansible_id': organization_resource.ansible_id}
4753
response = admin_api_client.get(url + '?' + urlencode(query_params))
4854
assert response.status_code == 200, response.data
4955
assert response.data["count"] == 1, response.data
5056

51-
@pytest.mark.django_db
57+
# filter by random user id
58+
query_params = {'user': random_user.id}
59+
response = admin_api_client.get(url + '?' + urlencode(query_params))
60+
assert response.status_code == 200, response.data
61+
assert response.data["count"] == 1, response.data
62+
63+
def test_filter_by_user_id(self, admin_api_client, inv_rd, inventory, random_user):
64+
'''
65+
Test that filtering with user id still works.
66+
This ensures that the default rest filters are still functional for this
67+
viewset.
68+
'''
69+
user_resource = Resource.objects.get(object_id=random_user.pk, content_type=ContentType.objects.get_for_model(random_user).pk)
70+
url = get_relative_url('roleuserassignment-list')
71+
data = dict(role_definition=inv_rd.id, content_type='aap.inventory', user_ansible_id=user_resource.ansible_id, object_id=inventory.id)
72+
response = admin_api_client.post(url, data=data, format="json")
73+
assert response.status_code == 201, response.data
74+
75+
# filter by user_id
76+
query_params = {'user': random_user.id}
77+
response = admin_api_client.get(url + '?' + urlencode(query_params))
78+
assert response.status_code == 200, response.data
79+
assert response.data["count"] == 1, response.data
80+
81+
# filter by user_ansible_id
82+
query_params = {'user_ansible_id': user_resource.ansible_id}
83+
response = admin_api_client.get(url + '?' + urlencode(query_params))
84+
assert response.status_code == 200, response.data
85+
assert response.data["count"] == 1, response.data
86+
5287
def test_filter_team_ansible_id(self, admin_api_client, team, inv_rd, inventory):
5388
'''
5489
Test filtering RoleTeamAssignment by team_ansible_id.
@@ -66,7 +101,6 @@ def test_filter_team_ansible_id(self, admin_api_client, team, inv_rd, inventory)
66101
assert response.data["count"] == 1, response.data
67102

68103
@pytest.mark.parametrize("ansible_id_type", ["user", "team", "object"])
69-
@pytest.mark.django_db
70104
def test_invalid_ansible_id_format(self, admin_api_client, ansible_id_type):
71105
'''
72106
Test that invalid UUID formats for ansible_id raise a 400 error.

0 commit comments

Comments
 (0)