Source code for mezzanine.accounts.forms

from __future__ import unicode_literals

from django.contrib.auth import authenticate, get_user_model
from django.contrib.auth.tokens import default_token_generator
from django.db.models import Q
from django.db.models.manager import Manager
from django import forms
from django.utils.http import int_to_base36
from django.utils.translation import ugettext, ugettext_lazy as _

from mezzanine.accounts import (get_profile_model, get_profile_user_fieldname,
                                get_profile_for_user, ProfileNotConfigured)
from mezzanine.conf import settings
from mezzanine.core.forms import Html5Mixin
from mezzanine.utils.urls import slugify, unique_slug


User = get_user_model()

_exclude_fields = tuple(getattr(settings,
                                "ACCOUNTS_PROFILE_FORM_EXCLUDE_FIELDS", ()))

# If a profile model has been configured with the ``ACCOUNTS_PROFILE_MODEL``
# setting, create a model form for it that will have its fields added to
# ``ProfileForm``.
try:
    class ProfileFieldsForm(forms.ModelForm):
        class Meta:
            model = get_profile_model()
            exclude = (get_profile_user_fieldname(),) + _exclude_fields
except ProfileNotConfigured:
    pass


if settings.ACCOUNTS_NO_USERNAME:
    _exclude_fields += ("username",)
    username_label = _("Email address")
else:
    username_label = _("Username or email address")


[docs]class LoginForm(Html5Mixin, forms.Form): """ Fields for login. """ username = forms.CharField(label=username_label) password = forms.CharField(label=_("Password"), widget=forms.PasswordInput(render_value=False))
[docs] def clean(self): """ Authenticate the given username/email and password. If the fields are valid, store the authenticated user for returning via save(). """ username = self.cleaned_data.get("username") password = self.cleaned_data.get("password") self._user = authenticate(username=username, password=password) if self._user is None: raise forms.ValidationError( ugettext("Invalid username/email and password")) elif not self._user.is_active: raise forms.ValidationError(ugettext("Your account is inactive")) return self.cleaned_data
[docs] def save(self): """ Just return the authenticated user - used for logging in. """ return getattr(self, "_user", None)
[docs]class ProfileForm(Html5Mixin, forms.ModelForm): """ ModelForm for auth.User - used for signup and profile update. If a Profile model is defined via ``ACCOUNTS_PROFILE_MODEL``, its fields are injected into the form. """ password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput(render_value=False)) password2 = forms.CharField(label=_("Password (again)"), widget=forms.PasswordInput(render_value=False)) class Meta: model = User fields = ("first_name", "last_name", "email", "username") exclude = _exclude_fields def __init__(self, *args, **kwargs): super(ProfileForm, self).__init__(*args, **kwargs) self._signup = self.instance.id is None user_fields = set([f.name for f in User._meta.get_fields()]) try: self.fields["username"].help_text = ugettext( "Only letters, numbers, dashes or underscores please") except KeyError: pass for field in self.fields: # Make user fields required. if field in user_fields: self.fields[field].required = True # Disable auto-complete for password fields. # Password isn't required for profile update. if field.startswith("password"): self.fields[field].widget.attrs["autocomplete"] = "off" self.fields[field].widget.attrs.pop("required", "") if not self._signup: self.fields[field].required = False if field == "password1": self.fields[field].help_text = ugettext( "Leave blank unless you want " "to change your password") # Add any profile fields to the form. try: profile_fields_form = self.get_profile_fields_form() profile_fields = profile_fields_form().fields self.fields.update(profile_fields) if not self._signup: user_profile = get_profile_for_user(self.instance) for field in profile_fields: value = getattr(user_profile, field) # Check for multiple initial values, i.e. a m2m field if isinstance(value, Manager): value = value.all() self.initial[field] = value except ProfileNotConfigured: pass
[docs] def clean_username(self): """ Ensure the username doesn't exist or contain invalid chars. We limit it to slugifiable chars since it's used as the slug for the user's profile view. """ username = self.cleaned_data.get("username") if username.lower() != slugify(username).lower(): raise forms.ValidationError( ugettext("Username can only contain letters, numbers, dashes " "or underscores.")) lookup = {"username__iexact": username} try: User.objects.exclude(id=self.instance.id).get(**lookup) except User.DoesNotExist: return username raise forms.ValidationError( ugettext("This username is already registered"))
[docs] def clean_password2(self): """ Ensure the password fields are equal, and match the minimum length defined by ``ACCOUNTS_MIN_PASSWORD_LENGTH``. """ password1 = self.cleaned_data.get("password1") password2 = self.cleaned_data.get("password2") if password1: errors = [] if password1 != password2: errors.append(ugettext("Passwords do not match")) if len(password1) < settings.ACCOUNTS_MIN_PASSWORD_LENGTH: errors.append( ugettext("Password must be at least %s characters") % settings.ACCOUNTS_MIN_PASSWORD_LENGTH) if errors: self._errors["password1"] = self.error_class(errors) return password2
[docs] def clean_email(self): """ Ensure the email address is not already registered. """ email = self.cleaned_data.get("email") qs = User.objects.exclude(id=self.instance.id).filter(email=email) if len(qs) == 0: return email raise forms.ValidationError( ugettext("This email is already registered"))
[docs] def save(self, *args, **kwargs): """ Create the new user. If no username is supplied (may be hidden via ``ACCOUNTS_PROFILE_FORM_EXCLUDE_FIELDS`` or ``ACCOUNTS_NO_USERNAME``), we generate a unique username, so that if profile pages are enabled, we still have something to use as the profile's slug. """ kwargs["commit"] = False user = super(ProfileForm, self).save(*args, **kwargs) try: self.cleaned_data["username"] except KeyError: if not self.instance.username: try: username = ("%(first_name)s %(last_name)s" % self.cleaned_data).strip() except KeyError: username = "" if not username: username = self.cleaned_data["email"].split("@")[0] qs = User.objects.exclude(id=self.instance.id) user.username = unique_slug(qs, "username", slugify(username)) password = self.cleaned_data.get("password1") if password: user.set_password(password) elif self._signup: try: user.set_unusable_password() except AttributeError: # This could happen if using a custom user model that # doesn't inherit from Django's AbstractBaseUser. pass user.save() try: profile = get_profile_for_user(user) profile_form = self.get_profile_fields_form() profile_form(self.data, self.files, instance=profile).save() except ProfileNotConfigured: pass if self._signup: if (settings.ACCOUNTS_VERIFICATION_REQUIRED or settings.ACCOUNTS_APPROVAL_REQUIRED): user.is_active = False user.save() else: token = default_token_generator.make_token(user) user = authenticate(uidb36=int_to_base36(user.id), token=token, is_active=True) return user
def get_profile_fields_form(self): try: return ProfileFieldsForm except NameError: raise ProfileNotConfigured
[docs]class PasswordResetForm(Html5Mixin, forms.Form): """ Validates the user's username or email for sending a login token for authenticating to change their password. """ username = forms.CharField(label=username_label) def clean(self): username = self.cleaned_data.get("username") username_or_email = Q(username=username) | Q(email=username) try: user = User.objects.get(username_or_email, is_active=True) except User.DoesNotExist: raise forms.ValidationError( ugettext("Invalid username/email")) else: self._user = user return self.cleaned_data
[docs] def save(self): """ Just return the authenticated user - used for sending login email. """ return getattr(self, "_user", None)