text: from __future__ import unicode_literals
  
  from collections import OrderedDict
  
  from django import forms
  from django.core.mail import EmailMultiAlternatives
  from django.forms.utils import flatatt
  from django.template import loader
  from django.utils.encoding import force_bytes
  from django.utils.html import format_html, format_html_join
  from django.utils.http import urlsafe_base64_encode
  from django.utils.safestring import mark_safe
  from django.utils.text import capfirst
  from django.utils.translation import ugettext, ugettext_lazy as _
  
  from django.contrib.auth import authenticate, get_user_model
  from django.contrib.auth.models import User
  from django.contrib.auth.hashers import UNUSABLE_PASSWORD_PREFIX, identify_hasher
  from django.contrib.auth.tokens import default_token_generator
  from django.contrib.sites.shortcuts import get_current_site
  
  
  UNMASKED_DIGITS_TO_SHOW = 6
  
  
  def mask_password(password):
      shown = password[:UNMASKED_DIGITS_TO_SHOW]
      masked = "*" * max(len(password) - UNMASKED_DIGITS_TO_SHOW, 0)
      return shown + masked
  
  
  class ReadOnlyPasswordHashWidget(forms.Widget):
      def render(self, name, value, attrs):
          encoded = value
          final_attrs = self.build_attrs(attrs)
  
          if not encoded or encoded.startswith(UNUSABLE_PASSWORD_PREFIX):
              summary = mark_safe("<strong>%s</strong>" % ugettext("No password set."))
          else:
              try:
                  hasher = identify_hasher(encoded)
              except ValueError:
                  summary = mark_safe("<strong>%s</strong>" % ugettext(
                      "Invalid password format or unknown hashing algorithm."))
              else:
                  summary = format_html_join('',
                                             "<strong>{0}</strong>: {1} ",
                                             ((ugettext(key), value)
                                              for key, value in hasher.safe_summary(encoded).items())
                                             )
  
          return format_html("<div{0}>{1}</div>", flatatt(final_attrs), summary)
  
  
  class ReadOnlyPasswordHashField(forms.Field):
      widget = ReadOnlyPasswordHashWidget
  
      def __init__(self, *args, **kwargs):
          kwargs.setdefault("required", False)
          super(ReadOnlyPasswordHashField, self).__init__(*args, **kwargs)
  
      def bound_data(self, data, initial):
          # Always return initial because the widget doesn't
          # render an input field.
          return initial
  
      def has_changed(self, initial, data):
          return False
  
  
  class UserCreationForm(forms.ModelForm):
      """
      A form that creates a user, with no privileges, from the given username and
      password.
      """
      error_messages = {
          'password_mismatch': _("The two password fields didn't match."),
      }
      password1 = forms.CharField(label=_("Password"),
          widget=forms.PasswordInput)
      password2 = forms.CharField(label=_("Password confirmation"),
          widget=forms.PasswordInput,
          help_text=_("Enter the same password as above, for verification."))
  
      class Meta:
          model = User
          fields = ("username",)
  
      def clean_password2(self):
          password1 = self.cleaned_data.get("password1")
          password2 = self.cleaned_data.get("password2")
          if password1 and password2 and password1 != password2:
              raise forms.ValidationError(
                  self.error_messages['password_mismatch'],
                  code='password_mismatch',
              )
          return password2
  
      def save(self, commit=True):
          user = super(UserCreationForm, self).save(commit=False)
          user.set_password(self.cleaned_data["password1"])
          if commit:
              user.save()
          return user
  
  
  class UserChangeForm(forms.ModelForm):
      password = ReadOnlyPasswordHashField(label=_("Password"),
          help_text=_("Raw passwords are not stored, so there is no way to see "
                      "this user's password, but you can change the password "
                      "using <a href=\"password/\">this form</a>."))
  
      class Meta:
          model = User
          fields = '__all__'
  
      def __init__(self, *args, **kwargs):
          super(UserChangeForm, self).__init__(*args, **kwargs)
          f = self.fields.get('user_permissions', None)
          if f is not None:
              f.queryset = f.queryset.select_related('content_type')
  
      def clean_password(self):
          # Regardless of what the user provides, return the initial value.
          # This is done here, rather than on the field, because the
          # field does not have access to the initial value
          return self.initial["password"]
  
  
  class AuthenticationForm(forms.Form):
      """
      Base class for authenticating users. Extend this to get a form that accepts
      username/password logins.
      """
      username = forms.CharField(max_length=254)
      password = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
  
      error_messages = {
          'invalid_login': _("Please enter a correct %(username)s and password. "
                             "Note that both fields may be case-sensitive."),
          'inactive': _("This account is inactive."),
      }
  
      def __init__(self, request=None, *args, **kwargs):
          """
          The 'request' parameter is set for custom auth use by subclasses.
          The form data comes in via the standard 'data' kwarg.
          """
          self.request = request
          self.user_cache = None
          super(AuthenticationForm, self).__init__(*args, **kwargs)
  
          # Set the label for the "username" field.
          UserModel = get_user_model()
          self.username_field = UserModel._meta.get_field(UserModel.USERNAME_FIELD)
          if self.fields['username'].label is None:
              self.fields['username'].label = capfirst(self.username_field.verbose_name)
  
      def clean(self):
          username = self.cleaned_data.get('username')
          password = self.cleaned_data.get('password')
  
          if username and password:
              self.user_cache = authenticate(username=username,
                                             password=password)
              if self.user_cache is None:
                  raise forms.ValidationError(
                      self.error_messages['invalid_login'],
                      code='invalid_login',
                      params={'username': self.username_field.verbose_name},
                  )
              else:
                  self.confirm_login_allowed(self.user_cache)
  
          return self.cleaned_data
  
      def confirm_login_allowed(self, user):
          """
          Controls whether the given User may log in. This is a policy setting,
          independent of end-user authentication. This default behavior is to
          allow login by active users, and reject login by inactive users.
  
          If the given user cannot log in, this method should raise a
          ``forms.ValidationError``.
  
          If the given user may log in, this method should return None.
          """
          if not user.is_active:
              raise forms.ValidationError(
                  self.error_messages['inactive'],
                  code='inactive',
              )
  
      def get_user_id(self):
          if self.user_cache:
              return self.user_cache.id
          return None
  
      def get_user(self):
          return self.user_cache
  
  
  class PasswordResetForm(forms.Form):
      email = forms.EmailField(label=_("Email"), max_length=254)
  
      def send_mail(self, subject_template_name, email_template_name,
                    context, from_email, to_email, html_email_template_name=None):
          """
          Sends a django.core.mail.EmailMultiAlternatives to `to_email`.
          """
          subject = loader.render_to_string(subject_template_name, context)
          # Email subject *must not* contain newlines
          subject = ''.join(subject.splitlines())
          body = loader.render_to_string(email_template_name, context)
  
          email_message = EmailMultiAlternatives(subject, body, from_email, [to_email])
          if html_email_template_name is not None:
              html_email = loader.render_to_string(html_email_template_name, context)
              email_message.attach_alternative(html_email, 'text/html')
  
          email_message.send()
  
      def save(self, domain_override=None,
               subject_template_name='registration/password_reset_subject.txt',
               email_template_name='registration/password_reset_email.html',
               use_https=False, token_generator=default_token_generator,
               from_email=None, request=None, html_email_template_name=None):
          """
          Generates a one-use only link for resetting password and sends to the
          user.
          """
          UserModel = get_user_model()
          email = self.cleaned_data["email"]
          active_users = UserModel._default_manager.filter(
              email__iexact=email, is_active=True)
          for user in active_users:
              # Make sure that no email is sent to a user that actually has
              # a password marked as unusable
              if not user.has_usable_password():
                  continue
              if not domain_override:
                  current_site = get_current_site(request)
                  site_name = current_site.name
                  domain = current_site.domain
              else:
                  site_name = domain = domain_override
              context = {
                  'email': user.email,
                  'domain': domain,
                  'site_name': site_name,
                  'uid': urlsafe_base64_encode(force_bytes(user.pk)),
                  'user': user,
                  'token': token_generator.make_token(user),
                  'protocol': 'https' if use_https else 'http',
              }
  
              self.send_mail(subject_template_name, email_template_name,
                             context, from_email, user.email,
                             html_email_template_name=html_email_template_name)
  
  
  class SetPasswordForm(forms.Form):
      """
      A form that lets a user change set their password without entering the old
      password
      """
      error_messages = {
          'password_mismatch': _("The two password fields didn't match."),
      }
      new_password1 = forms.CharField(label=_("New password"),
                                      widget=forms.PasswordInput)
      new_password2 = forms.CharField(label=_("New password confirmation"),
                                      widget=forms.PasswordInput)
  
      def __init__(self, user, *args, **kwargs):
          self.user = user
          super(SetPasswordForm, self).__init__(*args, **kwargs)
  
      def clean_new_password2(self):
          password1 = self.cleaned_data.get('new_password1')
          password2 = self.cleaned_data.get('new_password2')
          if password1 and password2:
              if password1 != password2:
                  raise forms.ValidationError(
                      self.error_messages['password_mismatch'],
                      code='password_mismatch',
                  )
          return password2
  
      def save(self, commit=True):
          self.user.set_password(self.cleaned_data['new_password1'])
          if commit:
              self.user.save()
          return self.user
  
  
  class PasswordChangeForm(SetPasswordForm):
      """
      A form that lets a user change their password by entering their old
      password.
      """
      error_messages = dict(SetPasswordForm.error_messages, **{
          'password_incorrect': _("Your old password was entered incorrectly. "
                                  "Please enter it again."),
      })
      old_password = forms.CharField(label=_("Old password"),
                                     widget=forms.PasswordInput)
  
      def clean_old_password(self):
          """
          Validates that the old_password field is correct.
          """
          old_password = self.cleaned_data["old_password"]
          if not self.user.check_password(old_password):
              raise forms.ValidationError(
                  self.error_messages['password_incorrect'],
                  code='password_incorrect',
              )
          return old_password
  
  PasswordChangeForm.base_fields = OrderedDict(
      (k, PasswordChangeForm.base_fields[k])
      for k in ['old_password', 'new_password1', 'new_password2']
  )
  
  
  class AdminPasswordChangeForm(forms.Form):
      """
      A form used to change the password of a user in the admin interface.
      """
      error_messages = {
          'password_mismatch': _("The two password fields didn't match."),
      }
      required_css_class = 'required'
      password1 = forms.CharField(label=_("Password"),
                                  widget=forms.PasswordInput)
      password2 = forms.CharField(label=_("Password (again)"),
                                  widget=forms.PasswordInput)
  
      def __init__(self, user, *args, **kwargs):
          self.user = user
          super(AdminPasswordChangeForm, self).__init__(*args, **kwargs)
  
      def clean_password2(self):
          password1 = self.cleaned_data.get('password1')
          password2 = self.cleaned_data.get('password2')
          if password1 and password2:
              if password1 != password2:
                  raise forms.ValidationError(
                      self.error_messages['password_mismatch'],
                      code='password_mismatch',
                  )
          return password2
  
      def save(self, commit=True):
          """
          Saves the new password.
          """
          self.user.set_password(self.cleaned_data["password1"])
          if commit:
              self.user.save()
          return self.user
  
      def _get_changed_data(self):
          data = super(AdminPasswordChangeForm, self).changed_data
          for name in self.fields.keys():
              if name not in data:
                  return []
          return ['password']
      changed_data = property(_get_changed_data)
  