Commit 9ef04940 by Greg Price

Return field detail with registration API errors

Also, make registration API CSRF exempt
parent 0646b5f5
...@@ -58,7 +58,22 @@ var edx = edx || {}; ...@@ -58,7 +58,22 @@ var edx = edx || {};
saveSuccess: function() { saveSuccess: function() {
this.trigger('auth-complete'); this.trigger('auth-complete');
} },
saveError: function( error ) {
this.errors = _.flatten(
_.map(
JSON.parse(error.responseText),
function(error_list) {
return _.map(
error_list,
function(error) { return "<li>" + error.user_message + "</li>"; }
);
}
)
);
this.setErrors();
this.toggleDisableButton(false);
}
}); });
})(jQuery, _, gettext); })(jQuery, _, gettext);
...@@ -1368,11 +1368,19 @@ class RegistrationViewTest(ApiTestCase): ...@@ -1368,11 +1368,19 @@ class RegistrationViewTest(ApiTestCase):
"honor_code": "true", "honor_code": "true",
}) })
self.assertEqual(response.status_code, 409) self.assertEqual(response.status_code, 409)
response_json = json.loads(response.content)
self.assertEqual( self.assertEqual(
response.content, response_json,
"It looks like {} belongs to an existing account. Try again with a different email address.".format( {
"email": [{
"user_message": (
"It looks like {} belongs to an existing account. "
"Try again with a different email address."
).format(
self.EMAIL self.EMAIL
) )
}]
}
) )
def test_register_duplicate_username(self): def test_register_duplicate_username(self):
...@@ -1395,11 +1403,19 @@ class RegistrationViewTest(ApiTestCase): ...@@ -1395,11 +1403,19 @@ class RegistrationViewTest(ApiTestCase):
"honor_code": "true", "honor_code": "true",
}) })
self.assertEqual(response.status_code, 409) self.assertEqual(response.status_code, 409)
response_json = json.loads(response.content)
self.assertEqual( self.assertEqual(
response.content, response_json,
"It looks like {} belongs to an existing account. Try again with a different username.".format( {
"username": [{
"user_message": (
"It looks like {} belongs to an existing account. "
"Try again with a different username."
).format(
self.USERNAME self.USERNAME
) )
}]
}
) )
def test_register_duplicate_username_and_email(self): def test_register_duplicate_username_and_email(self):
...@@ -1422,11 +1438,46 @@ class RegistrationViewTest(ApiTestCase): ...@@ -1422,11 +1438,46 @@ class RegistrationViewTest(ApiTestCase):
"honor_code": "true", "honor_code": "true",
}) })
self.assertEqual(response.status_code, 409) self.assertEqual(response.status_code, 409)
response_json = json.loads(response.content)
self.assertEqual( self.assertEqual(
response.content, response_json,
"It looks like {} and {} belong to an existing account. Try again with a different email address and username.".format( {
self.EMAIL, self.USERNAME "username": [{
"user_message": (
"It looks like {} belongs to an existing account. "
"Try again with a different username."
).format(
self.USERNAME
) )
}],
"email": [{
"user_message": (
"It looks like {} belongs to an existing account. "
"Try again with a different email address."
).format(
self.EMAIL
)
}]
}
)
def test_missing_fields(self):
response = self.client.post(
self.url,
{
"email": self.EMAIL,
"name": self.NAME,
"honor_code": "true",
}
)
self.assertEqual(response.status_code, 400)
response_json = json.loads(response.content)
self.assertEqual(
response_json,
{
"username": [{"user_message": "Username must be minimum of two characters long"}],
"password": [{"user_message": "A valid password is required"}],
}
) )
def _assert_reg_field(self, extra_fields_setting, expected_field): def _assert_reg_field(self, extra_fields_setting, expected_field):
......
...@@ -8,10 +8,10 @@ from django.conf import settings ...@@ -8,10 +8,10 @@ from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.http import HttpResponse from django.http import HttpResponse
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core.exceptions import ImproperlyConfigured, ValidationError from django.core.exceptions import ImproperlyConfigured, NON_FIELD_ERRORS, ValidationError
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views.decorators.csrf import ensure_csrf_cookie, csrf_protect from django.views.decorators.csrf import ensure_csrf_cookie, csrf_protect, csrf_exempt
from opaque_keys.edx import locator from opaque_keys.edx import locator
from rest_framework import authentication from rest_framework import authentication
from rest_framework import filters from rest_framework import filters
...@@ -227,8 +227,7 @@ class RegistrationView(APIView): ...@@ -227,8 +227,7 @@ class RegistrationView(APIView):
return HttpResponse(form_desc.to_json(), content_type="application/json") return HttpResponse(form_desc.to_json(), content_type="application/json")
@method_decorator(require_post_params(DEFAULT_FIELDS)) @method_decorator(csrf_exempt)
@method_decorator(csrf_protect)
def post(self, request): def post(self, request):
"""Create the user's account. """Create the user's account.
...@@ -254,31 +253,23 @@ class RegistrationView(APIView): ...@@ -254,31 +253,23 @@ class RegistrationView(APIView):
# Handle duplicate email/username # Handle duplicate email/username
conflicts = account_api.check_account_exists(email=email, username=username) conflicts = account_api.check_account_exists(email=email, username=username)
if conflicts: if conflicts:
if all(conflict in conflicts for conflict in ['email', 'username']): conflict_messages = {
# Translators: This message is shown to users who attempt to create a new
# account using both an email address and a username associated with an
# existing account.
error_msg = _(
u"It looks like {email_address} and {username} belong to an existing account. Try again with a different email address and username."
).format(email_address=email, username=username)
elif 'email' in conflicts:
# Translators: This message is shown to users who attempt to create a new # Translators: This message is shown to users who attempt to create a new
# account using an email address associated with an existing account. # account using an email address associated with an existing account.
error_msg = _( "email": _(
u"It looks like {email_address} belongs to an existing account. Try again with a different email address." u"It looks like {email_address} belongs to an existing account. Try again with a different email address."
).format(email_address=email) ).format(email_address=email),
else:
# Translators: This message is shown to users who attempt to create a new # Translators: This message is shown to users who attempt to create a new
# account using a username associated with an existing account. # account using a username associated with an existing account.
error_msg = _( "username": _(
u"It looks like {username} belongs to an existing account. Try again with a different username." u"It looks like {username} belongs to an existing account. Try again with a different username."
).format(username=username) ).format(username=username),
}
return HttpResponse( errors = {
status=409, field: [{"user_message": conflict_messages[field]}]
content=error_msg, for field in conflicts
content_type="text/plain" }
) return JsonResponse(errors, status=409)
# Backwards compatibility: the student view expects both # Backwards compatibility: the student view expects both
# terms of service and honor code values. Since we're combining # terms of service and honor code values. Since we're combining
...@@ -293,12 +284,14 @@ class RegistrationView(APIView): ...@@ -293,12 +284,14 @@ class RegistrationView(APIView):
try: try:
create_account_with_params(request, data) create_account_with_params(request, data)
except ValidationError as err: except ValidationError as err:
error_list = next(err.message_dict.itervalues()) # Should only get non-field errors from this function
return HttpResponse( assert NON_FIELD_ERRORS not in err.message_dict
status=400, # Only return first error for each field
content=error_list[0], errors = {
content_type="text/plain" field: [{"user_message": error} for error in error_list]
) for field, error_list in err.message_dict.items()
}
return JsonResponse(errors, status=400)
response = JsonResponse({"success": True}) response = JsonResponse({"success": True})
set_marketing_cookie(request, response) set_marketing_cookie(request, response)
......
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