From 883b69500cd737e631469ac9db10478513c5c178 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Sun, 26 Oct 2014 13:37:25 -0700 Subject: [PATCH] signup robustness --- core/forms.py | 22 +++++++++++---- core/tests/view_tests.py | 60 +++++++++++++++++++++++++++------------- core/views/views.py | 38 ++++++++++++------------- templates/sign_up.html | 3 +- 4 files changed, 76 insertions(+), 47 deletions(-) diff --git a/core/forms.py b/core/forms.py index b1fd234..66db58d 100644 --- a/core/forms.py +++ b/core/forms.py @@ -1,13 +1,25 @@ from django import forms +from core.models import FinetoothUser class CommentForm(forms.Form): content = forms.CharField( label="", widget=forms.Textarea(attrs={'rows': 6}) ) -class SignupForm(forms.Form): - username = forms.CharField(label="username") - password = forms.CharField(widget=forms.PasswordInput()) - confirm_password = forms.CharField(widget=forms.PasswordInput()) - email = forms.CharField() \ No newline at end of file +class SignupForm(forms.ModelForm): + class Meta: + model = FinetoothUser + fields = ('username', 'email') + + password = forms.CharField(widget=forms.PasswordInput) + confirm_password = forms.CharField(widget=forms.PasswordInput) + + def clean_confirm_password(self): + password = self.cleaned_data.get('password') + confirm_password = self.cleaned_data.get('confirm_password') + if password != confirm_password: + raise forms.ValidationError( + "Password confirmation didn't match." + ) + return password diff --git a/core/tests/view_tests.py b/core/tests/view_tests.py index 94e0512..e5b0e21 100644 --- a/core/tests/view_tests.py +++ b/core/tests/view_tests.py @@ -15,34 +15,56 @@ class SignupTest(TestCase): def test_can_sign_up(self): response = self.client.post( reverse('sign_up'), - {'username': "signup_testr", 'password': "moeDukr(,rpdCesLlrqr", - 'confirm_password': "moeDukr(,rpdCesLlrqr", 'email': "signuptest@example.com"} - ) - # XX: The call to assertRedirects was printing an empty - # dictionary to standard out (if someone accidentally left a - # debugging print statement in Django core (?!), I couldn't - # find it) - with open(os.devnull, 'w') as dev_null: - original_stdout = sys.stdout - sys.stdout = dev_null - self.assertRedirects(response, '/') - sys.stdout = original_stdout - self.assertTrue( - FinetoothUser.objects.filter(username="signup_testr").exists() - ) - - @skip("an apparently spurious TransactionManagementError due to the issue " - "described at http://stackoverflow.com/a/23326971") # TODO FIXME + {'username': "signup_testr", + 'password': "moeDukr(,rpdCesLlrq", + 'confirm_password': "moeDukr(,rpdCesLlrq", + 'email': "signuptest@example.com"} + ) + self.assertRedirects(response, '/') + user_queryset = FinetoothUser.objects.filter(username="signup_testr") + self.assertTrue(user_queryset.exists()) + self.assertTrue(user_queryset[0].check_password("moeDukr(,rpdCesLlrq")) + def test_cannnot_claim_extant_username(self): f.FinetoothUserFactory.create(username="username_squatter") response = self.client.post( reverse('sign_up'), - {'username': "username_squatter", 'password': "oclxJums^whyysmtam", + {'username': "username_squatter", + 'password': "oclxJums^whyysmtam", + 'confirm_password': "oclxJums^whyysmtam", 'email': "metoo@example.com"}, follow=True ) self.assertIn(b"Username already exists.", response.content) + def test_confirm_password_must_match(self): + prior_user_count = FinetoothUser.objects.count() + response = self.client.post( + reverse('sign_up'), + {'username': "pentest", + 'password': "*sd6f3mjdrt3y42", + 'confirm_password': "not_the_same_password_is_it", + 'email': "pt@example.com"}, + follow=True + ) + post_user_count = FinetoothUser.objects.count() + self.assertEqual(prior_user_count, post_user_count) + self.assertEqual(422, response.status_code) + + def test_required_fields(self): + prior_user_count = FinetoothUser.objects.count() + response = self.client.post( + reverse('sign_up'), + {'username': '', + 'password': "oclxJums^whyysmtam", + 'confirm_password': "oclxJums^whyysmtam", + 'email': ''}, + follow=True + ) + post_user_count = FinetoothUser.objects.count() + self.assertEqual(prior_user_count, post_user_count) + self.assertEqual(422, response.status_code) + class TaggingTest(TestCase): diff --git a/core/views/views.py b/core/views/views.py index 8efce6f..1b2cf80 100644 --- a/core/views/views.py +++ b/core/views/views.py @@ -1,13 +1,11 @@ import json from datetime import datetime - from django.shortcuts import render, redirect from django.http import HttpResponse from django.http import HttpResponseForbidden from django.http import HttpResponseBadRequest from django.http import HttpRequest - from django.views.decorators.csrf import csrf_exempt from django.views.decorators.debug import sensitive_post_parameters from django.views.decorators.http import require_POST @@ -32,30 +30,28 @@ def home(request, page_number): context = scored_context(context['posts'], context) return render(request, "home.html", context) -@sensitive_post_parameters('password') +@sensitive_post_parameters('password', 'confirm_password') def sign_up(request): if request.method == "POST": signup_form = SignupForm(request.POST) if signup_form.is_valid(): - try: - username = signup_form.cleaned_data["username"] - email = signup_form.cleaned_data["email"] - password = signup_form.cleaned_data["password"] - confirm_password = signup_form.cleaned_data["confirm_password"] - if password != confirm_password: - messages.error(request, "Passwords do not match.") - return render(request, 'sign_up.html', {'form': signup_form}) - FinetoothUser.objects.create_user(username, email, password) - messages.success(request, "Account creation successful!") - new_user = authenticate(username=username, password=password) - login(request, new_user) - return redirect("home") - except IntegrityError: - messages.error(request, "Username already exists.") - return redirect("sign_up") + username = signup_form.cleaned_data["username"] + email = signup_form.cleaned_data["email"] + password = signup_form.cleaned_data["password"] + confirm_password = signup_form.cleaned_data["confirm_password"] + FinetoothUser.objects.create_user(username, email, password) + messages.success(request, "Account creation successful!") + new_user = authenticate(username=username, password=password) + login(request, new_user) + return redirect("home") + else: + messages.warning(request, signup_form.errors) + return render( + request, 'sign_up.html', {'signup_form': signup_form}, status=422 + ) else: - form = SignupForm() - return render(request, 'sign_up.html', locals()) + signup_form = SignupForm() + return render(request, 'sign_up.html', {'signup_form': signup_form}) @require_POST def logout_view(request): diff --git a/templates/sign_up.html b/templates/sign_up.html index 1c0d1d1..c7377ed 100644 --- a/templates/sign_up.html +++ b/templates/sign_up.html @@ -5,9 +5,8 @@ {% block content %}
{% csrf_token %} -{{form.as_p}} +{{ signup_form.as_p }}

{% endblock %} -