annotate accounts/forms.py @ 697:67f8d49a9377

Cleaned up the code a bit. Separated the S3 stuff out into its own class. This class maybe should be in core. Still want to do some kind of context manager around the temporary file we are creating to ensure it gets deleted.
author Brian Neal <bgneal@gmail.com>
date Sun, 08 Sep 2013 21:02:58 -0500
parents 988782c6ce6c
children 9133b4626a4b
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@690 16
bgneal@690 17
bgneal@690 18 logger = logging.getLogger('auth')
gremmie@1 19
gremmie@1 20
gremmie@1 21 class RegisterForm(forms.Form):
bgneal@74 22 """Form used to register with the website"""
bgneal@498 23 username = forms.RegexField(
bgneal@498 24 max_length=30,
bgneal@498 25 regex=r'^\w+$',
bgneal@498 26 error_messages={'invalid': ('Your username must be 30 characters or'
bgneal@498 27 ' less and contain only letters, numbers and underscores.')},
bgneal@498 28 widget=forms.TextInput(attrs={'class': 'text'}),
bgneal@498 29 )
bgneal@498 30 email = forms.EmailField(widget=forms.TextInput(attrs={'class': 'text'}))
bgneal@498 31 password1 = forms.CharField(label="Password",
bgneal@498 32 widget=forms.PasswordInput(attrs={'class': 'text'}))
bgneal@498 33 password2 = forms.CharField(label="Password confirmation",
bgneal@498 34 widget=forms.PasswordInput(attrs={'class': 'text'}))
bgneal@316 35 agree_age = forms.BooleanField(required=True,
bgneal@155 36 label='I certify that I am over the age of 13',
bgneal@155 37 error_messages={
bgneal@347 38 'required': 'Sorry, but you must be over the age of 13 to '
bgneal@155 39 'register at our site.',
bgneal@155 40 })
bgneal@316 41 agree_tos = forms.BooleanField(required=True,
bgneal@155 42 label='I agree to the Terms of Service',
bgneal@155 43 error_messages={
bgneal@155 44 'required': 'You have not agreed to our Terms of Service.',
bgneal@155 45 })
bgneal@155 46 agree_privacy = forms.BooleanField(required=True,
bgneal@155 47 label='I agree to the Privacy Policy',
bgneal@155 48 error_messages={
bgneal@155 49 'required': 'You have not agreed to our Privacy Policy.',
bgneal@155 50 })
bgneal@498 51 question1 = forms.CharField(label="What number appears in the site name?",
bgneal@498 52 widget=forms.TextInput(attrs={'class': 'text'}))
bgneal@347 53 question2 = forms.CharField(label='', required=False,
bgneal@347 54 widget=forms.TextInput(attrs={'style': 'display: none;'}))
gremmie@1 55
bgneal@74 56 def __init__(self, *args, **kwargs):
bgneal@74 57 self.ip = kwargs.pop('ip', '?')
bgneal@74 58 super(RegisterForm, self).__init__(*args, **kwargs)
bgneal@74 59
bgneal@74 60 def clean_username(self):
bgneal@74 61 username = self.cleaned_data['username']
bgneal@74 62 try:
bgneal@565 63 User.objects.get(username=username)
bgneal@74 64 except User.DoesNotExist:
gremmie@1 65 try:
bgneal@565 66 PendingUser.objects.get(username=username)
bgneal@74 67 except PendingUser.DoesNotExist:
bgneal@74 68 try:
bgneal@565 69 IllegalUsername.objects.get(username=username)
bgneal@74 70 except IllegalUsername.DoesNotExist:
bgneal@74 71 return username
bgneal@74 72 self._validation_error("That username is not allowed.", username)
bgneal@74 73 self._validation_error("A pending user with that username already exists.", username)
bgneal@74 74 self._validation_error("A user with that username already exists.", username)
gremmie@1 75
bgneal@74 76 def clean_email(self):
bgneal@74 77 email = self.cleaned_data['email']
bgneal@565 78
bgneal@565 79 if User.objects.filter(email=email).count():
bgneal@565 80 self._validation_error("A user with that email address already exists.", email)
bgneal@565 81 elif PendingUser.objects.filter(email=email).count():
bgneal@74 82 self._validation_error("A pending user with that email address already exists.", email)
bgneal@565 83 elif IllegalEmail.objects.filter(email=email).count():
bgneal@565 84 self._validation_error("That email address is not allowed.", email)
bgneal@659 85
bgneal@565 86 # email is ok
bgneal@565 87 return email
gremmie@1 88
bgneal@74 89 def clean_password2(self):
bgneal@74 90 password1 = self.cleaned_data.get("password1", "")
bgneal@74 91 password2 = self.cleaned_data["password2"]
bgneal@74 92 if password1 != password2:
bgneal@74 93 self._validation_error("The two password fields didn't match.")
bgneal@155 94 if len(password1) < 6:
bgneal@155 95 self._validation_error("Please choose a password of 6 characters or more.")
bgneal@74 96 return password2
gremmie@1 97
bgneal@346 98 def clean_question1(self):
bgneal@346 99 answer = self.cleaned_data.get('question1')
bgneal@346 100 success = False
bgneal@346 101 if answer:
bgneal@346 102 try:
bgneal@346 103 val = int(answer)
bgneal@346 104 except ValueError:
bgneal@346 105 pass
bgneal@346 106 else:
bgneal@346 107 success = val == 101
bgneal@346 108 if not success:
bgneal@346 109 self._validation_error("Incorrect answer to our anti-spam question.", answer)
bgneal@346 110 return answer
bgneal@346 111
bgneal@347 112 def clean_question2(self):
bgneal@347 113 """
bgneal@347 114 Honeypot field should be empty.
bgneal@347 115 """
bgneal@347 116 answer = self.cleaned_data.get('question2')
bgneal@347 117 if answer:
bgneal@690 118 logger.critical('Accounts/registration: Honeypot filled [%s]', self.ip)
bgneal@690 119 self._validation_error('Wrong answer #2', answer)
bgneal@347 120 return answer
bgneal@347 121
bgneal@74 122 def save(self):
bgneal@74 123 pending_user = PendingUser.objects.create_pending_user(self.cleaned_data['username'],
bgneal@74 124 self.cleaned_data['email'],
bgneal@74 125 self.cleaned_data['password1'])
gremmie@1 126
bgneal@74 127 # Send the confirmation email
gremmie@1 128
bgneal@74 129 site = Site.objects.get_current()
bgneal@74 130 admin_email = settings.ADMINS[0][1]
gremmie@1 131
bgneal@316 132 activation_link = 'http://%s%s' % (site.domain, reverse('accounts.views.register_confirm',
bgneal@74 133 kwargs = {'username' : pending_user.username, 'key' : pending_user.key}))
gremmie@1 134
bgneal@74 135 msg = render_to_string('accounts/registration_email.txt',
bgneal@74 136 {
bgneal@74 137 'site_name' : site.name,
bgneal@74 138 'site_domain' : site.domain,
bgneal@74 139 'user_email' : pending_user.email,
bgneal@74 140 'activation_link' : activation_link,
bgneal@74 141 'username' : pending_user.username,
bgneal@74 142 'admin_email' : admin_email,
bgneal@74 143 })
gremmie@1 144
bgneal@74 145 subject = 'Registration Confirmation for ' + site.name
bgneal@659 146 send_mail(subject, msg, admin_email, [self.cleaned_data['email']],
bgneal@659 147 defer=False)
bgneal@690 148 logger.info('Accounts/registration conf. email sent to %s for user %s; IP = %s',
bgneal@316 149 self.cleaned_data['email'], pending_user.username, self.ip)
gremmie@1 150
bgneal@74 151 return pending_user
gremmie@1 152
bgneal@74 153 def _validation_error(self, msg, param=None):
bgneal@690 154 logger.error('Accounts/registration [%s]: %s (%s)', self.ip, msg, param)
bgneal@74 155 raise forms.ValidationError(msg)
bgneal@659 156
bgneal@659 157
bgneal@659 158 class ForgotUsernameForm(forms.Form):
bgneal@659 159 """Form used to recover lost username"""
bgneal@659 160 email = forms.EmailField(widget=forms.TextInput(attrs={'class': 'text'}))
bgneal@659 161
bgneal@659 162 def save(self):
bgneal@659 163 """Email the username associated with the email address to the user."""
bgneal@659 164 email = self.cleaned_data['email']
bgneal@659 165 try:
bgneal@659 166 user = User.objects.get(email=email)
bgneal@659 167 except User.DoesNotExist:
bgneal@659 168 # nothing to do; we don't tell the user as this gives away info
bgneal@659 169 # about our database
bgneal@659 170 return
bgneal@659 171
bgneal@659 172 site = Site.objects.get_current()
bgneal@659 173 admin_email = settings.ADMINS[0][1]
bgneal@659 174
bgneal@659 175 subject = 'Forgotten username for %s' % site.name
bgneal@659 176 msg = render_to_string('accounts/forgot_user_email.txt', {
bgneal@659 177 'user': user,
bgneal@659 178 'site': site,
bgneal@659 179 'admin_email': admin_email,
bgneal@659 180 })
bgneal@659 181 send_mail(subject, msg, admin_email, [email], defer=False)
bgneal@659 182
bgneal@690 183 logger.info('Forgotten username email sent to {} <{}>'.format(
bgneal@659 184 user.username, email))