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:
parent
67a1b8ce81
commit
cf7102bc49
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 %}
|
||||
|
@ -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):
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user