Commit a1c591e46219d778c76b8fb4a43fc3a6f1d56bca

Authored by Sergio Oliveira
1 parent 0816569e

Added django default forms

[skip ci]
Showing 2 changed files with 327 additions and 10 deletions   Show diff stats
colab/accounts/admin.py
1 1  
2 2 from django import forms
3 3 from django.contrib import admin
  4 +from django.contrib.auth import get_user_model
4 5 from django.contrib.auth.admin import UserAdmin
  6 +from django.contrib.auth.forms import UserCreationForm
5 7 from django.utils.translation import ugettext_lazy as _
6 8  
7   -from .models import User
  9 +User = get_user_model()
8 10  
9 11  
10   -class UserCreationForm(forms.ModelForm):
  12 +class CustomUserCreationForm(UserCreationForm):
11 13 class Meta:
12 14 model = User
13   - fields = ('username', 'email')
  15 + fields = ("username", "email")
14 16  
15   - def __init__(self, *args, **kwargs):
16   - super(UserCreationForm, self).__init__(*args, **kwargs)
17   - self.fields['email'].required = True
  17 + #def __init__(self, *args, **kwargs):
  18 + # super(CustomUserCreationForm, self).__init__(*args, **kwargs)
  19 + # self.fields['email'].required = True
18 20  
19 21  
20 22 class UserChangeForm(forms.ModelForm):
... ... @@ -33,10 +35,10 @@ class UserChangeForm(forms.ModelForm):
33 35  
34 36 class MyUserAdmin(UserAdmin):
35 37 form = UserChangeForm
36   - add_form = UserCreationForm
  38 + add_form = CustomUserCreationForm
37 39  
38 40 fieldsets = (
39   - (None, {'fields': ('username', 'email')}),
  41 + (None, {'fields': ('username', 'email', 'password')}),
40 42 (_('Personal info'), {'fields': ('first_name', 'last_name', 'twitter',
41 43 'facebook', 'google_talk', 'webpage',
42 44 )}),
... ... @@ -48,8 +50,8 @@ class MyUserAdmin(UserAdmin):
48 50 add_fieldsets = (
49 51 (None, {
50 52 'classes': ('wide',),
51   - 'fields': ('username', 'email')}
52   - ),
  53 + 'fields': ('username', 'email', 'password1', 'password2'),
  54 + }),
