1
0
mirror of https://github.com/ansible/awx.git synced 2024-11-01 08:21:15 +03:00

Moved access_list url to <whatever>/id/access_list

Eg: organizations/1/access_list will now return a list of all users who
have access to that organization.

This replaces our initial implementation which was resources/id/access_list
This commit is contained in:
Akita Noek 2016-03-09 11:41:42 -05:00
parent efcd4efda2
commit 1989012fd5
4 changed files with 85 additions and 91 deletions

View File

@ -26,6 +26,7 @@ from rest_framework import views
# AWX
from awx.main.models import * # noqa
from awx.main.utils import * # noqa
from awx.api.serializers import ResourceAccessListElementSerializer
__all__ = ['APIView', 'GenericAPIView', 'ListAPIView', 'SimpleListAPIView',
'ListCreateAPIView', 'SubListAPIView', 'SubListCreateAPIView',
@ -33,6 +34,7 @@ __all__ = ['APIView', 'GenericAPIView', 'ListAPIView', 'SimpleListAPIView',
'RetrieveUpdateAPIView', 'RetrieveDestroyAPIView',
'RetrieveUpdateDestroyAPIView', 'DestroyAPIView',
'SubDetailAPIView',
'ResourceAccessList',
'ParentMixin',]
logger = logging.getLogger('awx.api.generics')
@ -473,3 +475,20 @@ class RetrieveUpdateDestroyAPIView(RetrieveUpdateAPIView, RetrieveDestroyAPIView
class DestroyAPIView(GenericAPIView, generics.DestroyAPIView):
pass
class ResourceAccessList(ListAPIView):
serializer_class = ResourceAccessListElementSerializer
def get_queryset(self):
self.object_id = self.kwargs['pk']
resource_model = getattr(self, 'resource_model')
obj = resource_model.objects.get(pk=self.object_id)
roles = set([p.role for p in obj.role_permissions.all()])
ancestors = set()
for r in roles:
ancestors.update(set(r.ancestors.all()))
return User.objects.filter(roles__in=list(ancestors))

View File

@ -238,7 +238,7 @@ class BaseSerializer(serializers.ModelSerializer):
__metaclass__ = BaseSerializerMetaclass
class Meta:
fields = ('id', 'type', 'resource_id', 'url', 'related', 'summary_fields', 'created',
fields = ('id', 'type', 'url', 'related', 'summary_fields', 'created',
'modified', 'name', 'description')
summary_fields = () # FIXME: List of field names from this serializer that should be used when included as part of another's summary_fields.
summarizable_fields = () # FIXME: List of field names on this serializer that should be included in summary_fields.
@ -253,7 +253,6 @@ class BaseSerializer(serializers.ModelSerializer):
created = serializers.SerializerMethodField()
modified = serializers.SerializerMethodField()
active = serializers.SerializerMethodField()
resource_id = serializers.SerializerMethodField()
def get_type(self, obj):
@ -293,9 +292,6 @@ class BaseSerializer(serializers.ModelSerializer):
res['created_by'] = reverse('api:user_detail', args=(obj.created_by.pk,))
if getattr(obj, 'modified_by', None) and obj.modified_by.is_active:
res['modified_by'] = reverse('api:user_detail', args=(obj.modified_by.pk,))
if isinstance(obj, ResourceMixin):
content_type_id = ContentType.objects.get_for_model(obj).pk
res['resource_access_list'] = reverse('api:resource_access_list', kwargs={'content_type_id': content_type_id, 'pk': obj.pk})
return res
def _get_summary_fields(self, obj):
@ -366,11 +362,6 @@ class BaseSerializer(serializers.ModelSerializer):
summary_fields['roles'] = roles
return summary_fields
def get_resource_id(self, obj):
content_type_id = ContentType.objects.get_for_model(obj).pk
return '%d/%d' % (content_type_id, obj.pk)
return None
def get_created(self, obj):
if obj is None:
return None
@ -545,8 +536,6 @@ class BaseSerializer(serializers.ModelSerializer):
def to_representation(self, obj):
ret = super(BaseSerializer, self).to_representation(obj)
if 'resource_id' in ret and ret['resource_id'] is None:
ret.pop('resource_id')
return ret
@ -817,6 +806,7 @@ class UserSerializer(BaseSerializer):
credentials = reverse('api:user_credentials_list', args=(obj.pk,)),
roles = reverse('api:user_roles_list', args=(obj.pk,)),
activity_stream = reverse('api:user_activity_stream_list', args=(obj.pk,)),
access_list = reverse('api:user_access_list', args=(obj.pk,)),
))
return res
@ -871,6 +861,7 @@ class OrganizationSerializer(BaseSerializer):
notifiers_any = reverse('api:organization_notifiers_any_list', args=(obj.pk,)),
notifiers_success = reverse('api:organization_notifiers_success_list', args=(obj.pk,)),
notifiers_error = reverse('api:organization_notifiers_error_list', args=(obj.pk,)),
access_list = reverse('api:organization_access_list', args=(obj.pk,)),
))
return res
@ -943,6 +934,7 @@ class ProjectSerializer(UnifiedJobTemplateSerializer, ProjectOptionsSerializer):
notifiers_any = reverse('api:project_notifiers_any_list', args=(obj.pk,)),
notifiers_success = reverse('api:project_notifiers_success_list', args=(obj.pk,)),
notifiers_error = reverse('api:project_notifiers_error_list', args=(obj.pk,)),
access_list = reverse('api:project_access_list', args=(obj.pk,)),
))
# Backwards compatibility.
if obj.current_update:
@ -1042,6 +1034,7 @@ class InventorySerializer(BaseSerializerWithVariables):
job_templates = reverse('api:inventory_job_template_list', args=(obj.pk,)),
scan_job_templates = reverse('api:inventory_scan_job_template_list', args=(obj.pk,)),
ad_hoc_commands = reverse('api:inventory_ad_hoc_commands_list', args=(obj.pk,)),
access_list = reverse('api:inventory_access_list', args=(obj.pk,)),
#single_fact = reverse('api:inventory_single_fact_view', args=(obj.pk,)),
))
if obj.organization and obj.organization.active:
@ -1212,6 +1205,7 @@ class GroupSerializer(BaseSerializerWithVariables):
activity_stream = reverse('api:group_activity_stream_list', args=(obj.pk,)),
inventory_sources = reverse('api:group_inventory_sources_list', args=(obj.pk,)),
ad_hoc_commands = reverse('api:group_ad_hoc_commands_list', args=(obj.pk,)),
access_list = reverse('api:group_access_list', args=(obj.pk,)),
#single_fact = reverse('api:group_single_fact_view', args=(obj.pk,)),
))
if obj.inventory and obj.inventory.active:
@ -1475,6 +1469,7 @@ class TeamSerializer(BaseSerializer):
credentials = reverse('api:team_credentials_list', args=(obj.pk,)),
roles = reverse('api:team_roles_list', args=(obj.pk,)),
activity_stream = reverse('api:team_activity_stream_list', args=(obj.pk,)),
access_list = reverse('api:team_access_list', args=(obj.pk,)),
))
if obj.organization and obj.organization.active:
res['organization'] = reverse('api:organization_detail', args=(obj.organization.pk,))
@ -1509,37 +1504,13 @@ class RoleSerializer(BaseSerializer):
return ret
"""
class ResourceSerializer(BaseSerializer):
class Meta:
model = Resource
fields = ('*',)
def get_related(self, obj):
ret = super(ResourceSerializer, self).get_related(obj)
ret['access_list'] = reverse('api:resource_access_list', args=(obj.pk,))
try:
if obj.content_object:
ret.update(reverseGenericForeignKey(obj.content_object))
except AttributeError as e:
print(e)
# AttributeError's happen if our content_object is pointing at
# a model that no longer exists. This is dirty data and ideally
# doesn't exist, but in case it does, let's not puke.
pass
return ret
"""
class ResourceAccessListElementSerializer(UserSerializer):
def to_representation(self, user):
ret = super(ResourceAccessListElementSerializer, self).to_representation(user)
content_type = ContentType.objects.get(pk=self.context['view'].content_type_id)
object_id = self.context['view'].object_id
obj = content_type.model_class().objects.get(pk=object_id)
obj = self.context['view'].resource_model.objects.get(pk=object_id)
if 'summary_fields' not in ret:
ret['summary_fields'] = {}
@ -1611,7 +1582,8 @@ class CredentialSerializer(BaseSerializer):
def get_related(self, obj):
res = super(CredentialSerializer, self).get_related(obj)
res.update(dict(
activity_stream = reverse('api:credential_activity_stream_list', args=(obj.pk,))
activity_stream = reverse('api:credential_activity_stream_list', args=(obj.pk,)),
access_list = reverse('api:credential_access_list', args=(obj.pk,)),
))
if obj.user:
res['user'] = reverse('api:user_detail', args=(obj.user.pk,))
@ -1690,6 +1662,7 @@ class JobTemplateSerializer(UnifiedJobTemplateSerializer, JobOptionsSerializer):
notifiers_any = reverse('api:job_template_notifiers_any_list', args=(obj.pk,)),
notifiers_success = reverse('api:job_template_notifiers_success_list', args=(obj.pk,)),
notifiers_error = reverse('api:job_template_notifiers_error_list', args=(obj.pk,)),
access_list = reverse('api:job_template_access_list', args=(obj.pk,)),
))
if obj.host_config_key:
res['callback'] = reverse('api:job_template_callback', args=(obj.pk,))

