mirror of
https://github.com/ansible/awx.git
synced 2024-11-01 08:21:15 +03:00
Merge pull request #7150 from ryanpetrello/fix-7115
filter CredentialType OPTIONS *and* help text for `kind` requirements
This commit is contained in:
commit
628a0620ac
@ -287,7 +287,13 @@ class GenericAPIView(generics.GenericAPIView, APIView):
|
||||
'model_verbose_name': smart_text(self.model._meta.verbose_name),
|
||||
'model_verbose_name_plural': smart_text(self.model._meta.verbose_name_plural),
|
||||
})
|
||||
d['serializer_fields'] = self.metadata_class().get_serializer_info(self.get_serializer())
|
||||
serializer = self.get_serializer()
|
||||
for method, key in [
|
||||
('GET', 'serializer_fields'),
|
||||
('POST', 'serializer_create_fields'),
|
||||
('PUT', 'serializer_update_fields')
|
||||
]:
|
||||
d[key] = self.metadata_class().get_serializer_info(serializer, method=method)
|
||||
d['settings'] = settings
|
||||
d['has_named_url'] = self.model in settings.NAMED_URL_GRAPH
|
||||
return d
|
||||
|
@ -17,7 +17,7 @@ from rest_framework.relations import RelatedField, ManyRelatedField
|
||||
from rest_framework.request import clone_request
|
||||
|
||||
# Ansible Tower
|
||||
from awx.main.models import InventorySource, NotificationTemplate, CredentialType
|
||||
from awx.main.models import InventorySource, NotificationTemplate
|
||||
|
||||
|
||||
class Metadata(metadata.SimpleMetadata):
|
||||
@ -117,6 +117,13 @@ class Metadata(metadata.SimpleMetadata):
|
||||
|
||||
return field_info
|
||||
|
||||
def get_serializer_info(self, serializer, method=None):
|
||||
filterer = getattr(serializer, 'filter_field_metadata', lambda fields, method: fields)
|
||||
return filterer(
|
||||
super(Metadata, self).get_serializer_info(serializer),
|
||||
method
|
||||
)
|
||||
|
||||
def determine_actions(self, request, view):
|
||||
# Add field information for GET requests (so field names/labels are
|
||||
# available even when we can't POST/PUT).
|
||||
@ -137,7 +144,7 @@ class Metadata(metadata.SimpleMetadata):
|
||||
# If user has appropriate permissions for the view, include
|
||||
# appropriate metadata about the fields that should be supplied.
|
||||
serializer = view.get_serializer(instance=obj)
|
||||
actions[method] = self.get_serializer_info(serializer)
|
||||
actions[method] = self.get_serializer_info(serializer, method=method)
|
||||
finally:
|
||||
view.request = request
|
||||
|
||||
@ -149,16 +156,6 @@ class Metadata(metadata.SimpleMetadata):
|
||||
if field == 'type' and hasattr(serializer, 'get_type_choices'):
|
||||
meta['choices'] = serializer.get_type_choices()
|
||||
|
||||
# API-created/modified CredentialType kinds are limited to
|
||||
# `cloud` and `network`
|
||||
if method != 'GET' and \
|
||||
hasattr(serializer, 'Meta') and \
|
||||
getattr(serializer.Meta, 'model', None) is CredentialType:
|
||||
actions[method]['kind']['choices'] = filter(
|
||||
lambda choice: choice[0] in ('cloud', 'net'),
|
||||
actions[method]['kind']['choices']
|
||||
)
|
||||
|
||||
# For GET method, remove meta attributes that aren't relevant
|
||||
# when reading a field and remove write-only fields.
|
||||
if method == 'GET':
|
||||
|
@ -287,6 +287,13 @@ class BaseSerializer(serializers.ModelSerializer):
|
||||
else:
|
||||
return obj.get_absolute_url(request=self.context.get('request'))
|
||||
|
||||
def filter_field_metadata(self, fields, method):
|
||||
"""
|
||||
Filter field metadata based on the request method.
|
||||
This it intended to be extended by subclasses.
|
||||
"""
|
||||
return fields
|
||||
|
||||
def _get_related(self, obj):
|
||||
return {} if obj is None else self.get_related(obj)
|
||||
|
||||
@ -1957,6 +1964,16 @@ class CredentialTypeSerializer(BaseSerializer):
|
||||
field['help_text'] = _(field['help_text'])
|
||||
return value
|
||||
|
||||
def filter_field_metadata(self, fields, method):
|
||||
# API-created/modified CredentialType kinds are limited to
|
||||
# `cloud` and `net`
|
||||
if method in ('PUT', 'POST'):
|
||||
fields['kind']['choices'] = filter(
|
||||
lambda choice: choice[0] in ('cloud', 'net'),
|
||||
fields['kind']['choices']
|
||||
)
|
||||
return fields
|
||||
|
||||
|
||||
# TODO: remove when API v1 is removed
|
||||
@six.add_metaclass(BaseSerializerMetaclass)
|
||||
|
@ -6,7 +6,7 @@ Make a POST request to this resource with the following {{ model_verbose_name }}
|
||||
fields to create a new {{ model_verbose_name }}:
|
||||
|
||||
{% with write_only=1 %}
|
||||
{% include "api/_result_fields_common.md" %}
|
||||
{% include "api/_result_fields_common.md" with serializer_fields=serializer_create_fields %}
|
||||
{% endwith %}
|
||||
|
||||
{% include "api/_new_in_awx.md" %}
|
||||
|
@ -15,7 +15,7 @@ Make a PUT or PATCH request to this resource to update this
|
||||
{{ model_verbose_name }}. The following fields may be modified:
|
||||
|
||||
{% with write_only=1 %}
|
||||
{% include "api/_result_fields_common.md" %}
|
||||
{% include "api/_result_fields_common.md" with serializer_fields=serializer_update_fields %}
|
||||
{% endwith %}
|
||||
|
||||
For a PUT request, include **all** fields in the request.
|
||||
|
@ -15,7 +15,7 @@ Make a PUT or PATCH request to this resource to update this
|
||||
{{ model_verbose_name }}. The following fields may be modified:
|
||||
|
||||
{% with write_only=1 %}
|
||||
{% include "api/_result_fields_common.md" %}
|
||||
{% include "api/_result_fields_common.md" with serializer_fields=serializer_update_fields %}
|
||||
{% endwith %}
|
||||
|
||||
For a PUT request, include **all** fields in the request.
|
||||
|
@ -12,6 +12,26 @@ def test_list_as_unauthorized_xfail(get):
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize('method, valid', [
|
||||
('GET', sorted(dict(CredentialType.KIND_CHOICES).keys())),
|
||||
('POST', ['cloud', 'net']),
|
||||
])
|
||||
def test_options_valid_kinds(method, valid, options, admin):
|
||||
response = options(reverse('api:credential_type_list'), admin)
|
||||
choices = sorted(dict(response.data['actions'][method]['kind']['choices']).keys())
|
||||
assert valid == choices
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_options_valid_put_kinds(options, admin):
|
||||
ssh = CredentialType.defaults['ssh']()
|
||||
ssh.save()
|
||||
response = options(reverse('api:credential_type_detail', kwargs={'pk': ssh.pk}), admin)
|
||||
choices = sorted(dict(response.data['actions']['PUT']['kind']['choices']).keys())
|
||||
assert ['cloud', 'net'] == choices
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_list_as_normal_user(get, alice):
|
||||
ssh = CredentialType.defaults['ssh']()
|
||||
|
Loading…
Reference in New Issue
Block a user