Commit 751669cb by David Baumgold

/create_account: use proper HTTP status codes

Use status code 400 when there is a validation error in creating an account.
parent 7b4ea225
...@@ -111,7 +111,7 @@ class AuthTestCase(ContentStoreTestCase): ...@@ -111,7 +111,7 @@ class AuthTestCase(ContentStoreTestCase):
def test_create_account_errors(self): def test_create_account_errors(self):
# No post data -- should fail # No post data -- should fail
resp = self.client.post('/create_account', {}) resp = self.client.post('/create_account', {})
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 400)
data = parse_json(resp) data = parse_json(resp)
self.assertEqual(data['success'], False) self.assertEqual(data['success'], False)
......
...@@ -107,31 +107,25 @@ require(["jquery", "jquery.cookie"], function($) { ...@@ -107,31 +107,25 @@ require(["jquery", "jquery.cookie"], function($) {
$("label").removeClass("is-focused"); $("label").removeClass("is-focused");
}); });
// form validation
function postJSON(url, data, callback) {
$.ajax({type:'POST',
url: url,
dataType: 'json',
data: data,
success: callback,
headers : {'X-CSRFToken': $.cookie('csrftoken')}
});
}
$('form#register_form').submit(function(e) { $('form#register_form').submit(function(e) {
e.preventDefault(); e.preventDefault();
var submit_data = $('#register_form').serialize(); var submit_data = $('#register_form').serialize();
postJSON('/create_account', $.ajax({
submit_data, url: '/create_account',
function(json) { type: 'POST',
if(json.success) { dataType: 'json',
location.href = "${'/course'}"; data: submit_data,
} else { headers: {'X-CSRFToken': $.cookie('csrftoken')},
success: function(json) {
location.href = "/course";
},
error: function(jqXHR, textStatus, errorThrown) {
json = $.parseJSON(jqXHR.responseText);
$('#register_error').html(json.value).stop().addClass('is-shown'); $('#register_error').html(json.value).stop().addClass('is-shown');
} },
} notifyOnError: false
); });
}); });
}); });
</script> </script>
......
...@@ -897,13 +897,13 @@ def create_account(request, post_override=None): ...@@ -897,13 +897,13 @@ def create_account(request, post_override=None):
if a not in post_vars: if a not in post_vars:
js['value'] = _("Error (401 {field}). E-mail us.").format(field=a) js['value'] = _("Error (401 {field}). E-mail us.").format(field=a)
js['field'] = a js['field'] = a
return HttpResponse(json.dumps(js)) return JsonResponse(js, status=400)
if extra_fields.get('honor_code', 'required') == 'required' and \ if extra_fields.get('honor_code', 'required') == 'required' and \
post_vars.get('honor_code', 'false') != u'true': post_vars.get('honor_code', 'false') != u'true':
js['value'] = _("To enroll, you must follow the honor code.").format(field=a) js['value'] = _("To enroll, you must follow the honor code.").format(field=a)
js['field'] = 'honor_code' js['field'] = 'honor_code'
return HttpResponse(json.dumps(js)) return JsonResponse(js, status=400)
# Can't have terms of service for certain SHIB users, like at Stanford # Can't have terms of service for certain SHIB users, like at Stanford
tos_required = ( tos_required = (
...@@ -919,7 +919,7 @@ def create_account(request, post_override=None): ...@@ -919,7 +919,7 @@ def create_account(request, post_override=None):
if post_vars.get('terms_of_service', 'false') != u'true': if post_vars.get('terms_of_service', 'false') != u'true':
js['value'] = _("You must accept the terms of service.").format(field=a) js['value'] = _("You must accept the terms of service.").format(field=a)
js['field'] = 'terms_of_service' js['field'] = 'terms_of_service'
return HttpResponse(json.dumps(js)) return JsonResponse(js, status=400)
# Confirm appropriate fields are there. # Confirm appropriate fields are there.
# TODO: Check e-mail format is correct. # TODO: Check e-mail format is correct.
...@@ -957,21 +957,21 @@ def create_account(request, post_override=None): ...@@ -957,21 +957,21 @@ def create_account(request, post_override=None):
} }
js['value'] = error_str[field_name] js['value'] = error_str[field_name]
js['field'] = field_name js['field'] = field_name
return HttpResponse(json.dumps(js)) return JsonResponse(js, status=400)
try: try:
validate_email(post_vars['email']) validate_email(post_vars['email'])
except ValidationError: except ValidationError:
js['value'] = _("Valid e-mail is required.").format(field=a) js['value'] = _("Valid e-mail is required.").format(field=a)
js['field'] = 'email' js['field'] = 'email'
return HttpResponse(json.dumps(js)) return JsonResponse(js, status=400)
try: try:
validate_slug(post_vars['username']) validate_slug(post_vars['username'])
except ValidationError: except ValidationError:
js['value'] = _("Username should only consist of A-Z and 0-9, with no spaces.").format(field=a) js['value'] = _("Username should only consist of A-Z and 0-9, with no spaces.").format(field=a)
js['field'] = 'username' js['field'] = 'username'
return HttpResponse(json.dumps(js)) return JsonResponse(js, status=400)
# Ok, looks like everything is legit. Create the account. # Ok, looks like everything is legit. Create the account.
ret = _do_create_account(post_vars) ret = _do_create_account(post_vars)
...@@ -1007,7 +1007,10 @@ def create_account(request, post_override=None): ...@@ -1007,7 +1007,10 @@ def create_account(request, post_override=None):
except: except:
log.warning('Unable to send activation email to user', exc_info=True) log.warning('Unable to send activation email to user', exc_info=True)
js['value'] = _('Could not send activation e-mail.') js['value'] = _('Could not send activation e-mail.')
return HttpResponse(json.dumps(js)) # What is the correct status code to use here? I think it's 500, because
# the problem is on the server's end -- but also, the account was created.
# Seems like the core part of the request was successful.
return JsonResponse(js, status=500)
# Immediately after a user creates an account, we log them in. They are only # Immediately after a user creates an account, we log them in. They are only
# logged in until they close the browser. They can't log in again until they click # logged in until they close the browser. They can't log in again until they click
...@@ -1034,14 +1037,12 @@ def create_account(request, post_override=None): ...@@ -1034,14 +1037,12 @@ def create_account(request, post_override=None):
login_user.save() login_user.save()
AUDIT_LOG.info(u"Login activated on extauth account - {0} ({1})".format(login_user.username, login_user.email)) AUDIT_LOG.info(u"Login activated on extauth account - {0} ({1})".format(login_user.username, login_user.email))
redirect_url = try_change_enrollment(request)
dog_stats_api.increment("common.student.account_created") dog_stats_api.increment("common.student.account_created")
response_params = {'success': True, response = JsonResponse({
'redirect_url': redirect_url} 'success': True,
'redirect_url': try_change_enrollment(request),
response = HttpResponse(json.dumps(response_params)) })
# set the login cookie for the edx marketing site # set the login cookie for the edx marketing site
# we want this cookie to be accessed via javascript # we want this cookie to be accessed via javascript
......
...@@ -6,49 +6,51 @@ import json ...@@ -6,49 +6,51 @@ import json
import uuid import uuid
from django.conf import settings from django.conf import settings
from django.test import TestCase
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from mock import patch from mock import patch
from courseware.tests.helpers import LoginEnrollmentTestCase, check_for_post_code
class TestExtraRegistrationVariables(TestCase):
class TestExtraRegistrationVariables(LoginEnrollmentTestCase):
""" """
Test that extra registration variables are properly checked according to settings Test that extra registration variables are properly checked according to settings
""" """
def setUp(self):
def _do_register_attempt(self, **extra_fields_values): super(TestExtraRegistrationVariables, self).setUp()
""" self.url = reverse('create_account')
Helper method to make the call to the do registration
"""
username = 'foo_bar' + uuid.uuid4().hex username = 'foo_bar' + uuid.uuid4().hex
fields_values = { self.url_params = {
'username': username, 'username': username,
'name': username,
'email': 'foo' + uuid.uuid4().hex + '@bar.com', 'email': 'foo' + uuid.uuid4().hex + '@bar.com',
'password': 'password', 'password': 'password',
'name': username,
'terms_of_service': 'true', 'terms_of_service': 'true',
'honor_code': 'true',
} }
fields_values = dict(fields_values.items() + extra_fields_values.items())
resp = check_for_post_code(self, 200, reverse('create_account'), fields_values)
data = json.loads(resp.content)
return data
def test_default_missing_honor(self): def test_default_missing_honor(self):
""" """
By default, the honor code must be required By default, the honor code must be required
""" """
data = self._do_register_attempt(honor_code='') self.url_params['honor_code'] = ''
self.assertEqual(data['success'], False) response = self.client.post(self.url, self.url_params)
self.assertEqual(data['value'], u'To enroll, you must follow the honor code.') self.assertEqual(response.status_code, 400)
obj = json.loads(response.content)
self.assertEqual(
obj['value'],
u'To enroll, you must follow the honor code.',
)
@patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'honor_code': 'optional'}) @patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'honor_code': 'optional'})
def test_optional_honor(self): def test_optional_honor(self):
""" """
With the honor code is made optional, should pass without extra vars With the honor code is made optional, should pass without extra vars
""" """
data = self._do_register_attempt(honor_code='') self.url_params['honor_code'] = ''
self.assertEqual(data['success'], True) response = self.client.post(self.url, self.url_params)
self.assertEqual(response.status_code, 200)
obj = json.loads(response.content)
self.assertEqual(obj['success'], True)
@patch.dict(settings.REGISTRATION_EXTRA_FIELDS, { @patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {
'level_of_education': 'hidden', 'level_of_education': 'hidden',
...@@ -63,89 +65,164 @@ class TestExtraRegistrationVariables(LoginEnrollmentTestCase): ...@@ -63,89 +65,164 @@ class TestExtraRegistrationVariables(LoginEnrollmentTestCase):
""" """
When the fields are all hidden, should pass without extra vars When the fields are all hidden, should pass without extra vars
""" """
data = self._do_register_attempt() response = self.client.post(self.url, self.url_params)
self.assertEqual(data['success'], True) self.assertEqual(response.status_code, 200)
obj = json.loads(response.content)
self.assertTrue(obj['success'])
@patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'city': 'required'}) @patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'city': 'required'})
def test_required_city_missing(self): def test_required_city_missing(self):
""" """
Should require the city if configured as 'required' but missing Should require the city if configured as 'required' but missing
""" """
data = self._do_register_attempt(honor_code='true', city='') self.url_params['city'] = ''
self.assertEqual(data['success'], False) response = self.client.post(self.url, self.url_params)
self.assertEqual(data['value'], u'A city is required') self.assertEqual(response.status_code, 400)
obj = json.loads(response.content)
self.assertEqual(
obj['value'],
u'A city is required',
)
data = self._do_register_attempt(honor_code='true', city='New York') @patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'city': 'required'})
self.assertEqual(data['success'], True) def test_required_city(self):
"""
Should require the city if configured as 'required' but missing
"""
self.url_params['city'] = 'New York'
response = self.client.post(self.url, self.url_params)
self.assertEqual(response.status_code, 200)
obj = json.loads(response.content)
self.assertTrue(obj['success'])
@patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'country': 'required'}) @patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'country': 'required'})
def test_required_country_missing(self): def test_required_country_missing(self):
""" """
Should require the country if configured as 'required' but missing Should require the country if configured as 'required' but missing
""" """
data = self._do_register_attempt(honor_code='true', country='') self.url_params['country'] = ''
self.assertEqual(data['success'], False) response = self.client.post(self.url, self.url_params)
self.assertEqual(data['value'], u'A country is required') self.assertEqual(response.status_code, 400)
obj = json.loads(response.content)
self.assertEqual(
obj['value'],
u'A country is required',
)
data = self._do_register_attempt(honor_code='true', country='New York') @patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'country': 'required'})
self.assertEqual(data['success'], True) def test_required_country(self):
self.url_params['country'] = 'New York'
response = self.client.post(self.url, self.url_params)
self.assertEqual(response.status_code, 200)
obj = json.loads(response.content)
self.assertTrue(obj['success'])
@patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'level_of_education': 'required'}) @patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'level_of_education': 'required'})
def test_required_level_of_education_missing(self): def test_required_level_of_education_missing(self):
""" """
Should require the level_of_education if configured as 'required' but missing Should require the level_of_education if configured as 'required' but missing
""" """
data = self._do_register_attempt(honor_code='true', level_of_education='') self.url_params['level_of_education'] = ''
self.assertEqual(data['success'], False) response = self.client.post(self.url, self.url_params)
self.assertEqual(data['value'], u'A level of education is required.') self.assertEqual(response.status_code, 400)
obj = json.loads(response.content)
self.assertEqual(
obj['value'],
u'A level of education is required',
)
data = self._do_register_attempt(honor_code='true', level_of_education='p') @patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'level_of_education': 'required'})
self.assertEqual(data['success'], True) def test_required_level_of_education(self):
self.url_params['level_of_education'] = 'p'
response = self.client.post(self.url, self.url_params)
self.assertEqual(response.status_code, 200)
obj = json.loads(response.content)
self.assertTrue(obj['success'])
@patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'gender': 'required'}) @patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'gender': 'required'})
def test_required_gender_missing(self): def test_required_gender_missing(self):
""" """
Should require the gender if configured as 'required' but missing Should require the gender if configured as 'required' but missing
""" """
data = self._do_register_attempt(honor_code='true', gender='') self.url_params['gender'] = ''
self.assertEqual(data['success'], False) response = self.client.post(self.url, self.url_params)
self.assertEqual(data['value'], u'Your gender is required') self.assertEqual(response.status_code, 400)
obj = json.loads(response.content)
self.assertEqual(
obj['value'],
u'Your gender is required',
)
data = self._do_register_attempt(honor_code='true', gender='m') @patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'gender': 'required'})
self.assertEqual(data['success'], True) def test_required_gender(self):
self.url_params['gender'] = 'm'
response = self.client.post(self.url, self.url_params)
self.assertEqual(response.status_code, 200)
obj = json.loads(response.content)
self.assertTrue(obj['success'])
@patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'year_of_birth': 'required'}) @patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'year_of_birth': 'required'})
def test_required_year_of_birth_missing(self): def test_required_year_of_birth_missing(self):
""" """
Should require the year_of_birth if configured as 'required' but missing Should require the year_of_birth if configured as 'required' but missing
""" """
data = self._do_register_attempt(honor_code='true', year_of_birth='') self.url_params['year_of_birth'] = ''
self.assertEqual(data['success'], False) response = self.client.post(self.url, self.url_params)
self.assertEqual(data['value'], u'Your year of birth is required') self.assertEqual(response.status_code, 400)
obj = json.loads(response.content)
self.assertEqual(
obj['value'],
u'Your year of birth is required',
)
data = self._do_register_attempt(honor_code='true', year_of_birth='1982') @patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'year_of_birth': 'required'})
self.assertEqual(data['success'], True) def test_required_year_of_birth(self):
self.url_params['year_of_birth'] = '1982'
response = self.client.post(self.url, self.url_params)
self.assertEqual(response.status_code, 200)
obj = json.loads(response.content)
self.assertTrue(obj['success'])
@patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'mailing_address': 'required'}) @patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'mailing_address': 'required'})
def test_required_mailing_address_missing(self): def test_required_mailing_address_missing(self):
""" """
Should require the mailing_address if configured as 'required' but missing Should require the mailing_address if configured as 'required' but missing
""" """
data = self._do_register_attempt(honor_code='true', mailing_address='') self.url_params['mailing_address'] = ''
self.assertEqual(data['success'], False) response = self.client.post(self.url, self.url_params)
self.assertEqual(data['value'], u'Your mailing address is required') self.assertEqual(response.status_code, 400)
obj = json.loads(response.content)
self.assertEqual(
obj['value'],
u'Your mailing address is required',
)
data = self._do_register_attempt(honor_code='true', mailing_address='my address') @patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'mailing_address': 'required'})
self.assertEqual(data['success'], True) def test_required_mailing_address(self):
self.url_params['mailing_address'] = 'my address'
response = self.client.post(self.url, self.url_params)
self.assertEqual(response.status_code, 200)
obj = json.loads(response.content)
self.assertTrue(obj['success'])
@patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'goals': 'required'}) @patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'goals': 'required'})
def test_required_goals_missing(self): def test_required_goals_missing(self):
""" """
Should require the goals if configured as 'required' but missing Should require the goals if configured as 'required' but missing
""" """
data = self._do_register_attempt(honor_code='true', goals='') self.url_params['goals'] = ''
self.assertEqual(data['success'], False) response = self.client.post(self.url, self.url_params)
self.assertEqual(data['value'], u'A description of your goals is required') self.assertEqual(response.status_code, 400)
obj = json.loads(response.content)
self.assertEqual(
obj['value'],
u'A description of your goals is required',
)
data = self._do_register_attempt(honor_code='true', goals='my goals') @patch.dict(settings.REGISTRATION_EXTRA_FIELDS, {'goals': 'required'})
self.assertEqual(data['success'], True) def test_required_goals(self):
self.url_params['goals'] = 'my goals'
response = self.client.post(self.url, self.url_params)
self.assertEqual(response.status_code, 200)
obj = json.loads(response.content)
self.assertTrue(obj['success'])
...@@ -51,15 +51,17 @@ ...@@ -51,15 +51,17 @@
}); });
$('#register-form').on('ajax:success', function(event, json, xhr) { $('#register-form').on('ajax:success', function(event, json, xhr) {
if(json.success) { var url = json.redirect_url || "${reverse('dashboard')}";
location.href="${reverse('dashboard')}"; location.href = url;
} else { });
$('#register-form').on('ajax:error', function(event, jqXHR, textStatus) {
toggleSubmitButton(true); toggleSubmitButton(true);
json = $.parseJSON(jqXHR.responseText);
$('.status.message.submission-error').addClass('is-shown').focus(); $('.status.message.submission-error').addClass('is-shown').focus();
$('.status.message.submission-error .message-copy').html(json.value).stop().css("display", "block"); $('.status.message.submission-error .message-copy').html(json.value).stop().css("display", "block");
$(".field-error").removeClass('field-error'); $(".field-error").removeClass('field-error');
$("[data-field='"+json.field+"']").addClass('field-error') $("[data-field='"+json.field+"']").addClass('field-error')
}
}); });
})(this); })(this);
......
...@@ -53,20 +53,17 @@ ...@@ -53,20 +53,17 @@
}); });
$('#register-form').on('ajax:success', function(event, json, xhr) { $('#register-form').on('ajax:success', function(event, json, xhr) {
if(json.success) { var url = json.redirect_url || "${reverse('dashboard')}";
if(json.redirect_url){ location.href = url;
location.href=json.redirect_url; });
}
else { $('#register-form').on('ajax:error', function(event, jqXHR, textStatus) {
location.href="${reverse('dashboard')}";
}
} else {
toggleSubmitButton(true); toggleSubmitButton(true);
json = $.parseJSON(jqXHR.responseText);
$('.status.message.submission-error').addClass('is-shown').focus(); $('.status.message.submission-error').addClass('is-shown').focus();
$('.status.message.submission-error .message-copy').html(json.value).stop().css("display", "block"); $('.status.message.submission-error .message-copy').html(json.value).stop().css("display", "block");
$(".field-error").removeClass('field-error'); $(".field-error").removeClass('field-error');
$("[data-field='"+json.field+"']").addClass('field-error') $("[data-field='"+json.field+"']").addClass('field-error')
}
}); });
})(this); })(this);
......
...@@ -152,13 +152,13 @@ ...@@ -152,13 +152,13 @@
<script type="text/javascript"> <script type="text/javascript">
(function() { (function() {
$(document).delegate('#register_form', 'ajax:success', function(data, json, xhr) { $(document).delegate('#register_form', 'ajax:success', function(data, json, xhr) {
if(json.success) {
location.href="${reverse('dashboard')}"; location.href="${reverse('dashboard')}";
} else { });
$(document).delegate('#register_form', 'ajax:error', function(event, jqXHR, textStatus) {
json = $.parseJSON(jqXHR.responseText);
$(".field-error").removeClass('field-error'); $(".field-error").removeClass('field-error');
$('#register_error').html(json.value).stop().css("display", "block"); $('#register_error').html(json.value).stop().css("display", "block");
$("[data-field='"+json.field+"']").addClass('field-error') $("[data-field='"+json.field+"']").addClass('field-error')
}
}); });
// removing close link's default behavior // removing close link's default behavior
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment