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

Move validation of credential creation to the serializer. Use SubListCreateAPIView for creating a credential under another object, and remove fields from serializer and API docs that aren't valid when creating a credential under another object.

This commit is contained in:
Chris Church 2016-06-15 18:24:28 -04:00
parent 67a1b8ce81
commit cf7102bc49
4 changed files with 71 additions and 81 deletions

View File

@ -9,6 +9,7 @@ import time
# Django
from django.conf import settings
from django.db import connection
from django.http import QueryDict
from django.shortcuts import get_object_or_404
from django.template.loader import render_to_string
from django.utils.encoding import smart_text
@ -328,10 +329,11 @@ class SubListCreateAPIView(SubListAPIView, ListCreateAPIView):
# Make a copy of the data provided (since it's readonly) in order to
# inject additional data.
if hasattr(request.data, 'dict'):
data = request.data.dict()
if hasattr(request.data, 'copy'):
data = request.data.copy()
else:
data = request.data
data = QueryDict('')
data.update(request.data)
# add the parent key to the post data using the pk from the URL
parent_key = getattr(self, 'parent_key', None)

View File

@ -1701,11 +1701,51 @@ class CredentialSerializerCreate(CredentialSerializer):
model = Credential
fields = ('*', 'user', 'team', 'organization')
def validate(self, attrs):
owner_fields = set()
for field in ('user', 'team', 'organization'):
if field in attrs:
if attrs[field]:
owner_fields.add(field)
else:
attrs.pop(field)
if not owner_fields:
raise serializers.ValidationError({"detail": "Missing 'user', 'team', or 'organization'."})
elif len(owner_fields) > 1:
raise serializers.ValidationError({"detail": "Expecting exactly one of 'user', 'team', or 'organization'."})
return super(CredentialSerializerCreate, self).validate(attrs)
def create(self, validated_data):
# Remove the user, team, and organization processed in view
for field in ['user', 'team', 'organization']:
validated_data.pop(field, None)
return super(CredentialSerializer, self).create(validated_data)
user = validated_data.pop('user', None)
team = validated_data.pop('team', None)
credential = super(CredentialSerializer, self).create(validated_data)
if user:
credential.owner_role.members.add(user)
if team:
credential.owner_role.parents.add(team.member_role)
return credential
class UserCredentialSerializerCreate(CredentialSerializerCreate):
class Meta:
model = Credential
fields = ('*', '-team', '-organization')
class TeamCredentialSerializerCreate(CredentialSerializerCreate):
class Meta:
model = Credential
fields = ('*', '-user', '-organization')
class OrganizationCredentialSerializerCreate(CredentialSerializerCreate):
class Meta:
model = Credential
fields = ('*', '-user', '-team')
class JobOptionsSerializer(BaseSerializer):
@ -2731,4 +2771,3 @@ class FactSerializer(BaseFactSerializer):
res = super(FactSerializer, self).get_related(obj)
res['host'] = obj.host.get_absolute_url()
return res

View File

@ -1,5 +1,5 @@
{% for fn, fm in serializer_fields.items %}{% spaceless %}
{% if write_only and fm.read_only or not write_only and fm.write_only %}
{% if write_only and fm.read_only or not write_only and fm.write_only or write_only and fn == parent_key %}
{% else %}
* `{{ fn }}`: {{ fm.help_text|capfirst }} ({{ fm.type }}{% if write_only and fm.required %}, required{% endif %}{% if write_only and fm.read_only %}, read-only{% endif %}{% if write_only and not fm.choices and not fm.required %}, default=`{% if fm.type == "string" or fm.type == "email" %}"{% firstof fm.default "" %}"{% else %}{% if fm.type == "field" and not fm.default %}None{% else %}{{ fm.default }}{% endif %}{% endif %}`{% endif %}){% if fm.choices %}{% for c in fm.choices %}
- `{% if c.0 == "" %}""{% else %}{{ c.0 }}{% endif %}`{% if c.1 != c.0 %}: {{ c.1 }}{% endif %}{% if write_only and c.0 == fm.default %} (default){% endif %}{% endfor %}{% endif %}{% endif %}

View File

