diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 40ab2d3cd2..f258470f48 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -96,6 +96,46 @@ SUMMARIZABLE_FK_FIELDS = { } +def reverseGenericForeignKey(content_object): + ''' + Computes a reverse for a GenericForeignKey field. + + Returns a dictionary of the form + { '': reverse() } + for example + { 'organization': '/api/v1/organizations/1/' } + ''' + + ret = {} + if type(content_object) is Organization: + ret['organization'] = reverse('api:organization_detail', args=(content_object.pk,)) + if type(content_object) is User: + ret['user'] = reverse('api:user_detail', args=(content_object.pk,)) + if type(content_object) is Team: + ret['team'] = reverse('api:team_detail', args=(content_object.pk,)) + if type(content_object) is Project: + ret['project'] = reverse('api:project_detail', args=(content_object.pk,)) + if type(content_object) is Inventory: + ret['inventory'] = reverse('api:inventory_detail', args=(content_object.pk,)) + if type(content_object) is Host: + ret['host'] = reverse('api:host_detail', args=(content_object.pk,)) + if type(content_object) is Group: + ret['group'] = reverse('api:group_detail', args=(content_object.pk,)) + if type(content_object) is InventorySource: + ret['inventory_source'] = reverse('api:inventory_source_detail', args=(content_object.pk,)) + if type(content_object) is Credential: + ret['credential'] = reverse('api:credential_detail', args=(content_object.pk,)) + if type(content_object) is JobTemplate: + ret['job_template'] = reverse('api:job_template_detail', args=(content_object.pk,)) + if type(content_object) is Role: + ret['role'] = reverse('api:role_detail', args=(content_object.pk,)) + if type(content_object) is Job: + ret['job'] = reverse('api:job_detail', args=(content_object.pk,)) + if type(content_object) is JobEvent: + ret['job_event'] = reverse('api:job_event_detail', args=(content_object.pk,)) + return ret + + class BaseSerializerMetaclass(serializers.SerializerMetaclass): ''' Custom metaclass to enable attribute inheritance from Meta objects on @@ -1421,25 +1461,16 @@ class RoleSerializer(BaseSerializer): def get_related(self, obj): ret = super(RoleSerializer, self).get_related(obj) - if obj.content_object: - if type(obj.content_object) is Organization: - ret['organization'] = reverse('api:organization_detail', args=(obj.object_id,)) - if type(obj.content_object) is Team: - ret['team'] = reverse('api:team_detail', args=(obj.object_id,)) - if type(obj.content_object) is Project: - ret['project'] = reverse('api:project_detail', args=(obj.object_id,)) - if type(obj.content_object) is Inventory: - ret['inventory'] = reverse('api:inventory_detail', args=(obj.object_id,)) - if type(obj.content_object) is Host: - ret['host'] = reverse('api:host_detail', args=(obj.object_id,)) - if type(obj.content_object) is Group: - ret['group'] = reverse('api:group_detail', args=(obj.object_id,)) - if type(obj.content_object) is InventorySource: - ret['inventory_source'] = reverse('api:inventory_source_detail', args=(obj.object_id,)) - if type(obj.content_object) is Credential: - ret['credential'] = reverse('api:credential_detail', args=(obj.object_id,)) - if type(obj.content_object) is JobTemplate: - ret['job_template'] = reverse('api:job_template_detail', args=(obj.object_id,)) + ret['users'] = reverse('api:role_users_list', args=(obj.pk,)) + ret['teams'] = reverse('api:role_teams_list', args=(obj.pk,)) + try: + if obj.content_object: + ret.update(reverseGenericForeignKey(obj.content_object)) + except AttributeError: + # 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 @@ -1450,6 +1481,21 @@ class ResourceSerializer(BaseSerializer): 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): diff --git a/awx/api/urls.py b/awx/api/urls.py index 685c6122e7..a249077c8e 100644 --- a/awx/api/urls.py +++ b/awx/api/urls.py @@ -151,7 +151,7 @@ role_urls = patterns('awx.api.views', ) resource_urls = patterns('awx.api.views', - #url(r'^$', 'resource_list'), + url(r'^$', 'resource_list'), url(r'^(?P[0-9]+)/$', 'resource_detail'), url(r'^(?P[0-9]+)/access_list/$', 'resource_access_list'), #url(r'^(?P[0-9]+)/users/$', 'resource_users_list'), diff --git a/awx/api/views.py b/awx/api/views.py index e49741f14e..ad2cffeb19 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -135,6 +135,8 @@ class ApiV1RootView(APIView): data['system_job_templates'] = reverse('api:system_job_template_list') data['system_jobs'] = reverse('api:system_job_list') data['schedules'] = reverse('api:schedule_list') + data['roles'] = reverse('api:role_list') + data['resources'] = reverse('api:resource_list') data['unified_job_templates'] = reverse('api:unified_job_template_list') data['unified_jobs'] = reverse('api:unified_job_list') data['activity_stream'] = reverse('api:activity_stream_list') @@ -3160,6 +3162,15 @@ class ResourceDetail(RetrieveAPIView): def get_queryset(self): return Resource.objects +class ResourceList(ListAPIView): + + model = Resource + serializer_class = ResourceSerializer + new_in_300 = True + + def get_queryset(self): + return Resource.objects.filter(permissions__role__ancestors__members=self.request.user) + class ResourceAccessList(ListAPIView): model = User