PageRenderTime 26ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/appengine/auth/forms.py

https://code.google.com/p/pageforest/
Python | 195 lines | 191 code | 4 blank | 0 comment | 5 complexity | 07a607732fec9d4e2ecf2a16bb7234b4 MD5 | raw file
  1. import re
  2. import string
  3. import logging
  4. from django import forms
  5. from django.conf import settings
  6. from django.utils.safestring import mark_safe
  7. from utils.forms import AjaxForm
  8. from auth.models import User
  9. KEYBOARD_ROWS = """
  10. `1234567890-=
  11. qwertyuiop[]\
  12. qwertzuiop
  13. asdfghjkl;'
  14. zxcvbnm,./
  15. yxcvbnm,.-
  16. """.split()
  17. USERNAME_REGEX_MATCH = re.compile('^%s$' % settings.USERNAME_REGEX).match
  18. class LabeledCheckbox(forms.CheckboxInput):
  19. """
  20. Checkbox with a label.
  21. """
  22. def __init__(self, attrs=None, label=None, field_id=None):
  23. super(LabeledCheckbox, self).__init__(attrs)
  24. self.label = label
  25. self.field_id = field_id
  26. def render(self, name, value, attrs=None):
  27. """
  28. Generate HTML for a checkbox with a label.
  29. """
  30. check_string = super(LabeledCheckbox, self).render(name, value, attrs)
  31. import logging
  32. check_string += '&nbsp;<label for="id_%s">%s</label>' % (
  33. self.field_id, self.label)
  34. return mark_safe(check_string)
  35. class ReadonlyTextInput(forms.TextInput):
  36. def render(self, name, value, attrs=None):
  37. if self.attrs.get('readonly', False):
  38. if value is None:
  39. value = ''
  40. return unicode(value)
  41. return super(ReadonlyTextInput, self).render(name, value, attrs)
  42. class ReadonlyCheckboxInput(forms.CheckboxInput):
  43. def render(self, name, value, attrs=None):
  44. if self.attrs.get('readonly', False):
  45. return unicode(value)
  46. return super(ReadonlyCheckboxInput, self).render(name, value, attrs)
  47. class Static(forms.Widget):
  48. def render(self, name, value, attrs=None):
  49. if value is None:
  50. value = ''
  51. return unicode(value)
  52. class UsernamePasswordForm(AjaxForm):
  53. """
  54. Reusable form class with a username and password field.
  55. Both SignUpForm and SignInForm are subclasses of this.
  56. """
  57. username = forms.CharField(min_length=2, max_length=30,
  58. widget=forms.TextInput(attrs={'class': 'focus'}))
  59. password = forms.CharField(min_length=40, max_length=40,
  60. widget=forms.PasswordInput(render_value=False))
  61. def clean_username(self):
  62. """
  63. Validate the username and return helpful error messages.
  64. """
  65. username = self.cleaned_data['username']
  66. key_name = username.lower()
  67. if username[0] not in string.ascii_letters:
  68. raise forms.ValidationError(
  69. "Username must start with a letter.")
  70. if username[-1] not in string.ascii_letters + string.digits:
  71. raise forms.ValidationError(
  72. "Username must end with a letter or number.")
  73. if not USERNAME_REGEX_MATCH(username):
  74. raise forms.ValidationError(
  75. "Username must contain only letters, numbers and dashes.")
  76. if key_name in settings.RESERVED_USERNAMES:
  77. raise forms.ValidationError("This username is reserved.")
  78. return username
  79. class SignUpForm(UsernamePasswordForm):
  80. """
  81. Account registration form for new users, with helpful error messages.
  82. """
  83. repeat = forms.CharField(max_length=40, label="Repeat password",
  84. widget=forms.PasswordInput(render_value=False), required=False)
  85. email = forms.EmailField(max_length=75, label="Email address")
  86. tos = forms.BooleanField(
  87. label="Terms of Service",
  88. widget=LabeledCheckbox(label="I agree", field_id='tos'),
  89. error_messages={'required':
  90. mark_safe('You must agree to the <a href="http://' +
  91. settings.DEFAULT_DOMAIN + '/terms-of-service' +
  92. '" target="_blank">Terms of Service</a>.')})
  93. def clean_username(self):
  94. """
  95. Verify that the username is available.
  96. """
  97. username = super(SignUpForm, self).clean_username()
  98. if User.lookup(username):
  99. raise forms.ValidationError("This username is already taken.")
  100. return username
  101. def save(self):
  102. """
  103. Create a new user with the form data.
  104. """
  105. username = self.cleaned_data['username']
  106. user = User(key_name=username.lower(),
  107. username=username,
  108. email=self.cleaned_data['email'],
  109. password=self.cleaned_data['password'])
  110. user.put()
  111. return user
  112. class ProfileForm(AjaxForm):
  113. """
  114. Edit account information for existing users.
  115. """
  116. username = forms.CharField(min_length=2, max_length=30,
  117. widget=Static)
  118. email = forms.EmailField(max_length=75, label="Email address",
  119. widget=Static)
  120. password = forms.CharField(min_length=40, max_length=40,
  121. widget=forms.PasswordInput(render_value=False))
  122. repeat = forms.CharField(max_length=40, label="Repeat password",
  123. widget=forms.PasswordInput(render_value=False), required=False)
  124. is_admin = forms.BooleanField(label="Admin",
  125. widget=ReadonlyCheckboxInput)
  126. max_apps = forms.IntegerField(label="Max Apps",
  127. widget=ReadonlyTextInput)
  128. def enable_fields(self, user):
  129. if not (user.is_admin or user.get_username() in settings.SUPER_USERS):
  130. self.fields['is_admin'].widget.attrs['readonly'] = True
  131. self.fields['max_apps'].widget.attrs['readonly'] = True
  132. def save(self, user):
  133. """
  134. Create a new user with the form data.
  135. """
  136. user.max_apps = self.cleaned_data['max_apps']
  137. user.is_admin = self.cleaned_data['is_admin']
  138. user.put()
  139. class SignInForm(UsernamePasswordForm):
  140. """
  141. User authentication form.
  142. """
  143. appauth = forms.BooleanField(
  144. required=False,
  145. label="Application",
  146. widget=LabeledCheckbox(label="Allow access", field_id='appauth'))
  147. def clean_username(self):
  148. """
  149. Check that the user exists.
  150. """
  151. username = super(SignInForm, self).clean_username()
  152. user = User.lookup(username)
  153. if user is None:
  154. raise forms.ValidationError("No account for %s." % username)
  155. self.cleaned_data['user'] = user
  156. return username
  157. def clean(self):
  158. """
  159. Raise an error if the password does not match.
  160. """
  161. user = self.cleaned_data.get('user', None)
  162. password = self.cleaned_data.get('password', None)
  163. if user and password and password.lower() != user.password:
  164. raise forms.ValidationError("Invalid password.")
  165. return self.cleaned_data