This repository has been archived by the owner on Oct 22, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 409
/
forms.py
261 lines (217 loc) · 11.8 KB
/
forms.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
#encoding:utf-8
from __future__ import unicode_literals
from django import forms
from django.contrib.auth import get_user_model
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import authenticate
from userena import settings as userena_settings
from userena.models import UserenaSignup
from userena.utils import get_profile_model
from hashlib import sha1
import random
try:
from collections import OrderedDict
except ImportError:
# Python 2.6 requires library
from ordereddict import OrderedDict
attrs_dict = {'class': 'required'}
USERNAME_RE = r'^[\.\w]+$'
class SignupForm(forms.Form):
"""
Form for creating a new user account.
Validates that the requested username and e-mail is not already in use.
Also requires the password to be entered twice.
"""
username = forms.RegexField(regex=USERNAME_RE,
max_length=30,
widget=forms.TextInput(attrs=attrs_dict),
label=_("Username"),
error_messages={'invalid': _('Username must contain only letters, numbers, dots and underscores.')})
email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict,
maxlength=75)),
label=_("Email"))
password1 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict,
render_value=False),
label=_("Create password"))
password2 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict,
render_value=False),
label=_("Repeat password"))
def __init__(self, redirect=None, *args, **kwargs):
self.redirect = redirect
super(SignupForm, self).__init__(*args, **kwargs)
def clean_username(self):
"""
Validate that the username is alphanumeric and is not already in use.
Also validates that the username is not listed in
``USERENA_FORBIDDEN_USERNAMES`` list.
"""
try:
user = get_user_model().objects.get(username__iexact=self.cleaned_data['username'])
except get_user_model().DoesNotExist:
pass
else:
if userena_settings.USERENA_ACTIVATION_REQUIRED and UserenaSignup.objects.filter(user__username__iexact=self.cleaned_data['username']).exclude(activation_key=userena_settings.USERENA_ACTIVATED):
raise forms.ValidationError(_('This username is already taken but not confirmed. Please check your email for verification steps.'))
raise forms.ValidationError(_('This username is already taken.'))
if self.cleaned_data['username'].lower() in userena_settings.USERENA_FORBIDDEN_USERNAMES:
raise forms.ValidationError(_('This username is not allowed.'))
return self.cleaned_data['username']
def clean_email(self):
""" Validate that the e-mail address is unique. """
if get_user_model().objects.filter(email__iexact=self.cleaned_data['email']):
if userena_settings.USERENA_ACTIVATION_REQUIRED and UserenaSignup.objects.filter(user__email__iexact=self.cleaned_data['email']).exclude(activation_key=userena_settings.USERENA_ACTIVATED):
raise forms.ValidationError(_('This email is already in use but not confirmed. Please check your email for verification steps.'))
raise forms.ValidationError(_('This email is already in use. Please supply a different email.'))
return self.cleaned_data['email']
def clean(self):
"""
Validates 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 and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError(_('The two password fields didn\'t match.'))
return self.cleaned_data
def save(self):
""" Creates a new user and account. Returns the newly created user. """
username, email, password = (self.cleaned_data['username'],
self.cleaned_data['email'],
self.cleaned_data['password1'])
new_user = UserenaSignup.objects.create_user(username,
email,
password,
not userena_settings.USERENA_ACTIVATION_REQUIRED,
userena_settings.USERENA_ACTIVATION_REQUIRED,
redirect=self.redirect)
return new_user
class SignupFormOnlyEmail(SignupForm):
"""
Form for creating a new user account but not needing a username.
This form is an adaptation of :class:`SignupForm`. It's used when
``USERENA_WITHOUT_USERNAME`` setting is set to ``True``. And thus the user
is not asked to supply an username, but one is generated for them. The user
can than keep sign in by using their email.
"""
def __init__(self, *args, **kwargs):
super(SignupFormOnlyEmail, self).__init__(*args, **kwargs)
del self.fields['username']
def save(self):
""" Generate a random username before falling back to parent signup form """
while True:
username = sha1(str(random.random()).encode('utf-8')).hexdigest()[:5]
try:
get_user_model().objects.get(username__iexact=username)
except get_user_model().DoesNotExist: break
self.cleaned_data['username'] = username
return super(SignupFormOnlyEmail, self).save()
class SignupFormTos(SignupForm):
""" Add a Terms of Service button to the ``SignupForm``. """
tos = forms.BooleanField(widget=forms.CheckboxInput(attrs=attrs_dict),
label=_('I have read and agree to the Terms of Service'),
error_messages={'required': _('You must agree to the terms to register.')})
def identification_field_factory(label, error_required):
"""
A simple identification field factory which enable you to set the label.
:param label:
String containing the label for this field.
:param error_required:
String containing the error message if the field is left empty.
"""
return forms.CharField(label=label,
widget=forms.TextInput(attrs=attrs_dict),
max_length=75,
error_messages={'required': error_required})
class AuthenticationForm(forms.Form):
"""
A custom form where the identification can be a e-mail address or username.
"""
identification = identification_field_factory(_("Email or username"),
_("Either supply us with your email or username."))
password = forms.CharField(label=_("Password"),
widget=forms.PasswordInput(attrs=attrs_dict, render_value=False))
remember_me = forms.BooleanField(widget=forms.CheckboxInput(),
required=False,
label=_('Remember me for %(days)s') % {'days': _(userena_settings.USERENA_REMEMBER_ME_DAYS[0])})
def __init__(self, *args, **kwargs):
""" A custom init because we need to change the label if no usernames is used """
super(AuthenticationForm, self).__init__(*args, **kwargs)
# Dirty hack, somehow the label doesn't get translated without declaring
# it again here.
self.fields['remember_me'].label = _('Remember me for %(days)s') % {'days': _(userena_settings.USERENA_REMEMBER_ME_DAYS[0])}
if userena_settings.USERENA_WITHOUT_USERNAMES:
self.fields['identification'] = identification_field_factory(_("Email"),
_("Please supply your email."))
def clean(self):
"""
Checks for the identification and password.
If the combination can't be found will raise an invalid sign in error.
"""
identification = self.cleaned_data.get('identification')
password = self.cleaned_data.get('password')
if identification and password:
user = authenticate(identification=identification, password=password)
if user is None:
raise forms.ValidationError(_("Please enter a correct username or email and password. Note that both fields are case-sensitive."))
return self.cleaned_data
class ChangeEmailForm(forms.Form):
email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict,
maxlength=75)),
label=_("New email"))
def __init__(self, user, *args, **kwargs):
"""
The current ``user`` is needed for initialisation of this form so
that we can check if the email address is still free and not always
returning ``True`` for this query because it's the users own e-mail
address.
"""
super(ChangeEmailForm, self).__init__(*args, **kwargs)
if not isinstance(user, get_user_model()):
raise TypeError("user must be an instance of %s" % get_user_model().__name__)
else: self.user = user
def clean_email(self):
""" Validate that the email is not already registered with another user """
if self.cleaned_data['email'].lower() == self.user.email:
raise forms.ValidationError(_('You\'re already known under this email.'))
if get_user_model().objects.filter(email__iexact=self.cleaned_data['email']).exclude(email__iexact=self.user.email):
raise forms.ValidationError(_('This email is already in use. Please supply a different email.'))
return self.cleaned_data['email']
def save(self):
"""
Save method calls :func:`user.change_email()` method which sends out an
email with an verification key to verify and with it enable this new
email address.
"""
return self.user.userena_signup.change_email(self.cleaned_data['email'])
class EditProfileForm(forms.ModelForm):
""" Base form used for fields that are always required """
first_name = forms.CharField(label=_('First name'),
max_length=30,
required=False)
last_name = forms.CharField(label=_('Last name'),
max_length=30,
required=False)
def __init__(self, *args, **kw):
super(EditProfileForm, self).__init__(*args, **kw)
# Put the first and last name at the top
try: # in Django < 1.7
new_order = self.fields.keyOrder[:-2]
new_order.insert(0, 'first_name')
new_order.insert(1, 'last_name')
self.fields.keyOrder = new_order
except AttributeError: # in Django > 1.7
new_order = [('first_name', self.fields['first_name']),
('last_name', self.fields['last_name'])]
new_order.extend(list(self.fields.items())[:-2])
self.fields = OrderedDict(new_order)
class Meta:
model = get_profile_model()
exclude = ['user']
def save(self, force_insert=False, force_update=False, commit=True):
profile = super(EditProfileForm, self).save(commit=commit)
# Save first and last name
user = profile.user
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.save()
return profile