""" Forms and validation code for user registration. """ from django.contrib.auth.models import User from django import forms from django.utils.translation import ugettext_lazy as _ from registration.models import RegistrationProfile # I put this on all required fields, because it's easier to pick up # on them with CSS or JavaScript if they have a class of "required" # in the HTML. Your mileage may vary. If/when Django ticket #3515 # lands in trunk, this will no longer be necessary. # This was fixed in 2007, so I guess we don't need this any more. [W] attrs_dict = { 'class': 'required' } class RegistrationForm(forms.Form): """ Form for registering a new user account. Validates that the requested username is not already in use. Subclasses should feel free to add any additional validation they need, but should either preserve the base ``save()`` or implement a ``save()`` method which returns a ``User``. """ username = forms.RegexField(regex=r'^\w+$', max_length=30, widget=forms.TextInput(attrs=attrs_dict), label=_(u'username')) email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict, maxlength=75)), label=_(u'email address')) password1 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False), label=_(u'password')) def clean_username(self): """ Validate that the username is alphanumeric and is not already in use. """ try: user = User.objects.get(username__iexact=self.cleaned_data['username']) except User.DoesNotExist: return self.cleaned_data['username'] raise forms.ValidationError(_(u'This username is already taken. Please choose another.')) def clean(self): """ Verifiy that the values entered into the two password fields match. Note that an error here will end up in ``non_field_errors()`` because it doesn't apply to a single field. """ if 'password1' in self.cleaned_data: if len(self.cleaned_data['password1']) < 6: raise forms.ValidationError(_(u'Your password must be at least 6 characters')) return self.cleaned_data def save(self): """ Create the new ``User`` and ``RegistrationProfile``, and returns the ``User`` (by calling ``RegistrationProfile.objects.create_inactive_user()``). """ new_user = RegistrationProfile.objects.create_inactive_user(username=self.cleaned_data['username'], password=self.cleaned_data['password1'], email=self.cleaned_data['email']) return new_user class RegistrationFormTermsOfService(RegistrationForm): """ Subclass of ``RegistrationForm`` which adds a required checkbox for agreeing to a site's Terms of Service. """ tos = forms.BooleanField(widget=forms.CheckboxInput(attrs=attrs_dict), label=_(u'I have read and agree to the Terms of Service'), error_messages={ 'required': u"You must agree to the terms to register" }) class RegistrationFormUniqueEmail(RegistrationForm): """ Subclass of ``RegistrationForm`` which enforces uniqueness of email addresses. """ def clean_email(self): """ Validate that the supplied email address is unique for the site. """ if User.objects.filter(email__iexact=self.cleaned_data['email']): raise forms.ValidationError(_(u'This email address is already in use. Please supply a different email address.')) return self.cleaned_data['email'] class RegistrationFormNoFreeEmail(RegistrationForm): """ Subclass of ``RegistrationForm`` which disallows registration with email addresses from popular free webmail services; moderately useful for preventing automated spam registrations. To change the list of banned domains, subclass this form and override the attribute ``bad_domains``. """ bad_domains = ['aim.com', 'aol.com', 'email.com', 'gmail.com', 'googlemail.com', 'hotmail.com', 'hushmail.com', 'msn.com', 'mail.ru', 'mailinator.com', 'live.com'] def clean_email(self): """ Check the supplied email address against a list of known free webmail domains. """ email_domain = self.cleaned_data['email'].split('@')[1] if email_domain in self.bad_domains: raise forms.ValidationError(_(u'Registration using free email addresses is prohibited. Please supply a different email address.')) return self.cleaned_data['email']