53 55 )
54 56  
55 57  
... ...
colab/accounts/forms.py
... ... @@ -158,3 +158,318 @@ class ChangeXMPPPasswordForm(forms.ModelForm):
158 158 if commit:
159 159 self.instance.save()
160 160 return self.instance
  161 +
  162 +class UserCreationForm(forms.ModelForm):
  163 + """
  164 + A form that creates a user, with no privileges, from the given username and
  165 + password.
  166 + """
  167 + error_messages = {
  168 + 'duplicate_username': _("A user with that username already exists."),
  169 + 'password_mismatch': _("The two password fields didn't match."),
  170 + }
  171 + username = forms.RegexField(label=_("Username"), max_length=30,
  172 + regex=r'^[\w.@+-]+$',
  173 + help_text=_("Required. 30 characters or fewer. Letters, digits and "
  174 + "@/./+/-/_ only."),
  175 + error_messages={
  176 + 'invalid': _("This value may contain only letters, numbers and "
  177 + "@/./+/-/_ characters.")})
  178 + password1 = forms.CharField(label=_("Password"),
  179 + widget=forms.PasswordInput)
  180 + password2 = forms.CharField(label=_("Password confirmation"),
  181 + widget=forms.PasswordInput,
  182 + help_text=_("Enter the same password as above, for verification."))
  183 +
  184 + class Meta:
  185 + model = User
  186 + fields = ("username",)
  187 +
  188 + def clean_username(self):
  189 + # Since User.username is unique, this check is redundant,
  190 + # but it sets a nicer error message than the ORM. See #13147.
  191 + username = self.cleaned_data["username"]
  192 + try:
  193 + User._default_manager.get(username=username)
  194 + except User.DoesNotExist:
  195 + return username
  196 + raise forms.ValidationError(
  197 + self.error_messages['duplicate_username'],
  198 + code='duplicate_username',
  199 + )
  200 +
  201 + def clean_password2(self):
  202 + password1 = self.cleaned_data.get("password1")
  203 + password2 = self.cleaned_data.get("password2")
  204 + if password1 and password2 and password1 != password2:
  205 + raise forms.ValidationError(
  206 + self.error_messages['password_mismatch'],
  207 + code='password_mismatch',
  208 + )
  209 + return password2
  210 +
  211 + def save(self, commit=True):
  212 + user = super(UserCreationForm, self).save(commit=False)
  213 + user.set_password(self.cleaned_data["password1"])
  214 + if commit:
  215 + user.save()
  216 + return user
  217 +
  218 +
  219 +class UserChangeForm(forms.ModelForm):
  220 + username = forms.RegexField(
  221 + label=_("Username"), max_length=30, regex=r"^[\w.@+-]+$",
  222 + help_text=_("Required. 30 characters or fewer. Letters, digits and "
  223 + "@/./+/-/_ only."),
  224 + error_messages={
  225 + 'invalid': _("This value may contain only letters, numbers and "
  226 + "@/./+/-/_ characters.")})
  227 + password = ReadOnlyPasswordHashField(label=_("Password"),
  228 + help_text=_("Raw passwords are not stored, so there is no way to see "
  229 + "this user's password, but you can change the password "
  230 + "using <a href=\"password/\">this form</a>."))
  231 +
  232 + class Meta:
  233 + model = User
  234 + fields = '__all__'
  235 +
  236 + def __init__(self, *args, **kwargs):
  237 + super(UserChangeForm, self).__init__(*args, **kwargs)
  238 + f = self.fields.get('user_permissions', None)
  239 + if f is not None:
  240 + f.queryset = f.queryset.select_related('content_type')
  241 +
  242 + def clean_password(self):
  243 + # Regardless of what the user provides, return the initial value.
  244 + # This is done here, rather than on the field, because the
  245 + # field does not have access to the initial value
  246 + return self.initial["password"]
  247 +
  248 +
  249 +class AuthenticationForm(forms.Form):
  250 + """
  251 + Base class for authenticating users. Extend this to get a form that accepts
  252 + username/password logins.
  253 + """
  254 + username = forms.CharField(max_length=254)
  255 + password = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
  256 +
  257 + error_messages = {
  258 + 'invalid_login': _("Please enter a correct %(username)s and password. "
  259 + "Note that both fields may be case-sensitive."),
  260 + 'inactive': _("This account is inactive."),
  261 + }
  262 +
  263 + def __init__(self, request=None, *args, **kwargs):
  264 + """
  265 + The 'request' parameter is set for custom auth use by subclasses.
  266 + The form data comes in via the standard 'data' kwarg.
  267 + """
  268 + self.request = request
  269 + self.user_cache = None
  270 + super(AuthenticationForm, self).__init__(*args, **kwargs)
  271 +
  272 + # Set the label for the "username" field.
  273 + UserModel = get_user_model()
  274 + self.username_field = UserModel._meta.get_field(UserModel.USERNAME_FIELD)
  275 + if self.fields['username'].label is None:
  276 + self.fields['username'].label = capfirst(self.username_field.verbose_name)
  277 +
  278 + def clean(self):
  279 + username = self.cleaned_data.get('username')
  280 + password = self.cleaned_data.get('password')
  281 +
  282 + if username and password:
  283 + self.user_cache = authenticate(username=username,
  284 + password=password)
  285 + if self.user_cache is None:
  286 + raise forms.ValidationError(
  287 + self.error_messages['invalid_login'],
  288 + code='invalid_login',
  289 + params={'username': self.username_field.verbose_name},
  290 + )
  291 + else:
  292 + self.confirm_login_allowed(self.user_cache)
  293 +
  294 + return self.cleaned_data
  295 +
  296 + def confirm_login_allowed(self, user):
  297 + """
  298 + Controls whether the given User may log in. This is a policy setting,
  299 + independent of end-user authentication. This default behavior is to
  300 + allow login by active users, and reject login by inactive users.
  301 + If the given user cannot log in, this method should raise a
  302 + ``forms.ValidationError``.
  303 + If the given user may log in, this method should return None.
  304 + """
  305 + if not user.is_active:
  306 + raise forms.ValidationError(
  307 + self.error_messages['inactive'],
  308 + code='inactive',
  309 + )
  310 +
  311 + def get_user_id(self):
  312 + if self.user_cache:
  313 + return self.user_cache.id
  314 + return None
  315 +
  316 + def get_user(self):
  317 + return self.user_cache
  318 +
  319 +
  320 +class PasswordResetForm(forms.Form):
  321 + email = forms.EmailField(label=_("Email"), max_length=254)
  322 +
  323 + def save(self, domain_override=None,
  324 + subject_template_name='registration/password_reset_subject.txt',
  325 + email_template_name='registration/password_reset_email.html',
  326 + use_https=False, token_generator=default_token_generator,
  327 + from_email=None, request=None, html_email_template_name=None):
  328 + """
  329 + Generates a one-use only link for resetting password and sends to the
  330 + user.
  331 + """
  332 + from django.core.mail import send_mail
  333 + UserModel = get_user_model()
  334 + email = self.cleaned_data["email"]
  335 + active_users = UserModel._default_manager.filter(
  336 + email__iexact=email, is_active=True)
  337 + for user in active_users:
  338 + # Make sure that no email is sent to a user that actually has
  339 + # a password marked as unusable
  340 + if not user.has_usable_password():
  341 + continue
  342 + if not domain_override:
  343 + current_site = get_current_site(request)
  344 + site_name = current_site.name
  345 + domain = current_site.domain
  346 + else:
  347 + site_name = domain = domain_override
  348 + c = {
  349 + 'email': user.email,
  350 + 'domain': domain,
  351 + 'site_name': site_name,
  352 + 'uid': urlsafe_base64_encode(force_bytes(user.pk)),
  353 + 'user': user,
  354 + 'token': token_generator.make_token(user),
  355 + 'protocol': 'https' if use_https else 'http',
  356 + }
  357 + subject = loader.render_to_string(subject_template_name, c)
  358 + # Email subject *must not* contain newlines
  359 + subject = ''.join(subject.splitlines())
  360 + email = loader.render_to_string(email_template_name, c)
  361 +
  362 + if html_email_template_name:
  363 + html_email = loader.render_to_string(html_email_template_name, c)
  364 + else:
  365 + html_email = None
  366 + send_mail(subject, email, from_email, [user.email], html_message=html_email)
  367 +
  368 +
  369 +class SetPasswordForm(forms.Form):
  370 + """
  371 + A form that lets a user change set their password without entering the old
  372 + password
  373 + """
  374 + error_messages = {
  375 + 'password_mismatch': _("The two password fields didn't match."),
  376 + }
  377 + new_password1 = forms.CharField(label=_("New password"),
  378 + widget=forms.PasswordInput)
  379 + new_password2 = forms.CharField(label=_("New password confirmation"),
  380 + widget=forms.PasswordInput)
  381 +
  382 + def __init__(self, user, *args, **kwargs):
  383 + self.user = user
  384 + super(SetPasswordForm, self).__init__(*args, **kwargs)
  385 +
  386 + def clean_new_password2(self):
  387 + password1 = self.cleaned_data.get('new_password1')
  388 + password2 = self.cleaned_data.get('new_password2')
  389 + if password1 and password2:
  390 + if password1 != password2:
  391 + raise forms.ValidationError(
  392 + self.error_messages['password_mismatch'],
  393 + code='password_mismatch',
  394 + )
  395 + return password2
  396 +
  397 + def save(self, commit=True):
  398 + self.user.set_password(self.cleaned_data['new_password1'])
  399 + if commit:
  400 + self.user.save()
  401 + return self.user
  402 +
  403 +
  404 +class PasswordChangeForm(SetPasswordForm):
  405 + """
  406 + A form that lets a user change their password by entering their old
  407 + password.
  408 + """
  409 + error_messages = dict(SetPasswordForm.error_messages, **{
  410 + 'password_incorrect': _("Your old password was entered incorrectly. "
  411 + "Please enter it again."),
  412 + })
  413 + old_password = forms.CharField(label=_("Old password"),
  414 + widget=forms.PasswordInput)
  415 +
  416 + def clean_old_password(self):
  417 + """
  418 + Validates that the old_password field is correct.
  419 + """
  420 + old_password = self.cleaned_data["old_password"]
  421 + if not self.user.check_password(old_password):
  422 + raise forms.ValidationError(
  423 + self.error_messages['password_incorrect'],
  424 + code='password_incorrect',
  425 + )
  426 + return old_password
  427 +
  428 +PasswordChangeForm.base_fields = OrderedDict(
  429 + (k, PasswordChangeForm.base_fields[k])
  430 + for k in ['old_password', 'new_password1', 'new_password2']
  431 +)
  432 +
  433 +
  434 +class AdminPasswordChangeForm(forms.Form):
  435 + """
  436 + A form used to change the password of a user in the admin interface.
  437 + """
  438 + error_messages = {
  439 + 'password_mismatch': _("The two password fields didn't match."),
  440 + }
  441 + password1 = forms.CharField(label=_("Password"),
  442 + widget=forms.PasswordInput)
  443 + password2 = forms.CharField(label=_("Password (again)"),
  444 + widget=forms.PasswordInput)
  445 +
  446 + def __init__(self, user, *args, **kwargs):
  447 + self.user = user
  448 + super(AdminPasswordChangeForm, self).__init__(*args, **kwargs)
  449 +
  450 + def clean_password2(self):
  451 + password1 = self.cleaned_data.get('password1')
  452 + password2 = self.cleaned_data.get('password2')
  453 + if password1 and password2:
  454 + if password1 != password2:
  455 + raise forms.ValidationError(
  456 + self.error_messages['password_mismatch'],
  457 + code='password_mismatch',
  458 + )
  459 + return password2
  460 +
  461 + def save(self, commit=True):
  462 + """
  463 + Saves the new password.
  464 + """
  465 + self.user.set_password(self.cleaned_data["password1"])
  466 + if commit:
  467 + self.user.save()
  468 + return self.user
  469 +
  470 + def _get_changed_data(self):
  471 + data = super(AdminPasswordChangeForm, self).changed_data
  472 + for name in self.fields.keys():
  473 + if name not in data:
  474 + return []
  475 + return ['password']
... ...