gremmie@1: """forms for the accounts application""" gremmie@1: bgneal@74: import logging bgneal@74: gremmie@1: from django import forms gremmie@1: from django.contrib.auth.models import User gremmie@1: from django.core.urlresolvers import reverse gremmie@1: from django.template.loader import render_to_string gremmie@1: from django.contrib.sites.models import Site bgneal@6: from django.conf import settings gremmie@1: gremmie@1: from core.functions import send_mail gremmie@1: from accounts.models import PendingUser gremmie@1: from accounts.models import IllegalUsername gremmie@1: from accounts.models import IllegalEmail bgneal@472: from antispam.rate_limit import block_ip gremmie@1: gremmie@1: gremmie@1: class RegisterForm(forms.Form): bgneal@74: """Form used to register with the website""" bgneal@346: username = forms.RegexField(max_length=30, regex=r'^\w+$', bgneal@155: error_messages={ bgneal@347: 'invalid': 'Your username must be 30 characters or less and ' bgneal@155: 'contain only letters, numbers and underscores.'}) bgneal@74: email = forms.EmailField() bgneal@346: password1 = forms.CharField(label="Password", widget=forms.PasswordInput) bgneal@346: password2 = forms.CharField(label="Password confirmation", widget=forms.PasswordInput) bgneal@316: agree_age = forms.BooleanField(required=True, bgneal@155: label='I certify that I am over the age of 13', bgneal@155: error_messages={ bgneal@347: 'required': 'Sorry, but you must be over the age of 13 to ' bgneal@155: 'register at our site.', bgneal@155: }) bgneal@316: agree_tos = forms.BooleanField(required=True, bgneal@155: label='I agree to the Terms of Service', bgneal@155: error_messages={ bgneal@155: 'required': 'You have not agreed to our Terms of Service.', bgneal@155: }) bgneal@155: agree_privacy = forms.BooleanField(required=True, bgneal@155: label='I agree to the Privacy Policy', bgneal@155: error_messages={ bgneal@155: 'required': 'You have not agreed to our Privacy Policy.', bgneal@155: }) bgneal@346: question1 = forms.CharField(label="What number appears in the site name?") bgneal@347: question2 = forms.CharField(label='', required=False, bgneal@347: widget=forms.TextInput(attrs={'style': 'display: none;'})) gremmie@1: bgneal@74: def __init__(self, *args, **kwargs): bgneal@74: self.ip = kwargs.pop('ip', '?') bgneal@74: super(RegisterForm, self).__init__(*args, **kwargs) bgneal@74: bgneal@74: def clean_username(self): bgneal@74: username = self.cleaned_data['username'] bgneal@74: try: bgneal@74: User.objects.get(username = username) bgneal@74: except User.DoesNotExist: gremmie@1: try: bgneal@74: PendingUser.objects.get(username = username) bgneal@74: except PendingUser.DoesNotExist: bgneal@74: try: bgneal@74: IllegalUsername.objects.get(username = username) bgneal@74: except IllegalUsername.DoesNotExist: bgneal@74: return username bgneal@74: self._validation_error("That username is not allowed.", username) bgneal@74: self._validation_error("A pending user with that username already exists.", username) bgneal@74: self._validation_error("A user with that username already exists.", username) gremmie@1: bgneal@74: def clean_email(self): bgneal@74: email = self.cleaned_data['email'] bgneal@74: try: bgneal@74: User.objects.get(email = email) bgneal@74: except User.DoesNotExist: gremmie@1: try: bgneal@74: PendingUser.objects.get(email = email) bgneal@74: except PendingUser.DoesNotExist: bgneal@74: try: bgneal@74: IllegalEmail.objects.get(email = email) bgneal@74: except IllegalEmail.DoesNotExist: bgneal@74: return email bgneal@74: self._validation_error("That email address is not allowed.", email) bgneal@74: self._validation_error("A pending user with that email address already exists.", email) bgneal@74: self._validation_error("A user with that email address already exists.", email) gremmie@1: bgneal@74: def clean_password2(self): bgneal@74: password1 = self.cleaned_data.get("password1", "") bgneal@74: password2 = self.cleaned_data["password2"] bgneal@74: if password1 != password2: bgneal@74: self._validation_error("The two password fields didn't match.") bgneal@155: if len(password1) < 6: bgneal@155: self._validation_error("Please choose a password of 6 characters or more.") bgneal@74: return password2 gremmie@1: bgneal@346: def clean_question1(self): bgneal@346: answer = self.cleaned_data.get('question1') bgneal@346: success = False bgneal@346: if answer: bgneal@346: try: bgneal@346: val = int(answer) bgneal@346: except ValueError: bgneal@346: pass bgneal@346: else: bgneal@346: success = val == 101 bgneal@346: if not success: bgneal@346: self._validation_error("Incorrect answer to our anti-spam question.", answer) bgneal@346: return answer bgneal@346: bgneal@347: def clean_question2(self): bgneal@347: """ bgneal@347: Honeypot field should be empty. bgneal@347: """ bgneal@347: answer = self.cleaned_data.get('question2') bgneal@347: if answer: bgneal@472: block_ip(self.ip) bgneal@347: self._validation_error('Wrong answer #2: %s' % answer) bgneal@347: return answer bgneal@347: bgneal@74: def save(self): bgneal@74: pending_user = PendingUser.objects.create_pending_user(self.cleaned_data['username'], bgneal@74: self.cleaned_data['email'], bgneal@74: self.cleaned_data['password1']) gremmie@1: bgneal@74: # Send the confirmation email gremmie@1: bgneal@74: site = Site.objects.get_current() bgneal@74: admin_email = settings.ADMINS[0][1] gremmie@1: bgneal@316: activation_link = 'http://%s%s' % (site.domain, reverse('accounts.views.register_confirm', bgneal@74: kwargs = {'username' : pending_user.username, 'key' : pending_user.key})) gremmie@1: bgneal@74: msg = render_to_string('accounts/registration_email.txt', bgneal@74: { bgneal@74: 'site_name' : site.name, bgneal@74: 'site_domain' : site.domain, bgneal@74: 'user_email' : pending_user.email, bgneal@74: 'activation_link' : activation_link, bgneal@74: 'username' : pending_user.username, bgneal@74: 'admin_email' : admin_email, bgneal@74: }) gremmie@1: bgneal@74: subject = 'Registration Confirmation for ' + site.name bgneal@252: send_mail(subject, msg, admin_email, [self.cleaned_data['email']], bgneal@252: expedite=True) bgneal@316: logging.info('Accounts/registration conf. email sent to %s for user %s; IP = %s', bgneal@316: self.cleaned_data['email'], pending_user.username, self.ip) gremmie@1: bgneal@74: return pending_user gremmie@1: bgneal@74: def _validation_error(self, msg, param=None): bgneal@316: logging.error('Accounts/registration [%s]: %s (%s)', self.ip, msg, param) bgneal@74: raise forms.ValidationError(msg)