def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): """ The restful handler for xblock requests. DELETE json: delete this xblock instance from the course. Supports query parameters "recurse" to delete all children and "all_versions" to delete from all (mongo) versions. GET json: returns representation of the xblock (locator id, data, and metadata). PUT or POST json: if xblock location is specified, update the xblock instance. The json payload can contain these fields, all optional: :data: the new value for the data. :children: the locator ids of children for this xblock. :metadata: new values for the metadata fields. Any whose values are None will be deleted not set to None! Absent ones will be left alone. :nullout: which metadata fields to set to None The JSON representation on the updated xblock (minus children) is returned. if xblock location is not specified, create a new xblock instance. The json playload can contain these fields: :parent_locator: parent for new xblock, required :category: type of xblock, required :display_name: name for new xblock, optional :boilerplate: template name for populating fields, optional The locator (and old-style id) for the created xblock (minus children) is returned. """ if course_id is not None: location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, usage_id=block) if not has_access(request.user, location): raise PermissionDenied() old_location = loc_mapper().translate_locator_to_location(location) if request.method == 'GET': rsp = _get_module_info(location) return JsonResponse(rsp) elif request.method == 'DELETE': delete_children = str_to_bool(request.REQUEST.get('recurse', 'False')) delete_all_versions = str_to_bool(request.REQUEST.get('all_versions', 'False')) return _delete_item_at_location(old_location, delete_children, delete_all_versions) else: # Since we have a course_id, we are updating an existing xblock. return _save_item( location, old_location, data=request.json.get('data'), children=request.json.get('children'), metadata=request.json.get('metadata'), nullout=request.json.get('nullout') ) elif request.method in ('PUT', 'POST'): return _create_item(request) else: return HttpResponseBadRequest( "Only instance creation is supported without a course_id.", content_type="text/plain" )
def test_str_to_bool_false(self): self.assertFalse(str_to_bool('Tru')) self.assertFalse(str_to_bool('False')) self.assertFalse(str_to_bool('false')) self.assertFalse(str_to_bool('')) self.assertFalse(str_to_bool(None)) self.assertFalse(str_to_bool('anything'))
def test_raises_error(val): with self.assertRaises(AttributeError): self.assertFalse(str_to_bool(val))
def test_str_to_bool_true(self): self.assertTrue(str_to_bool('True')) self.assertTrue(str_to_bool('true')) self.assertTrue(str_to_bool('trUe'))
def xblock_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None): """ The restful handler for xblock requests. DELETE json: delete this xblock instance from the course. Supports query parameters "recurse" to delete all children and "all_versions" to delete from all (mongo) versions. GET json: returns representation of the xblock (locator id, data, and metadata). if ?fields=graderType, it returns the graderType for the unit instead of the above. html: returns HTML for rendering the xblock (which includes both the "preview" view and the "editor" view) PUT or POST json: if xblock locator is specified, update the xblock instance. The json payload can contain these fields, all optional: :data: the new value for the data. :children: the locator ids of children for this xblock. :metadata: new values for the metadata fields. Any whose values are None will be deleted not set to None! Absent ones will be left alone. :nullout: which metadata fields to set to None :graderType: change how this unit is graded :publish: can be one of three values, 'make_public, 'make_private', or 'create_draft' The JSON representation on the updated xblock (minus children) is returned. if xblock locator is not specified, create a new xblock instance, either by duplicating an existing xblock, or creating an entirely new one. The json playload can contain these fields: :parent_locator: parent for new xblock, required for both duplicate and create new instance :duplicate_source_locator: if present, use this as the source for creating a duplicate copy :category: type of xblock, required if duplicate_source_locator is not present. :display_name: name for new xblock, optional :boilerplate: template name for populating fields, optional and only used if duplicate_source_locator is not present The locator (and old-style id) for the created xblock (minus children) is returned. """ if package_id is not None: locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block) if not has_course_access(request.user, locator): raise PermissionDenied() old_location = loc_mapper().translate_locator_to_location(locator) if request.method == 'GET': accept_header = request.META.get('HTTP_ACCEPT', 'application/json') if 'application/json' in accept_header: fields = request.REQUEST.get('fields', '').split(',') if 'graderType' in fields: # right now can't combine output of this w/ output of _get_module_info, but worthy goal return JsonResponse( CourseGradingModel.get_section_grader_type(locator)) # TODO: pass fields to _get_module_info and only return those rsp = _get_module_info(locator) return JsonResponse(rsp) else: return HttpResponse(status=406) elif request.method == 'DELETE': delete_children = str_to_bool( request.REQUEST.get('recurse', 'False')) delete_all_versions = str_to_bool( request.REQUEST.get('all_versions', 'False')) # delete item from loc_mapper and cache loc_mapper().delete_item_mapping(locator, old_location) return _delete_item_at_location(old_location, delete_children, delete_all_versions, request.user) else: # Since we have a package_id, we are updating an existing xblock. if block == 'handouts' and old_location is None: # update handouts location in loc_mapper course_location = loc_mapper().translate_locator_to_location( locator, get_course=True) old_location = course_location.replace(category='course_info', name=block) locator = loc_mapper().translate_location( course_location.course_id, old_location) return _save_item( request, locator, old_location, data=request.json.get('data'), children=request.json.get('children'), metadata=request.json.get('metadata'), nullout=request.json.get('nullout'), grader_type=request.json.get('graderType'), publish=request.json.get('publish'), ) elif request.method in ('PUT', 'POST'): if 'duplicate_source_locator' in request.json: parent_locator = BlockUsageLocator(request.json['parent_locator']) duplicate_source_locator = BlockUsageLocator( request.json['duplicate_source_locator']) # _duplicate_item is dealing with locations to facilitate the recursive call for # duplicating children. parent_location = loc_mapper().translate_locator_to_location( parent_locator) duplicate_source_location = loc_mapper( ).translate_locator_to_location(duplicate_source_locator) dest_location = _duplicate_item( parent_location, duplicate_source_location, request.json.get('display_name'), request.user, ) course_location = loc_mapper().translate_locator_to_location( BlockUsageLocator(parent_locator), get_course=True) dest_locator = loc_mapper().translate_location( course_location.course_id, dest_location, False, True) return JsonResponse({"locator": unicode(dest_locator)}) else: return _create_item(request) else: return HttpResponseBadRequest( "Only instance creation is supported without a package_id.", content_type="text/plain")
def xblock_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None): """ The restful handler for xblock requests. DELETE json: delete this xblock instance from the course. Supports query parameters "recurse" to delete all children and "all_versions" to delete from all (mongo) versions. GET json: returns representation of the xblock (locator id, data, and metadata). if ?fields=graderType, it returns the graderType for the unit instead of the above. html: returns HTML for rendering the xblock (which includes both the "preview" view and the "editor" view) PUT or POST json: if xblock locator is specified, update the xblock instance. The json payload can contain these fields, all optional: :data: the new value for the data. :children: the locator ids of children for this xblock. :metadata: new values for the metadata fields. Any whose values are None will be deleted not set to None! Absent ones will be left alone. :nullout: which metadata fields to set to None :graderType: change how this unit is graded :publish: can be one of three values, 'make_public, 'make_private', or 'create_draft' The JSON representation on the updated xblock (minus children) is returned. if xblock locator is not specified, create a new xblock instance, either by duplicating an existing xblock, or creating an entirely new one. The json playload can contain these fields: :parent_locator: parent for new xblock, required for both duplicate and create new instance :duplicate_source_locator: if present, use this as the source for creating a duplicate copy :category: type of xblock, required if duplicate_source_locator is not present. :display_name: name for new xblock, optional :boilerplate: template name for populating fields, optional and only used if duplicate_source_locator is not present The locator (and old-style id) for the created xblock (minus children) is returned. """ if package_id is not None: locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block) if not has_course_access(request.user, locator): raise PermissionDenied() old_location = loc_mapper().translate_locator_to_location(locator) if request.method == 'GET': accept_header = request.META.get('HTTP_ACCEPT', 'application/json') if 'application/json' in accept_header: fields = request.REQUEST.get('fields', '').split(',') if 'graderType' in fields: # right now can't combine output of this w/ output of _get_module_info, but worthy goal return JsonResponse(CourseGradingModel.get_section_grader_type(locator)) # TODO: pass fields to _get_module_info and only return those rsp = _get_module_info(locator) return JsonResponse(rsp) else: return HttpResponse(status=406) elif request.method == 'DELETE': delete_children = str_to_bool(request.REQUEST.get('recurse', 'False')) delete_all_versions = str_to_bool(request.REQUEST.get('all_versions', 'False')) return _delete_item_at_location(old_location, delete_children, delete_all_versions, request.user) else: # Since we have a package_id, we are updating an existing xblock. if block == 'handouts' and old_location is None: # update handouts location in loc_mapper course_location = loc_mapper().translate_locator_to_location(locator, get_course=True) old_location = course_location.replace(category='course_info', name=block) locator = loc_mapper().translate_location(course_location.course_id, old_location) return _save_item( request, locator, old_location, data=request.json.get('data'), children=request.json.get('children'), metadata=request.json.get('metadata'), nullout=request.json.get('nullout'), grader_type=request.json.get('graderType'), publish=request.json.get('publish'), ) elif request.method in ('PUT', 'POST'): if 'duplicate_source_locator' in request.json: parent_locator = BlockUsageLocator(request.json['parent_locator']) duplicate_source_locator = BlockUsageLocator(request.json['duplicate_source_locator']) # _duplicate_item is dealing with locations to facilitate the recursive call for # duplicating children. parent_location = loc_mapper().translate_locator_to_location(parent_locator) duplicate_source_location = loc_mapper().translate_locator_to_location(duplicate_source_locator) dest_location = _duplicate_item( parent_location, duplicate_source_location, request.json.get('display_name'), request.user, ) course_location = loc_mapper().translate_locator_to_location(BlockUsageLocator(parent_locator), get_course=True) dest_locator = loc_mapper().translate_location(course_location.course_id, dest_location, False, True) return JsonResponse({"locator": unicode(dest_locator)}) else: return _create_item(request) else: return HttpResponseBadRequest( "Only instance creation is supported without a package_id.", content_type="text/plain" )
def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): """ The restful handler for xblock requests. DELETE json: delete this xblock instance from the course. Supports query parameters "recurse" to delete all children and "all_versions" to delete from all (mongo) versions. GET json: returns representation of the xblock (locator id, data, and metadata). if ?fields=graderType, it returns the graderType for the unit instead of the above. html: returns HTML for rendering the xblock (which includes both the "preview" view and the "editor" view) PUT or POST json: if xblock locator is specified, update the xblock instance. The json payload can contain these fields, all optional: :data: the new value for the data. :children: the locator ids of children for this xblock. :metadata: new values for the metadata fields. Any whose values are None will be deleted not set to None! Absent ones will be left alone. :nullout: which metadata fields to set to None :graderType: change how this unit is graded :publish: can be one of three values, 'make_public, 'make_private', or 'create_draft' The JSON representation on the updated xblock (minus children) is returned. if xblock locator is not specified, create a new xblock instance. The json playload can contain these fields: :parent_locator: parent for new xblock, required :category: type of xblock, required :display_name: name for new xblock, optional :boilerplate: template name for populating fields, optional The locator (and old-style id) for the created xblock (minus children) is returned. """ if course_id is not None: locator = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, usage_id=block) if not has_access(request.user, locator): raise PermissionDenied() old_location = loc_mapper().translate_locator_to_location(locator) if request.method == 'GET': if 'application/json' in request.META.get('HTTP_ACCEPT', 'application/json'): fields = request.REQUEST.get('fields', '').split(',') if 'graderType' in fields: # right now can't combine output of this w/ output of _get_module_info, but worthy goal return JsonResponse(CourseGradingModel.get_section_grader_type(locator)) # TODO: pass fields to _get_module_info and only return those rsp = _get_module_info(locator) return JsonResponse(rsp) else: component = modulestore().get_item(old_location) # Wrap the generated fragment in the xmodule_editor div so that the javascript # can bind to it correctly component.runtime.wrappers.append(partial(wrap_xblock, handler_prefix)) try: content = component.render('studio_view').content # catch exceptions indiscriminately, since after this point they escape the # dungeon and surface as uneditable, unsaveable, and undeletable # component-goblins. except Exception as exc: # pylint: disable=W0703 log.debug("Unable to render studio_view for %r", component, exc_info=True) content = render_to_string('html_error.html', {'message': str(exc)}) return render_to_response('component.html', { 'preview': get_preview_html(request, component), 'editor': content }) elif request.method == 'DELETE': delete_children = str_to_bool(request.REQUEST.get('recurse', 'False')) delete_all_versions = str_to_bool(request.REQUEST.get('all_versions', 'False')) return _delete_item_at_location(old_location, delete_children, delete_all_versions) else: # Since we have a course_id, we are updating an existing xblock. return _save_item( request, locator, old_location, data=request.json.get('data'), children=request.json.get('children'), metadata=request.json.get('metadata'), nullout=request.json.get('nullout'), grader_type=request.json.get('graderType'), publish=request.json.get('publish'), ) elif request.method in ('PUT', 'POST'): return _create_item(request) else: return HttpResponseBadRequest( "Only instance creation is supported without a course_id.", content_type="text/plain" )
def xblock_handler(request, usage_key_string): """ The restful handler for xblock requests. DELETE json: delete this xblock instance from the course. Supports query parameters "recurse" to delete all children and "all_versions" to delete from all (mongo) versions. GET json: returns representation of the xblock (locator id, data, and metadata). if ?fields=graderType, it returns the graderType for the unit instead of the above. html: returns HTML for rendering the xblock (which includes both the "preview" view and the "editor" view) PUT or POST json: if xblock locator is specified, update the xblock instance. The json payload can contain these fields, all optional: :data: the new value for the data. :children: the unicode representation of the UsageKeys of children for this xblock. :metadata: new values for the metadata fields. Any whose values are None will be deleted not set to None! Absent ones will be left alone. :nullout: which metadata fields to set to None :graderType: change how this unit is graded :publish: can be one of three values, 'make_public, 'make_private', or 'create_draft' The JSON representation on the updated xblock (minus children) is returned. if usage_key_string is not specified, create a new xblock instance, either by duplicating an existing xblock, or creating an entirely new one. The json playload can contain these fields: :parent_locator: parent for new xblock, required for both duplicate and create new instance :duplicate_source_locator: if present, use this as the source for creating a duplicate copy :category: type of xblock, required if duplicate_source_locator is not present. :display_name: name for new xblock, optional :boilerplate: template name for populating fields, optional and only used if duplicate_source_locator is not present The locator (unicode representation of a UsageKey) for the created xblock (minus children) is returned. """ if usage_key_string: usage_key = UsageKey.from_string(usage_key_string) if not has_course_access(request.user, usage_key.course_key): raise PermissionDenied() if request.method == 'GET': accept_header = request.META.get('HTTP_ACCEPT', 'application/json') if 'application/json' in accept_header: fields = request.REQUEST.get('fields', '').split(',') if 'graderType' in fields: # right now can't combine output of this w/ output of _get_module_info, but worthy goal return JsonResponse( CourseGradingModel.get_section_grader_type(usage_key)) # TODO: pass fields to _get_module_info and only return those rsp = _get_module_info(usage_key) return JsonResponse(rsp) else: return HttpResponse(status=406) elif request.method == 'DELETE': delete_children = str_to_bool( request.REQUEST.get('recurse', 'False')) delete_all_versions = str_to_bool( request.REQUEST.get('all_versions', 'False')) return _delete_item_at_location(usage_key, delete_children, delete_all_versions, request.user) else: # Since we have a usage_key, we are updating an existing xblock. return _save_item( request, usage_key, data=request.json.get('data'), children=request.json.get('children'), metadata=request.json.get('metadata'), nullout=request.json.get('nullout'), grader_type=request.json.get('graderType'), publish=request.json.get('publish'), ) elif request.method in ('PUT', 'POST'): if 'duplicate_source_locator' in request.json: parent_usage_key = UsageKey.from_string( request.json['parent_locator']) duplicate_source_usage_key = UsageKey.from_string( request.json['duplicate_source_locator']) dest_usage_key = _duplicate_item( parent_usage_key, duplicate_source_usage_key, request.json.get('display_name'), request.user, ) return JsonResponse({"locator": unicode(dest_usage_key)}) else: return _create_item(request) else: return HttpResponseBadRequest( "Only instance creation is supported without a usage key.", content_type="text/plain")
def xblock_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None): """ The restful handler for xblock requests. DELETE json: delete this xblock instance from the course. Supports query parameters "recurse" to delete all children and "all_versions" to delete from all (mongo) versions. GET json: returns representation of the xblock (locator id, data, and metadata). if ?fields=graderType, it returns the graderType for the unit instead of the above. html: returns HTML for rendering the xblock (which includes both the "preview" view and the "editor" view) PUT or POST json: if xblock locator is specified, update the xblock instance. The json payload can contain these fields, all optional: :data: the new value for the data. :children: the locator ids of children for this xblock. :metadata: new values for the metadata fields. Any whose values are None will be deleted not set to None! Absent ones will be left alone. :nullout: which metadata fields to set to None :graderType: change how this unit is graded :publish: can be one of three values, 'make_public, 'make_private', or 'create_draft' The JSON representation on the updated xblock (minus children) is returned. if xblock locator is not specified, create a new xblock instance, either by duplicating an existing xblock, or creating an entirely new one. The json playload can contain these fields: :parent_locator: parent for new xblock, required for both duplicate and create new instance :duplicate_source_locator: if present, use this as the source for creating a duplicate copy :category: type of xblock, required if duplicate_source_locator is not present. :display_name: name for new xblock, optional :boilerplate: template name for populating fields, optional and only used if duplicate_source_locator is not present The locator (and old-style id) for the created xblock (minus children) is returned. """ if package_id is not None: locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block) if not has_course_access(request.user, locator): raise PermissionDenied() old_location = loc_mapper().translate_locator_to_location(locator) if request.method == 'GET': if 'application/json' in request.META.get('HTTP_ACCEPT', 'application/json'): fields = request.REQUEST.get('fields', '').split(',') if 'graderType' in fields: # right now can't combine output of this w/ output of _get_module_info, but worthy goal return JsonResponse(CourseGradingModel.get_section_grader_type(locator)) # TODO: pass fields to _get_module_info and only return those rsp = _get_module_info(locator) return JsonResponse(rsp) else: component = modulestore().get_item(old_location) # Wrap the generated fragment in the xmodule_editor div so that the javascript # can bind to it correctly component.runtime.wrappers.append(partial(wrap_xblock, handler_prefix)) try: content = component.render('studio_view').content # catch exceptions indiscriminately, since after this point they escape the # dungeon and surface as uneditable, unsaveable, and undeletable # component-goblins. except Exception as exc: # pylint: disable=W0703 log.debug("Unable to render studio_view for %r", component, exc_info=True) content = render_to_string('html_error.html', {'message': str(exc)}) return render_to_response('component.html', { 'preview': get_preview_html(request, component), 'editor': content }) elif request.method == 'DELETE': delete_children = str_to_bool(request.REQUEST.get('recurse', 'False')) delete_all_versions = str_to_bool(request.REQUEST.get('all_versions', 'False')) return _delete_item_at_location(old_location, delete_children, delete_all_versions) else: # Since we have a package_id, we are updating an existing xblock. return _save_item( request, locator, old_location, data=request.json.get('data'), children=request.json.get('children'), metadata=request.json.get('metadata'), nullout=request.json.get('nullout'), grader_type=request.json.get('graderType'), publish=request.json.get('publish'), ) elif request.method in ('PUT', 'POST'): if 'duplicate_source_locator' in request.json: parent_locator = BlockUsageLocator(request.json['parent_locator']) duplicate_source_locator = BlockUsageLocator(request.json['duplicate_source_locator']) # _duplicate_item is dealing with locations to facilitate the recursive call for # duplicating children. parent_location = loc_mapper().translate_locator_to_location(parent_locator) duplicate_source_location = loc_mapper().translate_locator_to_location(duplicate_source_locator) dest_location = _duplicate_item( parent_location, duplicate_source_location, request.json.get('display_name') ) course_location = loc_mapper().translate_locator_to_location(BlockUsageLocator(parent_locator), get_course=True) dest_locator = loc_mapper().translate_location(course_location.course_id, dest_location, False, True) return JsonResponse({"locator": unicode(dest_locator)}) else: return _create_item(request) else: return HttpResponseBadRequest( "Only instance creation is supported without a package_id.", content_type="text/plain" )