View File

@ -24,6 +24,7 @@ organization_urls = patterns('awx.api.views',
url(r'^(?P<pk>[0-9]+)/notifiers_any/$', 'organization_notifiers_any_list'),
url(r'^(?P<pk>[0-9]+)/notifiers_error/$', 'organization_notifiers_error_list'),
url(r'^(?P<pk>[0-9]+)/notifiers_success/$', 'organization_notifiers_success_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', 'organization_access_list'),
)
user_urls = patterns('awx.api.views',
@ -36,6 +37,7 @@ user_urls = patterns('awx.api.views',
url(r'^(?P<pk>[0-9]+)/credentials/$', 'user_credentials_list'),
url(r'^(?P<pk>[0-9]+)/roles/$', 'user_roles_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'user_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', 'user_access_list'),
)
project_urls = patterns('awx.api.views',
@ -51,6 +53,7 @@ project_urls = patterns('awx.api.views',
url(r'^(?P<pk>[0-9]+)/notifiers_any/$', 'project_notifiers_any_list'),
url(r'^(?P<pk>[0-9]+)/notifiers_error/$', 'project_notifiers_error_list'),
url(r'^(?P<pk>[0-9]+)/notifiers_success/$', 'project_notifiers_success_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', 'project_access_list'),
)
project_update_urls = patterns('awx.api.views',
@ -68,6 +71,7 @@ team_urls = patterns('awx.api.views',
url(r'^(?P<pk>[0-9]+)/credentials/$', 'team_credentials_list'),
url(r'^(?P<pk>[0-9]+)/roles/$', 'team_roles_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'team_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', 'team_access_list'),
)
inventory_urls = patterns('awx.api.views',
@ -84,6 +88,7 @@ inventory_urls = patterns('awx.api.views',
url(r'^(?P<pk>[0-9]+)/job_templates/$', 'inventory_job_template_list'),
url(r'^(?P<pk>[0-9]+)/scan_job_templates/$', 'inventory_scan_job_template_list'),
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', 'inventory_ad_hoc_commands_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', 'inventory_access_list'),
#url(r'^(?P<pk>[0-9]+)/single_fact/$', 'inventory_single_fact_view'),
)
@ -117,6 +122,7 @@ group_urls = patterns('awx.api.views',
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'group_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/inventory_sources/$', 'group_inventory_sources_list'),
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', 'group_ad_hoc_commands_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', 'group_access_list'),
#url(r'^(?P<pk>[0-9]+)/single_fact/$', 'group_single_fact_view'),
)
@ -150,6 +156,7 @@ credential_urls = patterns('awx.api.views',
url(r'^$', 'credential_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'credential_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/$', 'credential_detail'),
url(r'^(?P<pk>[0-9]+)/access_list/$', 'credential_access_list'),
# See also credentials resources on users/teams.
)
@ -162,15 +169,6 @@ role_urls = patterns('awx.api.views',
url(r'^(?P<pk>[0-9]+)/children/$', 'role_children_list'),
)
resource_urls = patterns('awx.api.views',
#url(r'^$', 'resource_list'),
#url(r'^(?P<pk>[0-9]+)/$', 'resource_detail'),
url(r'^(?P<content_type_id>[0-9]+)/(?P<pk>[0-9]+)/access_list/$', 'resource_access_list'),
#url(r'^(?P<pk>[0-9]+)/users/$', 'resource_users_list'),
#url(r'^(?P<pk>[0-9]+)/teams/$', 'resource_teams_list'),
#url(r'^(?P<pk>[0-9]+)/roles/$', 'resource_teams_list'),
)
job_template_urls = patterns('awx.api.views',
url(r'^$', 'job_template_list'),
url(r'^(?P<pk>[0-9]+)/$', 'job_template_detail'),
@ -183,6 +181,7 @@ job_template_urls = patterns('awx.api.views',
url(r'^(?P<pk>[0-9]+)/notifiers_any/$', 'job_template_notifiers_any_list'),
url(r'^(?P<pk>[0-9]+)/notifiers_error/$', 'job_template_notifiers_error_list'),
url(r'^(?P<pk>[0-9]+)/notifiers_success/$', 'job_template_notifiers_success_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', 'job_template_access_list'),
)
job_urls = patterns('awx.api.views',
@ -292,7 +291,6 @@ v1_urls = patterns('awx.api.views',
url(r'^inventory_scripts/', include(inventory_script_urls)),
url(r'^credentials/', include(credential_urls)),
url(r'^roles/', include(role_urls)),
url(r'^resources/', include(resource_urls)),
url(r'^job_templates/', include(job_template_urls)),
url(r'^jobs/', include(job_urls)),
url(r'^job_host_summaries/', include(job_host_summary_urls)),

View File

@ -703,6 +703,12 @@ class OrganizationNotifiersSuccessList(SubListCreateAttachDetachAPIView):
parent_model = Organization
relationship = 'notifiers_success'
class OrganizationAccessList(ResourceAccessList):
model = User # needs to be User for AccessLists's
resource_model = Organization
new_in_300 = True
class TeamList(ListCreateAPIView):
model = Team
@ -783,6 +789,11 @@ class TeamActivityStreamList(SubListAPIView):
Q(credential__in=parent.credentials.all()) |
Q(permission__in=parent.permissions.all()))
class TeamAccessList(ResourceAccessList):
model = User # needs to be User for AccessLists's
resource_model = Team
new_in_300 = True
class ProjectList(ListCreateAPIView):
@ -947,6 +958,12 @@ class ProjectUpdateNotificationsList(SubListAPIView):
parent_model = Project
relationship = 'notifications'
class ProjectAccessList(ResourceAccessList):
model = User # needs to be User for AccessLists's
resource_model = Project
new_in_300 = True
class UserList(ListCreateAPIView):
model = User
@ -1086,6 +1103,12 @@ class UserDetail(RetrieveUpdateDestroyAPIView):
own_credential.mark_inactive()
return super(UserDetail, self).destroy(request, *args, **kwargs)
class UserAccessList(ResourceAccessList):
model = User # needs to be User for AccessLists's
resource_model = User
new_in_300 = True
class CredentialList(ListCreateAPIView):
model = Credential
@ -1114,6 +1137,11 @@ class CredentialActivityStreamList(SubListAPIView):
# Okay, let it through.
return super(type(self), self).get(request, *args, **kwargs)
class CredentialAccessList(ResourceAccessList):
model = User # needs to be User for AccessLists's
resource_model = Credential
new_in_300 = True
class InventoryScriptList(ListCreateAPIView):
@ -1174,6 +1202,12 @@ class InventoryActivityStreamList(SubListAPIView):
qs = self.request.user.get_queryset(self.model)
return qs.filter(Q(inventory=parent) | Q(host__in=parent.hosts.all()) | Q(group__in=parent.groups.all()))
class InventoryAccessList(ResourceAccessList):
model = User # needs to be User for AccessLists's
resource_model = Inventory
new_in_300 = True
class InventoryJobTemplateList(SubListAPIView):
model = JobTemplate
@ -1509,6 +1543,13 @@ class GroupDetail(RetrieveUpdateDestroyAPIView):
obj.mark_inactive_recursive()
return Response(status=status.HTTP_204_NO_CONTENT)
class GroupAccessList(ResourceAccessList):
model = User # needs to be User for AccessLists's
resource_model = Group
new_in_300 = True
class InventoryGroupsList(SubListCreateAttachDetachAPIView):
model = Group
@ -2186,6 +2227,12 @@ class JobTemplateJobsList(SubListCreateAPIView):
relationship = 'jobs'
parent_key = 'job_template'
class JobTemplateAccessList(ResourceAccessList):
model = User # needs to be User for AccessLists's
resource_model = JobTemplate
new_in_300 = True
class SystemJobTemplateList(ListAPIView):
model = SystemJobTemplate
@ -3268,49 +3315,6 @@ class RoleChildrenList(SubListAPIView):
role = Role.objects.get(pk=self.kwargs['pk'])
return role.children
'''
class ResourceDetail(RetrieveAPIView):
model = Resource
serializer_class = ResourceSerializer
permission_classes = (IsAuthenticated,)
new_in_300 = True
# XXX: Permissions - only roles the user has access to see should be listed here
def get_queryset(self):
return Resource.objects
class ResourceList(ListAPIView):
model = Resource
serializer_class = ResourceSerializer
permission_classes = (IsAuthenticated,)
new_in_300 = True
def get_queryset(self):
return Resource.objects.filter(permissions__role__ancestors__members=self.request.user)
'''
class ResourceAccessList(ListAPIView):
model = User
serializer_class = ResourceAccessListElementSerializer
permission_classes = (IsAuthenticated,)
new_in_300 = True
def get_queryset(self):
self.content_type_id = self.kwargs['content_type_id']
self.object_id = self.kwargs['pk']
#resource = Resource.objects.get(pk=self.kwargs['pk'])
content_type = ContentType.objects.get(pk=self.content_type_id)
obj = content_type.model_class().objects.get(pk=self.object_id)
roles = set([p.role for p in obj.role_permissions.all()])
ancestors = set()
for r in roles:
ancestors.update(set(r.ancestors.all()))
return User.objects.filter(roles__in=list(ancestors))