1 # -*- coding: utf-8 -*-
2 # Copyright (c) 2007, 2008, BenoƮt Chesneau
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions are
10 # * Redistributions of source code must retain the above copyright
11 # * notice, this list of conditions and the following disclaimer.
12 # * Redistributions in binary form must reproduce the above copyright
13 # * notice, this list of conditions and the following disclaimer in the
14 # * documentation and/or other materials provided with the
15 # * distribution. Neither the name of the <ORGANIZATION> nor the names
16 # * of its contributors may be used to endorse or promote products
17 # * derived from this software without specific prior written
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
27 # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 from django import forms
34 from django.contrib.auth.models import User
35 from django.contrib.auth import authenticate
36 from django.utils.translation import ugettext as _
37 from django.conf import settings
42 # needed for some linux distributions like debian
44 from openid.yadis import xri
48 from django_authopenid.util import clean_next
50 __all__ = ['OpenidSigninForm', 'OpenidAuthForm', 'OpenidVerifyForm',
51 'OpenidRegisterForm', 'RegistrationForm', 'ChangepwForm',
52 'ChangeemailForm', 'EmailPasswordForm', 'DeleteForm',
53 'ChangeOpenidForm', 'ChangeEmailForm', 'ChangepwForm']
55 class OpenidSigninForm(forms.Form):
57 openid_url = forms.CharField(max_length=255,
58 widget=forms.widgets.TextInput(attrs={'class': 'required openid'}))
59 next = forms.CharField(max_length=255, widget=forms.HiddenInput(),
62 def clean_openid_url(self):
63 """ test if openid is accepted """
64 if 'openid_url' in self.cleaned_data:
65 openid_url = self.cleaned_data['openid_url']
66 if xri.identifierScheme(openid_url) == 'XRI' and getattr(
67 settings, 'OPENID_DISALLOW_INAMES', False
69 raise forms.ValidationError(_('i-names are not supported'))
70 return self.cleaned_data['openid_url']
74 if 'next' in self.cleaned_data and self.cleaned_data['next'] != "":
75 self.cleaned_data['next'] = clean_next(self.cleaned_data['next'])
76 return self.cleaned_data['next']
79 attrs_dict = { 'class': 'required login' }
80 username_re = re.compile(r'^\w+$')
82 class OpenidAuthForm(forms.Form):
83 """ legacy account signin form """
84 next = forms.CharField(max_length=255, widget=forms.HiddenInput(),
86 username = forms.CharField(max_length=30,
87 widget=forms.widgets.TextInput(attrs=attrs_dict))
88 password = forms.CharField(max_length=128,
89 widget=forms.widgets.PasswordInput(attrs=attrs_dict))
91 def __init__(self, data=None, files=None, auto_id='id_%s',
92 prefix=None, initial=None):
93 super(OpenidAuthForm, self).__init__(data, files, auto_id,
95 self.user_cache = None
97 def clean_username(self):
98 """ validate username and test if it exists."""
99 if 'username' in self.cleaned_data and \
100 'openid_url' not in self.cleaned_data:
101 if not username_re.search(self.cleaned_data['username']):
102 raise forms.ValidationError(_("Usernames can only contain \
103 letters, numbers and underscores"))
105 user = User.objects.get(
106 username__exact = self.cleaned_data['username']
108 except User.DoesNotExist:
109 raise forms.ValidationError(_("This username does not exist \
110 in our database. Please choose another."))
111 except User.MultipleObjectsReturned:
112 raise forms.ValidationError(u'There is already more than one \
113 account registered with that username. Please try \
115 return self.cleaned_data['username']
117 def clean_password(self):
118 """" test if password is valid for this username """
119 if 'username' in self.cleaned_data and \
120 'password' in self.cleaned_data:
121 self.user_cache = authenticate(
122 username=self.cleaned_data['username'],
123 password=self.cleaned_data['password']
125 if self.user_cache is None:
126 raise forms.ValidationError(_("Please enter a valid \
127 username and password. Note that both fields are \
129 elif self.user_cache.is_active == False:
130 raise forms.ValidationError(_("This account is inactive."))
131 return self.cleaned_data['password']
133 def clean_next(self):
134 """ validate next url """
135 if 'next' in self.cleaned_data and \
136 self.cleaned_data['next'] != "":
137 self.cleaned_data['next'] = clean_next(self.cleaned_data['next'])
138 return self.cleaned_data['next']
141 """ get authenticated user """
142 return self.user_cache
145 class OpenidRegisterForm(forms.Form):
146 """ openid signin form """
147 next = forms.CharField(max_length=255, widget=forms.HiddenInput(),
149 username = forms.CharField(max_length=30,
150 widget=forms.widgets.TextInput(attrs=attrs_dict))
151 email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict,
152 maxlength=200)), label=u'Email address')
154 def clean_username(self):
155 """ test if username is valid and exist in database """
156 if 'username' in self.cleaned_data:
157 if not username_re.search(self.cleaned_data['username']):
158 raise forms.ValidationError(_("Usernames can only contain \
159 letters, numbers and underscores"))
161 user = User.objects.get(
162 username__exact = self.cleaned_data['username']
164 except User.DoesNotExist:
165 return self.cleaned_data['username']
166 except User.MultipleObjectsReturned:
167 raise forms.ValidationError(u'There is already more than one \
168 account registered with that username. Please try \
170 raise forms.ValidationError(_("This username is already \
171 taken. Please choose another."))
173 def clean_email(self):
174 """For security reason one unique email in database"""
175 if 'email' in self.cleaned_data:
177 user = User.objects.get(email = self.cleaned_data['email'])
178 except User.DoesNotExist:
179 return self.cleaned_data['email']
180 except User.MultipleObjectsReturned:
181 raise forms.ValidationError(u'There is already more than one \
182 account registered with that e-mail address. Please try \
184 raise forms.ValidationError(_("This email is already \
185 registered in our database. Please choose another."))
188 class OpenidVerifyForm(forms.Form):
189 """ openid verify form (associate an openid with an account) """
190 next = forms.CharField(max_length=255, widget = forms.HiddenInput(),
192 username = forms.CharField(max_length=30,
193 widget=forms.widgets.TextInput(attrs=attrs_dict))
194 password = forms.CharField(max_length=128,
195 widget=forms.widgets.PasswordInput(attrs=attrs_dict))
197 def __init__(self, data=None, files=None, auto_id='id_%s',
198 prefix=None, initial=None):
199 super(OpenidVerifyForm, self).__init__(data, files, auto_id,
201 self.user_cache = None
203 def clean_username(self):
204 """ validate username """
205 if 'username' in self.cleaned_data:
206 if not username_re.search(self.cleaned_data['username']):
207 raise forms.ValidationError(_("Usernames can only contain \
208 letters, numbers and underscores"))
210 user = User.objects.get(
211 username__exact = self.cleaned_data['username']
213 except User.DoesNotExist:
214 raise forms.ValidationError(_("This username don't exist. \
215 Please choose another."))
216 except User.MultipleObjectsReturned:
217 raise forms.ValidationError(u'Somehow, that username is in \
218 use for multiple accounts. Please contact us to get this \
220 return self.cleaned_data['username']
222 def clean_password(self):
223 """ test if password is valid for this user """
224 if 'username' in self.cleaned_data and \
225 'password' in self.cleaned_data:
226 self.user_cache = authenticate(
227 username = self.cleaned_data['username'],
228 password = self.cleaned_data['password']
230 if self.user_cache is None:
231 raise forms.ValidationError(_("Please enter a valid \
232 username and password. Note that both fields are \
234 elif self.user_cache.is_active == False:
235 raise forms.ValidationError(_("This account is inactive."))
236 return self.cleaned_data['password']
239 """ get authenticated user """
240 return self.user_cache
243 attrs_dict = { 'class': 'required' }
244 username_re = re.compile(r'^\w+$')
246 class RegistrationForm(forms.Form):
247 """ legacy registration form """
249 next = forms.CharField(max_length=255, widget=forms.HiddenInput(),
251 username = forms.CharField(max_length=30,
252 widget=forms.TextInput(attrs=attrs_dict),
254 email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict,
255 maxlength=200)), label=u'Email address')
256 password1 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict),
258 password2 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict),
259 label=u'Password (again, to catch typos)')
261 def clean_username(self):
263 Validates that the username is alphanumeric and is not already
267 if 'username' in self.cleaned_data:
268 if not username_re.search(self.cleaned_data['username']):
269 raise forms.ValidationError(u'Usernames can only contain \
270 letters, numbers and underscores')
272 user = User.objects.get(
273 username__exact = self.cleaned_data['username']
276 except User.DoesNotExist:
277 return self.cleaned_data['username']
278 except User.MultipleObjectsReturned:
279 raise forms.ValidationError(u'Somehow, that username is in \
280 use for multiple accounts. Please contact us to get this \
282 raise forms.ValidationError(u'This username is already taken. \
283 Please choose another.')
285 def clean_email(self):
286 """ validate if email exist in database
287 :return: raise error if it exist """
288 if 'email' in self.cleaned_data:
290 user = User.objects.get(email = self.cleaned_data['email'])
291 except User.DoesNotExist:
292 return self.cleaned_data['email']
293 except User.MultipleObjectsReturned:
294 raise forms.ValidationError(u'There is already more than one \
295 account registered with that e-mail address. Please try \
297 raise forms.ValidationError(u'This email is already registered \
298 in our database. Please choose another.')
299 return self.cleaned_data['email']
301 def clean_password2(self):
303 Validates that the two password inputs match.
306 if 'password1' in self.cleaned_data and \
307 'password2' in self.cleaned_data and \
308 self.cleaned_data['password1'] == \
309 self.cleaned_data['password2']:
310 return self.cleaned_data['password2']
311 raise forms.ValidationError(u'You must type the same password each \
315 class ChangepwForm(forms.Form):
316 """ change password form """
317 oldpw = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict))
318 password1 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict))
319 password2 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict))
321 def __init__(self, data=None, user=None, *args, **kwargs):
323 raise TypeError("Keyword argument 'user' must be supplied")
324 super(ChangepwForm, self).__init__(data, *args, **kwargs)
327 def clean_oldpw(self):
328 """ test old password """
329 if not self.user.check_password(self.cleaned_data['oldpw']):
330 raise forms.ValidationError(_("Old password is incorrect. \
331 Please enter the correct password."))
332 return self.cleaned_data['oldpw']
334 def clean_password2(self):
336 Validates that the two password inputs match.
338 if 'password1' in self.cleaned_data and \
339 'password2' in self.cleaned_data and \
340 self.cleaned_data['password1'] == self.cleaned_data['password2']:
341 return self.cleaned_data['password2']
342 raise forms.ValidationError(_("new passwords do not match"))
345 class ChangeemailForm(forms.Form):
346 """ change email form """
347 email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict,
348 maxlength=200)), label=u'Email address')
349 password = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict))
351 def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, \
352 initial=None, user=None):
354 raise TypeError("Keyword argument 'user' must be supplied")
355 super(ChangeemailForm, self).__init__(data, files, auto_id,
357 self.test_openid = False
361 def clean_email(self):
362 """ check if email don't exist """
363 if 'email' in self.cleaned_data:
364 if self.user.email != self.cleaned_data['email']:
366 user = User.objects.get(email = self.cleaned_data['email'])
367 except User.DoesNotExist:
368 return self.cleaned_data['email']
369 except User.MultipleObjectsReturned:
370 raise forms.ValidationError(u'There is already more than one \
371 account registered with that e-mail address. Please try \
373 raise forms.ValidationError(u'This email is already registered \
374 in our database. Please choose another.')
375 return self.cleaned_data['email']
378 def clean_password(self):
379 """ check if we have to test a legacy account or not """
380 if 'password' in self.cleaned_data:
381 if not self.user.check_password(self.cleaned_data['password']):
382 self.test_openid = True
383 return self.cleaned_data['password']
385 class ChangeopenidForm(forms.Form):
386 """ change openid form """
387 openid_url = forms.CharField(max_length=255,
388 widget=forms.TextInput(attrs={'class': "required" }))
390 def __init__(self, data=None, user=None, *args, **kwargs):
392 raise TypeError("Keyword argument 'user' must be supplied")
393 super(ChangeopenidForm, self).__init__(data, *args, **kwargs)
396 class DeleteForm(forms.Form):
397 """ confirm form to delete an account """
398 confirm = forms.CharField(widget=forms.CheckboxInput(attrs=attrs_dict))
399 password = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict))
401 def __init__(self, data=None, files=None, auto_id='id_%s',
402 prefix=None, initial=None, user=None):
403 super(DeleteForm, self).__init__(data, files, auto_id, prefix, initial)
404 self.test_openid = False
407 def clean_password(self):
408 """ check if we have to test a legacy account or not """
409 if 'password' in self.cleaned_data:
410 if not self.user.check_password(self.cleaned_data['password']):
411 self.test_openid = True
412 return self.cleaned_data['password']
415 class EmailPasswordForm(forms.Form):
416 """ send new password form """
417 username = forms.CharField(max_length=30,
418 widget=forms.TextInput(attrs={'class': "required" }))
420 def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
422 super(EmailPasswordForm, self).__init__(data, files, auto_id,
424 self.user_cache = None
427 def clean_username(self):
428 """ get user for this username """
429 if 'username' in self.cleaned_data:
431 self.user_cache = User.objects.get(
432 username = self.cleaned_data['username'])
434 raise forms.ValidationError(_("Incorrect username."))
435 return self.cleaned_data['username']