Commit d4e82424 by Braden MacDonald Committed by E. Kolpakov

Friendly error message when library key is invalid

parent d25673ec
...@@ -426,8 +426,9 @@ def _save_xblock(user, xblock, data=None, children_strings=None, metadata=None, ...@@ -426,8 +426,9 @@ def _save_xblock(user, xblock, data=None, children_strings=None, metadata=None,
else: else:
try: try:
value = field.from_json(value) value = field.from_json(value)
except ValueError: except ValueError as verr:
return JsonResponse({"error": "Invalid data"}, 400) reason = _("Invalid data ({details})").format(details=verr.message) if verr.message else _("Invalid data")
return JsonResponse({"error": reason}, 400)
field.write_to(xblock, value) field.write_to(xblock, value)
# update the xblock and call any xblock callbacks # update the xblock and call any xblock callbacks
......
...@@ -894,6 +894,29 @@ class TestEditItem(ItemTest): ...@@ -894,6 +894,29 @@ class TestEditItem(ItemTest):
self._verify_published_with_draft(unit_usage_key) self._verify_published_with_draft(unit_usage_key)
self._verify_published_with_draft(html_usage_key) self._verify_published_with_draft(html_usage_key)
def test_field_value_errors(self):
"""
Test that if the user's input causes a ValueError on an XBlock field,
we provide a friendly error message back to the user.
"""
response = self.create_xblock(parent_usage_key=self.seq_usage_key, category='video')
video_usage_key = self.response_usage_key(response)
update_url = reverse_usage_url('xblock_handler', video_usage_key)
response = self.client.ajax_post(
update_url,
data={
'id': unicode(video_usage_key),
'metadata': {
'saved_video_position': "Not a valid relative time",
},
}
)
self.assertEqual(response.status_code, 400)
parsed = json.loads(response.content)
self.assertIn("error", parsed)
self.assertIn("Incorrect RelativeTime value", parsed["error"]) # See xmodule/fields.py
class TestEditSplitModule(ItemTest): class TestEditSplitModule(ItemTest):
""" """
......
""" """
LibraryContent: The XBlock used to include blocks from a library in a course. LibraryContent: The XBlock used to include blocks from a library in a course.
""" """
from bson.objectid import ObjectId from bson.objectid import ObjectId, InvalidId
from collections import namedtuple from collections import namedtuple
from copy import copy from copy import copy
import hashlib import hashlib
from .mako_module import MakoModuleDescriptor from .mako_module import MakoModuleDescriptor
from opaque_keys import InvalidKeyError
from opaque_keys.edx.locator import LibraryLocator from opaque_keys.edx.locator import LibraryLocator
import random import random
from webob import Response from webob import Response
...@@ -46,7 +47,10 @@ class LibraryVersionReference(namedtuple("LibraryVersionReference", "library_id ...@@ -46,7 +47,10 @@ class LibraryVersionReference(namedtuple("LibraryVersionReference", "library_id
version = library_id.version_guid version = library_id.version_guid
library_id = library_id.for_version(None) library_id = library_id.for_version(None)
if version and not isinstance(version, ObjectId): if version and not isinstance(version, ObjectId):
version = ObjectId(version) try:
version = ObjectId(version)
except InvalidId:
raise ValueError(version)
return super(LibraryVersionReference, cls).__new__(cls, library_id, version) return super(LibraryVersionReference, cls).__new__(cls, library_id, version)
@staticmethod @staticmethod
...@@ -86,7 +90,14 @@ class LibraryList(List): ...@@ -86,7 +90,14 @@ class LibraryList(List):
val = val.strip(' []') val = val.strip(' []')
parts = val.rsplit(',', 1) parts = val.rsplit(',', 1)
val = [parts[0], parts[1] if len(parts) > 1 else None] val = [parts[0], parts[1] if len(parts) > 1 else None]
return LibraryVersionReference.from_json(val) try:
return LibraryVersionReference.from_json(val)
except InvalidKeyError:
try:
friendly_val = val[0] # Just get the library key part, not the version
except IndexError:
friendly_val = unicode(val)
raise ValueError(_('"{value}" is not a valid library ID.').format(value=friendly_val))
return [parse(v) for v in values] return [parse(v) for v in values]
def to_json(self, values): def to_json(self, values):
......
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