# Django 1.8.18.dev20170123152445 documentation

# Source code for django.contrib.auth.forms

    from __future__ import unicode_literals

    from collections import OrderedDict

    from django import forms
    from django.contrib.auth import authenticate, get_user_model
    from django.contrib.auth.hashers import (
        UNUSABLE_PASSWORD_PREFIX, identify_hasher,
    )
    from django.contrib.auth.models import User
    from django.contrib.auth.tokens import default_token_generator
    from django.contrib.sites.shortcuts import get_current_site
    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 _

    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>{}</strong>: {} ",
                                               ((ugettext(key), value)
                                                for key, value in hasher.safe_summary(encoded).items())
                                               )

            return format_html("<div{}>{}</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 get_users(self, email):
            """Given an email, return matching user(s) who should receive a reset.

            This allows subclasses to more easily customize the default policies
            that prevent inactive users and users with unusable passwords from
            resetting their password.

            """
            active_users = get_user_model()._default_manager.filter(
                email__iexact=email, is_active=True)
            return (u for u in active_users if u.has_usable_password())

        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.
            """
            email = self.cleaned_data["email"]
            for user in self.get_users(email):
                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,
            help_text=_("Enter the same password as above, for verification."),
        )

        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)