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:
parent
efcd4efda2
commit
1989012fd5
@ -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))
|
||||
|
||||
|
@ -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,))
|
||||
|
@ -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)),
|
||||
|
@ -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))
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user