text: from django.conf import settings
  from django.contrib.auth import authenticate, get_user_model
  from django.contrib.auth.forms import SetPasswordForm, PasswordResetForm
  from django.urls import exceptions as url_exceptions
  from django.utils.encoding import force_str
  from django.utils.module_loading import import_string
  from django.utils.translation import gettext_lazy as _
  from rest_framework import exceptions, serializers
  from rest_framework.exceptions import ValidationError
  
  if 'allauth' in settings.INSTALLED_APPS:
      from .forms import AllAuthPasswordResetForm
  
  from .models import TokenModel
  
  # Get the UserModel
  UserModel = get_user_model()
  
  
  class LoginSerializer(serializers.Serializer):
      email = serializers.EmailField(required=False, allow_blank=True)
      password = serializers.CharField(style={'input_type': 'password'})
  
      def authenticate(self, **kwargs):
          return authenticate(self.context['request'], **kwargs)
  
      def _validate_email(self, email, password):
          if email and password:
              user = self.authenticate(email=email, password=password)
          else:
              msg = _('Must include "email" and "password".')
              raise exceptions.ValidationError(msg)
  
          return user
  
      def get_auth_user_using_allauth(self, email, password):
          return self._validate_email(email, password)
  
  
      def get_auth_user_using_orm(self, email, password):
          if email:
              try:
                  username = UserModel.objects.get(email__iexact=email).get_username()
              except UserModel.DoesNotExist:
                  pass
  
          if username:
              return self._validate_email(email, password)
  
          return None
  
      def get_auth_user(self, email, password):
          """
          Retrieve the auth user from given POST payload by using
          either `allauth` auth scheme or bare Django auth scheme.
  
          Returns the authenticated user instance if credentials are correct,
          else `None` will be returned
          """
          if 'allauth' in settings.INSTALLED_APPS:
  
              # When `is_active` of a user is set to False, allauth tries to return template html
              # which does not exist. This is the solution for it. See issue #264.
              try:
                  return self.get_auth_user_using_allauth(email, password)
              except url_exceptions.NoReverseMatch:
                  msg = _('Unable to log in with provided credentials.')
                  raise exceptions.ValidationError(msg)
          return self.get_auth_user_using_orm(email, password)
  
      @staticmethod
      def validate_auth_user_status(user):
          if not user.is_active:
              msg = _('User account is disabled.')
              raise exceptions.ValidationError(msg)
  
      @staticmethod
      def validate_email_verification_status(user):
          from allauth.account import app_settings
          if app_settings.EMAIL_VERIFICATION == app_settings.EmailVerificationMethod.MANDATORY:
              email_address = user.emailaddress_set.get(email=user.email)
              if not email_address.verified:
                  raise serializers.ValidationError(_('E-mail is not verified.'))
  
      def validate(self, attrs):
          email = attrs.get('email')
          password = attrs.get('password')
          user = self.get_auth_user(email, password)
  
          if not user:
              msg = _('Unable to log in with provided credentials.')
              raise exceptions.ValidationError(msg)
  
          # Did we get back an active user?
          self.validate_auth_user_status(user)
  
          # If required, is the email verified?
          if 'backend.rest_auth.registration' in settings.INSTALLED_APPS:
              self.validate_email_verification_status(user)
  
          attrs['user'] = user
          return attrs
  
  
  class TokenSerializer(serializers.ModelSerializer):
      """
      Serializer for Token model.
      """
  
      class Meta:
          model = TokenModel
          fields = ('key',)
  
  
  class UserDetailsSerializer(serializers.ModelSerializer):
      """
      User model w/o password
      """
  
      @staticmethod
      def validate_username(username):
          if 'allauth.account' not in settings.INSTALLED_APPS:
              # We don't need to call the all-auth
              # username validator unless its installed
              return username
  
          from allauth.account.adapter import get_adapter
          username = get_adapter().clean_username(username)
          return username
  
      class Meta:
          extra_fields = []
          # see https://github.com/iMerica/dj-rest-auth/issues/181
          # UserModel.XYZ causing attribute error while importing other
          # classes from `serializers.py`. So, we need to check whether the auth model has
          # the attribute or not
          if hasattr(UserModel, 'USERNAME_FIELD'):
              extra_fields.append(UserModel.USERNAME_FIELD)
          if hasattr(UserModel, 'EMAIL_FIELD'):
              extra_fields.append(UserModel.EMAIL_FIELD)
          if hasattr(UserModel, 'first_name'):
              extra_fields.append('first_name')
          if hasattr(UserModel, 'last_name'):
              extra_fields.append('last_name')
          model = UserModel
          fields = ('pk', *extra_fields)
          read_only_fields = ('email',)
  
  
  class JWTSerializer(serializers.Serializer):
      """
      Serializer for JWT authentication.
      """
      access_token = serializers.CharField()
      refresh_token = serializers.CharField()
      user = serializers.SerializerMethodField()
  
      def get_user(self, obj):
          """
          Required to allow using custom USER_DETAILS_SERIALIZER in
          JWTSerializer. Defining it here to avoid circular imports
          """
          rest_auth_serializers = getattr(settings, 'REST_AUTH_SERIALIZERS', {})
  
          JWTUserDetailsSerializer = import_string(
              rest_auth_serializers.get(
                  'USER_DETAILS_SERIALIZER',
                  'backend.rest_auth.serializers.UserDetailsSerializer',
              ),
          )
  
          user_data = JWTUserDetailsSerializer(obj['user'], context=self.context).data
          return user_data
  
  
  class JWTSerializerWithExpiration(JWTSerializer):
      """
      Serializer for JWT authentication with expiration times.
      """
      access_token_expiration = serializers.DateTimeField()
      refresh_token_expiration = serializers.DateTimeField()
  
  
  class PasswordResetSerializer(serializers.Serializer):
      """
      Serializer for requesting a password reset e-mail.
      """
      email = serializers.EmailField()
  
      reset_form = None
  
      @property
      def password_reset_form_class(self):
          if 'allauth' in settings.INSTALLED_APPS:
              return AllAuthPasswordResetForm
          else:
              return PasswordResetForm
  
      def get_email_options(self):
          """Override this method to change default e-mail options"""
          return {}
  
      def validate_email(self, value):
          # Create PasswordResetForm with the serializer
          self.reset_form = self.password_reset_form_class(data=self.initial_data)
          if not self.reset_form.is_valid():
              raise serializers.ValidationError(self.reset_form.errors)
  
          return value
  
      def save(self):
          if 'allauth' in settings.INSTALLED_APPS:
              from allauth.account.forms import default_token_generator
          else:
              from django.contrib.auth.tokens import default_token_generator
  
          request = self.context.get('request')
          # Set some values to trigger the send_email method.
          opts = {
              'use_https': request.is_secure(),
              'from_email': getattr(settings, 'DEFAULT_FROM_EMAIL'),
              'request': request,
              'token_generator': default_token_generator,
          }
  
          opts.update(self.get_email_options())
          self.reset_form.save(**opts)
  
  
  class PasswordResetConfirmSerializer(serializers.Serializer):
      """
      Serializer for confirming a password reset attempt.
      """
      new_password1 = serializers.CharField(max_length=128)
      new_password2 = serializers.CharField(max_length=128)
      uid = serializers.CharField()
      token = serializers.CharField()
  
      set_password_form_class = SetPasswordForm
  
      _errors = {}
      user = None
      set_password_form = None
  
      def custom_validation(self, attrs):
          pass
  
      def validate(self, attrs):
          if 'allauth' in settings.INSTALLED_APPS:
              from allauth.account.forms import default_token_generator
              from allauth.account.utils import url_str_to_user_pk as uid_decoder
          else:
              from django.contrib.auth.tokens import default_token_generator
              from django.utils.http import urlsafe_base64_decode as uid_decoder
  
          # Decode the uidb64 (allauth use base36) to uid to get User object
          try:
              uid = force_str(uid_decoder(attrs['uid']))
              self.user = UserModel._default_manager.get(pk=uid)
          except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
              raise ValidationError({'uid': ['Invalid value']})
  
          if not default_token_generator.check_token(self.user, attrs['token']):
              raise ValidationError({'token': ['Invalid value']})
  
          self.custom_validation(attrs)
          # Construct SetPasswordForm instance
          self.set_password_form = self.set_password_form_class(
              user=self.user, data=attrs,
          )
          if not self.set_password_form.is_valid():
              raise serializers.ValidationError(self.set_password_form.errors)
  
          return attrs
  
      def save(self):
          return self.set_password_form.save()
  
  
  class PasswordChangeSerializer(serializers.Serializer):
      old_password = serializers.CharField(max_length=128)
      new_password1 = serializers.CharField(max_length=128)
      new_password2 = serializers.CharField(max_length=128)
  
      set_password_form_class = SetPasswordForm
  
      set_password_form = None
  
      def __init__(self, *args, **kwargs):
          self.old_password_field_enabled = getattr(
              settings, 'OLD_PASSWORD_FIELD_ENABLED', False,
          )
          self.logout_on_password_change = getattr(
              settings, 'LOGOUT_ON_PASSWORD_CHANGE', False,
          )
          super().__init__(*args, **kwargs)
  
          if not self.old_password_field_enabled:
              self.fields.pop('old_password')
  
          self.request = self.context.get('request')
          self.user = getattr(self.request, 'user', None)
  
      def validate_old_password(self, value):
          invalid_password_conditions = (
              self.old_password_field_enabled,
              self.user,
              not self.user.check_password(value),
          )
  
          if all(invalid_password_conditions):
              err_msg = _('Your old password was entered incorrectly. Please enter it again.')
              raise serializers.ValidationError(err_msg)
          return value
  
      def validate(self, attrs):
          self.set_password_form = self.set_password_form_class(
              user=self.user, data=attrs,
          )
  
          if not self.set_password_form.is_valid():
              raise serializers.ValidationError(self.set_password_form.errors)
          return attrs
  
      def save(self):
          self.set_password_form.save()
          if not self.logout_on_password_change:
              from django.contrib.auth import update_session_auth_hash
              update_session_auth_hash(self.request, self.user)
  