annotate gpp/accounts/forms.py @ 505:a5d11471d031

Refactor the logic in the rate limiter decorator. Check to see if the request was ajax, as the ajax view always returns 200. Have to decode the JSON response to see if an error occurred or not.
author Brian Neal <bgneal@gmail.com>
date Sat, 03 Dec 2011 19:13:38 +0000
parents b137a0966e4b
children 9e7ae8462f3f
rev   line source
gremmie@1 1 """forms for the accounts application"""
gremmie@1 2
bgneal@74 3 import logging
bgneal@74 4
gremmie@1 5 from django import forms
gremmie@1 6 from django.contrib.auth.models import User
gremmie@1 7 from django.core.urlresolvers import reverse
gremmie@1 8 from django.template.loader import render_to_string
gremmie@1 9 from django.contrib.sites.models import Site
bgneal@6 10 from django.conf import settings
gremmie@1 11
gremmie@1 12 from core.functions import send_mail
gremmie@1 13 from accounts.models import PendingUser
gremmie@1 14 from accounts.models import IllegalUsername
gremmie@1 15 from accounts.models import IllegalEmail
bgneal@472 16 from antispam.rate_limit import block_ip
gremmie@1 17
gremmie@1 18
gremmie@1 19 class RegisterForm(forms.Form):
bgneal@74 20 """Form used to register with the website"""
bgneal@498 21 username = forms.RegexField(
bgneal@498 22 max_length=30,
bgneal@498 23 regex=r'^\w+$',
bgneal@498 24 error_messages={'invalid': ('Your username must be 30 characters or'
bgneal@498 25 ' less and contain only letters, numbers and underscores.')},
bgneal@498 26 widget=forms.TextInput(attrs={'class': 'text'}),
bgneal@498 27 )
bgneal@498 28 email = forms.EmailField(widget=forms.TextInput(attrs={'class': 'text'}))
bgneal@498 29 password1 = forms.CharField(label="Password",
bgneal@498 30 widget=forms.PasswordInput(attrs={'class': 'text'}))
bgneal@498 31 password2 = forms.CharField(label="Password confirmation",
bgneal@498 32 widget=forms.PasswordInput(attrs={'class': 'text'}))
bgneal@316 33 agree_age = forms.BooleanField(required=True,
bgneal@155 34 label='I certify that I am over the age of 13',
bgneal@155 35 error_messages={
bgneal@347 36 'required': 'Sorry, but you must be over the age of 13 to '
bgneal@155 37 'register at our site.',
bgneal@155 38 })
bgneal@316 39 agree_tos = forms.BooleanField(required=True,
bgneal@155 40 label='I agree to the Terms of Service',
bgneal@155 41 error_messages={
bgneal@155 42 'required': 'You have not agreed to our Terms of Service.',
bgneal@155 43 })
bgneal@155 44 agree_privacy = forms.BooleanField(required=True,
bgneal@155 45 label='I agree to the Privacy Policy',
bgneal@155 46 error_messages={
bgneal@155 47 'required': 'You have not agreed to our Privacy Policy.',
bgneal@155 48 })
bgneal@498 49 question1 = forms.CharField(label="What number appears in the site name?",
bgneal@498 50 widget=forms.TextInput(attrs={'class': 'text'}))
bgneal@347 51 question2 = forms.CharField(label='', required=False,
bgneal@347 52 widget=forms.TextInput(attrs={'style': 'display: none;'}))
gremmie@1 53
bgneal@74 54 def __init__(self, *args, **kwargs):
bgneal@74 55 self.ip = kwargs.pop('ip', '?')
bgneal@74 56 super(RegisterForm, self).__init__(*args, **kwargs)
bgneal@74 57
bgneal@74 58 def clean_username(self):
bgneal@74 59 username = self.cleaned_data['username']
bgneal@74 60 try:
bgneal@74 61 User.objects.get(username = username)
bgneal@74 62 except User.DoesNotExist:
gremmie@1 63 try:
bgneal@74 64 PendingUser.objects.get(username = username)
bgneal@74 65 except PendingUser.DoesNotExist:
bgneal@74 66 try:
bgneal@74 67 IllegalUsername.objects.get(username = username)
bgneal@74 68 except IllegalUsername.DoesNotExist:
bgneal@74 69 return username
bgneal@74 70 self._validation_error("That username is not allowed.", username)
bgneal@74 71 self._validation_error("A pending user with that username already exists.", username)
bgneal@74 72 self._validation_error("A user with that username already exists.", username)
gremmie@1 73
bgneal@74 74 def clean_email(self):
bgneal@74 75 email = self.cleaned_data['email']
bgneal@74 76 try:
bgneal@74 77 User.objects.get(email = email)
bgneal@74 78 except User.DoesNotExist:
gremmie@1 79 try:
bgneal@74 80 PendingUser.objects.get(email = email)
bgneal@74 81 except PendingUser.DoesNotExist:
bgneal@74 82 try:
bgneal@74 83 IllegalEmail.objects.get(email = email)
bgneal@74 84 except IllegalEmail.DoesNotExist:
bgneal@74 85 return email
bgneal@74 86 self._validation_error("That email address is not allowed.", email)
bgneal@74 87 self._validation_error("A pending user with that email address already exists.", email)
bgneal@74 88 self._validation_error("A user with that email address already exists.", email)
gremmie@1 89
bgneal@74 90 def clean_password2(self):
bgneal@74 91 password1 = self.cleaned_data.get("password1", "")
bgneal@74 92 password2 = self.cleaned_data["password2"]
bgneal@74 93 if password1 != password2:
bgneal@74 94 self._validation_error("The two password fields didn't match.")
bgneal@155 95 if len(password1) < 6:
bgneal@155 96 self._validation_error("Please choose a password of 6 characters or more.")
bgneal@74 97 return password2
gremmie@1 98
bgneal@346 99 def clean_question1(self):
bgneal@346 100 answer = self.cleaned_data.get('question1')
bgneal@346 101 success = False
bgneal@346 102 if answer:
bgneal@346 103 try:
bgneal@346 104 val = int(answer)
bgneal@346 105 except ValueError:
bgneal@346 106 pass
bgneal@346 107 else:
bgneal@346 108 success = val == 101
bgneal@346 109 if not success:
bgneal@346 110 self._validation_error("Incorrect answer to our anti-spam question.", answer)
bgneal@346 111 return answer
bgneal@346 112
bgneal@347 113 def clean_question2(self):
bgneal@347 114 """
bgneal@347 115 Honeypot field should be empty.
bgneal@347 116 """
bgneal@347 117 answer = self.cleaned_data.get('question2')
bgneal@347 118 if answer:
bgneal@472 119 block_ip(self.ip)
bgneal@347 120 self._validation_error('Wrong answer #2: %s' % answer)
bgneal@347 121 return answer
bgneal@347 122
bgneal@74 123 def save(self):
bgneal@74 124 pending_user = PendingUser.objects.create_pending_user(self.cleaned_data['username'],
bgneal@74 125 self.cleaned_data['email'],
bgneal@74 126 self.cleaned_data['password1'])
gremmie@1 127
bgneal@74 128 # Send the confirmation email
gremmie@1 129
bgneal@74 130 site = Site.objects.get_current()
bgneal@74 131 admin_email = settings.ADMINS[0][1]
gremmie@1 132
bgneal@316 133 activation_link = 'http://%s%s' % (site.domain, reverse('accounts.views.register_confirm',
bgneal@74 134 kwargs = {'username' : pending_user.username, 'key' : pending_user.key}))
gremmie@1 135
bgneal@74 136 msg = render_to_string('accounts/registration_email.txt',
bgneal@74 137 {
bgneal@74 138 'site_name' : site.name,
bgneal@74 139 'site_domain' : site.domain,
bgneal@74 140 'user_email' : pending_user.email,
bgneal@74 141 'activation_link' : activation_link,
bgneal@74 142 'username' : pending_user.username,
bgneal@74 143 'admin_email' : admin_email,
bgneal@74 144 })
gremmie@1 145
bgneal@74 146 subject = 'Registration Confirmation for ' + site.name
bgneal@252 147 send_mail(subject, msg, admin_email, [self.cleaned_data['email']],
bgneal@252 148 expedite=True)
bgneal@316 149 logging.info('Accounts/registration conf. email sent to %s for user %s; IP = %s',
bgneal@316 150 self.cleaned_data['email'], pending_user.username, self.ip)
gremmie@1 151
bgneal@74 152 return pending_user
gremmie@1 153
bgneal@74 154 def _validation_error(self, msg, param=None):
bgneal@316 155 logging.error('Accounts/registration [%s]: %s (%s)', self.ip, msg, param)
bgneal@74 156 raise forms.ValidationError(msg)