text: # Copyright (c) 2016 Ansible, Inc.
  # All Rights Reserved.
  
  # Django
  from django.utils.translation import ugettext_lazy as _
  from django.core.exceptions import ObjectDoesNotExist
  
  # Django REST Framework
  from rest_framework import serializers
  
  # AWX
  from awx.conf import fields
  from awx.main.models import Credential
  
  __all__ = ['BooleanNullField', 'CharNullField', 'ChoiceNullField', 'VerbatimField']
  
  
  class NullFieldMixin(object):
      '''
      Mixin to prevent shortcutting validation when we want to allow null input,
      but coerce the resulting value to another type.
      '''
  
      def validate_empty_values(self, data):
          (is_empty_value, data) = super(NullFieldMixin, self).validate_empty_values(data)
          if is_empty_value and data is None:
              return (False, data)
          return (is_empty_value, data)
  
  
  class BooleanNullField(NullFieldMixin, serializers.NullBooleanField):
      '''
      Custom boolean field that allows null and empty string as False values.
      '''
  
      def to_internal_value(self, data):
          return bool(super(BooleanNullField, self).to_internal_value(data))
  
  
  class CharNullField(NullFieldMixin, serializers.CharField):
      '''
      Custom char field that allows null as input and coerces to an empty string.
      '''
  
      def __init__(self, **kwargs):
          kwargs['allow_null'] = True
          super(CharNullField, self).__init__(**kwargs)
  
      def to_internal_value(self, data):
          return super(CharNullField, self).to_internal_value(data or u'')
  
  
  class ChoiceNullField(NullFieldMixin, serializers.ChoiceField):
      '''
      Custom choice field that allows null as input and coerces to an empty string.
      '''
  
      def __init__(self, **kwargs):
          kwargs['allow_null'] = True
          super(ChoiceNullField, self).__init__(**kwargs)
  
      def to_internal_value(self, data):
          return super(ChoiceNullField, self).to_internal_value(data or u'')
  
  
  class VerbatimField(serializers.Field):
      '''
      Custom field that passes the value through without changes.
      '''
  
      def to_internal_value(self, data):
          return data
  
      def to_representation(self, value):
          return value
  
  
  class OAuth2ProviderField(fields.DictField):
  
      default_error_messages = {
          'invalid_key_names': _('Invalid key names: {invalid_key_names}'),
      }
      valid_key_names = {'ACCESS_TOKEN_EXPIRE_SECONDS', 'AUTHORIZATION_CODE_EXPIRE_SECONDS', 'REFRESH_TOKEN_EXPIRE_SECONDS'}
      child = fields.IntegerField(min_value=1)
  
      def to_internal_value(self, data):
          data = super(OAuth2ProviderField, self).to_internal_value(data)
          invalid_flags = (set(data.keys()) - self.valid_key_names)
          if invalid_flags:
              self.fail('invalid_key_names', invalid_key_names=', '.join(list(invalid_flags)))
          return data
  
  
  class DeprecatedCredentialField(serializers.IntegerField):
  
      def __init__(self, **kwargs):
          kwargs['allow_null'] = True
          kwargs['default'] = None
          kwargs['min_value'] = 1
          kwargs.setdefault('help_text', 'This resource has been deprecated and will be removed in a future release')
          super(DeprecatedCredentialField, self).__init__(**kwargs)
  
      def to_internal_value(self, pk):
          try:
              pk = int(pk)
          except ValueError:
              self.fail('invalid')
          try:
              Credential.objects.get(pk=pk)
          except ObjectDoesNotExist:
              raise serializers.ValidationError(_('Credential {} does not exist').format(pk))
          return pk
  