PageRenderTime 28ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/registration/forms.py

http://vyperblog.googlecode.com/
Python | 321 lines | 269 code | 16 blank | 36 comment | 7 complexity | 95e14186d8b3b9ad63dde2de1d3d1b67 MD5 | raw file
Possible License(s): LGPL-2.0
  1. """
  2. Forms and validation code for user registration.
  3. """
  4. import logging
  5. import sha
  6. import random
  7. from google.appengine.api import memcache
  8. from django.contrib.auth.models import User
  9. from django import forms
  10. from django.utils.translation import ugettext_lazy as _
  11. from django.template import Context
  12. from registration.models import RegistrationProfile
  13. from vyperlogix.django import django_utils
  14. from django.conf import settings
  15. from vyperlogix.misc import _utils
  16. # I put this on all required fields, because it's easier to pick up
  17. # on them with CSS or JavaScript if they have a class of "required"
  18. # in the HTML. Your mileage may vary. If/when Django ticket #3515
  19. # lands in trunk, this will no longer be necessary.
  20. attrs_dict = { 'class': 'required' }
  21. class RegistrationForm(forms.Form):
  22. """
  23. Form for registering a new user account.
  24. Validates that the requested username is not already in use, and
  25. requires the password to be entered twice to catch typos.
  26. Subclasses should feel free to add any additional validation they
  27. need, but should either preserve the base ``save()`` or implement
  28. a ``save()`` method which returns a ``User``.
  29. """
  30. username = forms.RegexField(regex=r'^\w+$',max_length=30,widget=forms.TextInput(attrs=attrs_dict),label=_(u'User Name'))
  31. password1 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False),label=_(u'Password'))
  32. password2 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False),label=_(u'Password (again)'))
  33. first_name = forms.CharField(widget=forms.TextInput(attrs=attrs_dict),label=_(u'First Name'))
  34. last_name = forms.CharField(widget=forms.TextInput(attrs=attrs_dict),label=_(u'Last Name'))
  35. email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict,size=50,maxlength=128)),label=_(u'Email Address'))
  36. def clean_username(self):
  37. """
  38. Validate that the username is alphanumeric and is not already
  39. in use.
  40. """
  41. user = User.get_by_key_name("key_"+self.cleaned_data['username'].lower())
  42. if user:
  43. raise forms.ValidationError(_(u'This username is already taken. Please choose another.'))
  44. return self.cleaned_data['username']
  45. def clean_email(self):
  46. """
  47. Validate that the email is unique and is not already
  48. in use.
  49. """
  50. users = User.all().filter('email',self.cleaned_data['email'].lower())
  51. if users.count() > 0:
  52. raise forms.ValidationError(_(u'This email address is already taken. Please choose another.'))
  53. return self.cleaned_data['email']
  54. def clean(self):
  55. """
  56. Verifiy that the values entered into the two password fields
  57. match. Note that an error here will end up in
  58. ``non_field_errors()`` because it doesn't apply to a single
  59. field.
  60. """
  61. _name = self.cleaned_data['first_name']+' '+self.cleaned_data['last_name']
  62. users = [aUser for aUser in User.all() if (aUser.first_name+' '+aUser.last_name) == _name]
  63. if (len(users) > 0):
  64. raise forms.ValidationError(_(u'Another user have already taken your first and last name. Please be more unique.'))
  65. if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
  66. if self.cleaned_data['password1'] != self.cleaned_data['password2']:
  67. raise forms.ValidationError(_(u'You must type the same password twice.'))
  68. return self.cleaned_data
  69. def save(self, domain_override=""):
  70. """
  71. Create the new ``User`` and ``RegistrationProfile``, and
  72. returns the ``User`` (by calling
  73. ``RegistrationProfile.objects.create_inactive_user()``).
  74. """
  75. new_user = RegistrationProfile.objects.create_inactive_user(username=self.cleaned_data['username'],
  76. password=self.cleaned_data['password1'],
  77. email=self.cleaned_data['email'],
  78. first_name=self.cleaned_data['first_name'],
  79. last_name=self.cleaned_data['last_name'],
  80. domain_override=domain_override,
  81. )
  82. return new_user
  83. def getRegistrationEmailMessage(aRegistration,domain_override):
  84. from models import __registration_activation_email_subject__, __registration_activation_email__
  85. subject = django_utils.render_from_string(__registration_activation_email_subject__,context=Context({ 'site': domain_override },autoescape=False))
  86. subject = ''.join(subject.splitlines())
  87. c = { 'activation_key': aRegistration.activation_key,
  88. 'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS,
  89. 'site': domain_override
  90. }
  91. context = Context(c,autoescape=False)
  92. body = django_utils.render_from_string(__registration_activation_email__,context=context)
  93. return (subject,body)
  94. def getAccountPasswordEmailMessage(aRegistration,domain_override):
  95. from vyperlogix.products import keys
  96. from models import __account_password_email_subject__, __account_password_email__
  97. subject = django_utils.render_from_string(__account_password_email_subject__,context=Context({ 'site': domain_override },autoescape=False))
  98. subject = ''.join(subject.splitlines())
  99. c = { 'email_address': keys._encode(aRegistration.user.email),
  100. 'site': domain_override
  101. }
  102. context = Context(c,autoescape=False)
  103. body = django_utils.render_from_string(__account_password_email__,context=context)
  104. return (subject,body)
  105. class ResendRegistrationForm(forms.Form):
  106. """
  107. Form for requesting the Registration be re-sent.
  108. """
  109. email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict,size=50,maxlength=128)),label=_(u'Email Address'))
  110. def save(self, domain_override="", isRunningLocal=False):
  111. """
  112. Resends the Registration email...
  113. """
  114. hasEmailBeenSent = {'bool':False}
  115. _email = self.cleaned_data['email']
  116. registrations = [aRegistration for aRegistration in RegistrationProfile.all() if (not aRegistration.activation_key_expired()) and (aRegistration.user.email == _email)]
  117. if (len(registrations) == 0):
  118. hasEmailBeenSent['reason'] = 'Cannot resend your Registration (Activation) Notice because<BR/>it has expired or has been used.<BR/><BR/>Are you sure you have not simply forgotten your password ?!?'
  119. for aRegistration in registrations:
  120. aMemKey = "ResendRegistrationForm_%s" % (aRegistration.activation_key)
  121. aMemToken = memcache.get(aMemKey)
  122. if aMemToken is not None:
  123. hasEmailBeenSent['reason'] = 'Cannot resend your Registration (Activation) Notice until tomorrow.<BR/>Please try back later.'
  124. else:
  125. subject, body = getRegistrationEmailMessage(aRegistration,domain_override)
  126. hasEmailBeenSent['bool'] = True
  127. from django.core.mail import send_mail
  128. from_email = settings.DEFAULT_FROM_EMAIL
  129. to_email = [aRegistration.user.email]
  130. try:
  131. send_mail(subject, body, from_email, to_email)
  132. aMemToken = {'subject':subject,'body':body,'from_email':from_email,'to_email':to_email}
  133. memcache.add(aMemKey, aMemToken, 60*60*24)
  134. except Exception, e:
  135. info_string = _utils.formattedException(details=e)
  136. logging.error('ResendRegistrationForm.save.ERROR --> %s' % (info_string))
  137. return hasEmailBeenSent
  138. class SendChangePasswordForm(forms.Form):
  139. """
  140. Form for requesting the Change Password Form Link.
  141. """
  142. email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict,size=50,maxlength=128)),label=_(u'Email Address'))
  143. def save(self, domain_override=""):
  144. """
  145. Sends the Change Password email...
  146. """
  147. hasEmailBeenSent = {'bool':False}
  148. _email = self.cleaned_data['email']
  149. registrations = [aRegistration for aRegistration in RegistrationProfile.all() if (aRegistration.activation_key_expired()) and (aRegistration.user.email == _email)]
  150. if (len(registrations) == 0):
  151. hasEmailBeenSent['reason'] = 'Cannot send your Change Password Notice because<BR/>your account is not Active.<BR/><BR/>Are you sure you know your email address ?!?'
  152. for aRegistration in registrations:
  153. aMemKey = "SendChangePasswordForm_%s" % (aRegistration.activation_key)
  154. aMemToken = memcache.get(aMemKey)
  155. if aMemToken is not None:
  156. hasEmailBeenSent['reason'] = 'Cannot send your Change Password Notice until tomorrow.<BR/>Please try back later.'
  157. else:
  158. subject, body = getAccountPasswordEmailMessage(aRegistration,domain_override)
  159. hasEmailBeenSent['bool'] = True
  160. from django.core.mail import send_mail
  161. from_email = settings.DEFAULT_FROM_EMAIL
  162. to_email = [aRegistration.user.email]
  163. try:
  164. send_mail(subject, body, from_email, to_email)
  165. aMemToken = {'subject':subject,'body':body,'from_email':from_email,'to_email':to_email}
  166. memcache.add(aMemKey, aMemToken, 60*60*24)
  167. except Exception, e:
  168. info_string = _utils.formattedException(details=e)
  169. logging.error('SendChangePasswordForm.save.ERROR --> %s' % (info_string))
  170. return hasEmailBeenSent
  171. class ForgotPasswordForm(forms.Form):
  172. """
  173. Form for requesting the Registration be re-sent.
  174. """
  175. email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict,size=50,maxlength=128)),label=_(u'Email Address'))
  176. password1 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False),label=_(u'Password'))
  177. password2 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False),label=_(u'Password (again)'))
  178. def clean(self):
  179. """
  180. Verifiy that the values entered into the two password fields
  181. match. Note that an error here will end up in
  182. ``non_field_errors()`` because it doesn't apply to a single
  183. field.
  184. """
  185. if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
  186. if self.cleaned_data['password1'] != self.cleaned_data['password2']:
  187. raise forms.ValidationError(_(u'You must type the same password each time'))
  188. return self.cleaned_data
  189. def save(self, domain_override=""):
  190. """
  191. Resends the Registration email...
  192. """
  193. hasEmailBeenSent = {'bool':False}
  194. _email = self.cleaned_data['email']
  195. _password1 = self.cleaned_data['password1']
  196. _password2 = self.cleaned_data['password2']
  197. registrations = [aRegistration for aRegistration in RegistrationProfile.all() if (aRegistration.activation_key_expired()) and (aRegistration.user.email == _email)]
  198. if (len(registrations) == 0):
  199. hasEmailBeenSent['reason'] = 'Cannot reset your Password because<BR/>you either have not Activated your Registration<BR/>or you have not submitted your Registration.'
  200. for aRegistration in registrations:
  201. aMemKey = "ResendRegistrationForm_%s" % (aRegistration.activation_key)
  202. try:
  203. aRegistration.user.is_active = False
  204. salt = sha.new(str(random.random())).hexdigest()[:5]
  205. aRegistration.activation_key = sha.new(salt+aRegistration.user.username).hexdigest()
  206. aRegistration.user.set_password(_password1)
  207. aRegistration.user.save()
  208. aRegistration.save()
  209. subject, body = getRegistrationEmailMessage(aRegistration,domain_override)
  210. from django.core.mail import send_mail
  211. from_email = settings.DEFAULT_FROM_EMAIL
  212. to_email = [aRegistration.user.email]
  213. try:
  214. send_mail(subject, body, from_email, to_email)
  215. aMemToken = {'subject':subject,'body':body,'from_email':from_email,'to_email':to_email}
  216. memcache.add(aMemKey, aMemToken, 60*60*24)
  217. except Exception, e:
  218. info_string = _utils.formattedException(details=e)
  219. logging.error('ForgotPasswordForm.save.ERROR.1 --> %s' % (info_string))
  220. hasEmailBeenSent['bool'] = True
  221. except Exception, e:
  222. info_string = _utils.formattedException(details=e)
  223. logging.error('ForgotPasswordForm.save.ERROR.2 --> %s' % (info_string))
  224. return hasEmailBeenSent
  225. class RegistrationFormTermsOfService(RegistrationForm):
  226. """
  227. Subclass of ``RegistrationForm`` which adds a required checkbox
  228. for agreeing to a site's Terms of Service.
  229. """
  230. tos = forms.BooleanField(widget=forms.CheckboxInput(attrs=attrs_dict),
  231. label=_(u'I have read and agree to the Terms of Service'),
  232. error_messages={ 'required': u"You must agree to the terms to register" })
  233. class RegistrationFormUniqueEmail(RegistrationForm):
  234. """
  235. Subclass of ``RegistrationForm`` which enforces uniqueness of
  236. email addresses.
  237. """
  238. def clean_email(self):
  239. """
  240. Validate that the supplied email address is unique for the
  241. site.
  242. """
  243. email = self.cleaned_data['email'].lower()
  244. if User.all().filter('email =', email).count(1):
  245. raise forms.ValidationError(_(u'This email address is already in use. Please supply a different email address.'))
  246. return email
  247. class RegistrationFormNoFreeEmail(RegistrationForm):
  248. """
  249. Subclass of ``RegistrationForm`` which disallows registration with
  250. email addresses from popular free webmail services; moderately
  251. useful for preventing automated spam registrations.
  252. To change the list of banned domains, subclass this form and
  253. override the attribute ``bad_domains``.
  254. """
  255. bad_domains = ['aim.com', 'aol.com', 'email.com', 'gmail.com',
  256. 'googlemail.com', 'hotmail.com', 'hushmail.com',
  257. 'msn.com', 'mail.ru', 'mailinator.com', 'live.com']
  258. def clean_email(self):
  259. """
  260. Check the supplied email address against a list of known free
  261. webmail domains.
  262. """
  263. email_domain = self.cleaned_data['email'].split('@')[1]
  264. if email_domain in self.bad_domains:
  265. raise forms.ValidationError(_(u'Registration using free email addresses is prohibited. Please supply a different email address.'))
  266. return self.cleaned_data['email']