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))
|