@ -1313,55 +1313,15 @@ class UserAccessList(ResourceAccessList):
resource_model = User
new_in_300 = True
class CredentialList(ListCreateAPIView):
model = Credential
serializer_class = CredentialSerializerCreate
def post(self, request, *args, **kwargs):
# Check the validity of POST data, including special fields
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
for field in [x for x in ['user', 'team', 'organization'] if x in request.data and request.data[x] in ('', None)]:
request.data.pop(field)
kwargs.pop(field, None)
if not any([x in request.data for x in ['user', 'team', 'organization']]):
return Response({"detail": "Missing 'user', 'team', or 'organization'."}, status=status.HTTP_400_BAD_REQUEST)
if sum([1 if x in request.data else 0 for x in ['user', 'team', 'organization']]) != 1:
return Response({"detail": "Expecting exactly one of 'user', 'team', or 'organization'."}, status=status.HTTP_400_BAD_REQUEST)
if 'user' in request.data:
user = User.objects.get(pk=request.data['user'])
can_add_params = {'user': user.id}
if 'team' in request.data:
team = Team.objects.get(pk=request.data['team'])
can_add_params = {'team': team.id}
if 'organization' in request.data:
organization = Organization.objects.get(pk=request.data['organization'])
can_add_params = {'organization': organization.id}
if not self.request.user.can_access(Credential, 'add', can_add_params):
raise PermissionDenied()
ret = super(CredentialList, self).post(request, *args, **kwargs)
credential = Credential.objects.get(id=ret.data['id'])
if 'user' in request.data:
credential.owner_role.members.add(user)
if 'team' in request.data:
credential.owner_role.parents.add(team.member_role)
if 'organization' in request.data:
credential.organization = organization
credential.save()
return ret
class CredentialOwnerUsersList(SubListAPIView):
model = User
serializer_class = UserSerializer
parent_model = Credential
@ -1370,6 +1330,7 @@ class CredentialOwnerUsersList(SubListAPIView):
class CredentialOwnerTeamsList(SubListAPIView):
model = Team
serializer_class = TeamSerializer
parent_model = Credential
@ -1386,53 +1347,48 @@ class CredentialOwnerTeamsList(SubListAPIView):
return self.model.objects.filter(pk__in=teams)
class UserCredentialsList(CredentialList):
class UserCredentialsList(SubListCreateAPIView):
model = Credential
serializer_class = CredentialSerializer
serializer_class = UserCredentialSerializerCreate
parent_model = User
parent_key = 'user'
def get_queryset(self):
user = get_object_or_404(User,pk=self.kwargs['pk'])
if not self.request.user.can_access(User, 'read', user):
raise PermissionDenied()
user = self.get_parent_object()
self.check_parent_access(user)
visible_creds = Credential.accessible_objects(self.request.user, 'read_role')
user_creds = Credential.accessible_objects(user, 'read_role')
return user_creds & visible_creds
def post(self, request, *args, **kwargs):
request.data['user'] = self.kwargs['pk']
# The following post takes care of ensuring the current user can add a cred to this user
return super(UserCredentialsList, self).post(request, args, kwargs)
class TeamCredentialsList(CredentialList):
class TeamCredentialsList(SubListCreateAPIView):
model = Credential
serializer_class = CredentialSerializer
serializer_class = TeamCredentialSerializerCreate
parent_model = Team
parent_key = 'team'
def get_queryset(self):
team = get_object_or_404(Team, pk=self.kwargs['pk'])
if not self.request.user.can_access(Team, 'read', team):
raise PermissionDenied()
team = self.get_parent_object()
self.check_parent_access(team)
visible_creds = Credential.accessible_objects(self.request.user, 'read_role')
team_creds = Credential.objects.filter(owner_role__parents=team.member_role)
return team_creds & visible_creds
def post(self, request, *args, **kwargs):
request.data['team'] = self.kwargs['pk']
# The following post takes care of ensuring the current user can add a cred to this user
return super(TeamCredentialsList, self).post(request, args, kwargs)
class OrganizationCredentialList(CredentialList):
class OrganizationCredentialList(SubListCreateAPIView):
model = Credential
serializer_class = CredentialSerializer
serializer_class = OrganizationCredentialSerializerCreate
parent_model = Organization
parent_key = 'organization'
def get_queryset(self):
organization = Organization.objects.get(pk=self.kwargs['pk'])
if not self.request.user.can_access(Organization, 'read', organization):
raise PermissionDenied()
organization = self.get_parent_object()
self.check_parent_access(organization)
user_visible = Credential.accessible_objects(self.request.user, 'read_role').all()
org_set = Credential.accessible_objects(organization.admin_role, 'read_role').all()
@ -1442,13 +1398,6 @@ class OrganizationCredentialList(CredentialList):
return org_set & user_visible
def post(self, request, *args, **kwargs):
organization = Organization.objects.get(pk=self.kwargs['pk'])
request.data['organization'] = organization.id
# The following post takes care of ensuring the current user can add a cred to this user
return super(OrganizationCredentialList, self).post(request, args, kwargs)
class CredentialDetail(RetrieveUpdateDestroyAPIView):