diff --git a/cms/djangoapps/contentstore/views.py b/cms/djangoapps/contentstore/views.py index 34b97a1179..1df2c44ff7 100644 --- a/cms/djangoapps/contentstore/views.py +++ b/cms/djangoapps/contentstore/views.py @@ -383,6 +383,14 @@ def get_module_previews(request, descriptor): return preview_html +@login_required +@expect_json +def delete_item(request): + item_location = request.POST['id'] + modulestore().delete_item(item_location) + return HttpResponse() + + @login_required @expect_json def save_item(request): diff --git a/cms/static/coffee/src/views/module_edit.coffee b/cms/static/coffee/src/views/module_edit.coffee index b41cf10851..2326756dc8 100644 --- a/cms/static/coffee/src/views/module_edit.coffee +++ b/cms/static/coffee/src/views/module_edit.coffee @@ -6,10 +6,10 @@ class CMS.Views.ModuleEdit extends Backbone.View "click .component-editor .cancel-button": 'clickCancelButton' "click .component-editor .save-button": 'clickSaveButton' "click .component-actions .edit-button": 'clickEditButton' - + "click .component-actions .delete-button": 'onDelete' initialize: -> - @module = @options.module + @onDelete = @options.onDelete @render() $component_editor: => @$el.find('.component-editor') diff --git a/cms/static/coffee/src/views/unit.coffee b/cms/static/coffee/src/views/unit.coffee index df5e714d3a..1180b17471 100644 --- a/cms/static/coffee/src/views/unit.coffee +++ b/cms/static/coffee/src/views/unit.coffee @@ -18,9 +18,10 @@ class CMS.Views.UnitEdit extends Backbone.View update: (event, ui) => @saveOrder() ) - @$('.component').each((idx, element) -> + @$('.component').each((idx, element) => new CMS.Views.ModuleEdit( el: element, + onDelete: @deleteComponent, model: new CMS.Models.Module( id: $(element).data('id'), ) @@ -70,3 +71,13 @@ class CMS.Views.UnitEdit extends Backbone.View @model.save( children: @components() ) + + deleteComponent: (event) => + $component = $(event.currentTarget).parents('.component') + $.post('/delete_item', { + id: $component.data('id') + }, => + $component.remove() + @saveOrder() + ) + diff --git a/cms/templates/component.html b/cms/templates/component.html index 76a121fec6..f0d266e2e1 100644 --- a/cms/templates/component.html +++ b/cms/templates/component.html @@ -1,7 +1,7 @@ ${preview}
Edit - Delete + Delete
diff --git a/cms/urls.py b/cms/urls.py index e35c756c74..7cbb912b06 100644 --- a/cms/urls.py +++ b/cms/urls.py @@ -14,6 +14,7 @@ urlpatterns = ('', url(r'^delete/(?P.*?)$', 'contentstore.views.delete_unit', name='delete_unit'), url(r'^preview_component/(?P.*?)$', 'contentstore.views.preview_component', name='preview_component'), url(r'^save_item$', 'contentstore.views.save_item', name='save_item'), + url(r'^delete_item$', 'contentstore.views.delete_item', name='delete_item'), url(r'^clone_item$', 'contentstore.views.clone_item', name='clone_item'), url(r'^(?P[^/]+)/(?P[^/]+)/course/(?P[^/]+)$', 'contentstore.views.course_index', name='course_index'), diff --git a/common/lib/xmodule/xmodule/modulestore/__init__.py b/common/lib/xmodule/xmodule/modulestore/__init__.py index fa8cf8d3d7..880159d8ed 100644 --- a/common/lib/xmodule/xmodule/modulestore/__init__.py +++ b/common/lib/xmodule/xmodule/modulestore/__init__.py @@ -332,6 +332,14 @@ class ModuleStore(object): """ raise NotImplementedError + def delete_item(self, location): + """ + Delete an item from this modulestore + + location: Something that can be passed to Location + """ + raise NotImplementedError + def get_courses(self): ''' Returns a list containing the top level XModuleDescriptors of the courses diff --git a/common/lib/xmodule/xmodule/modulestore/mongo.py b/common/lib/xmodule/xmodule/modulestore/mongo.py index baa4e7870c..21e28e9d67 100644 --- a/common/lib/xmodule/xmodule/modulestore/mongo.py +++ b/common/lib/xmodule/xmodule/modulestore/mongo.py @@ -309,6 +309,14 @@ class MongoModuleStore(ModuleStoreBase): self._update_single_item(location, {'metadata': metadata}) + def delete_item(self, location): + """ + Delete an item from this modulestore + + location: Something that can be passed to Location + """ + self.collection.remove({'_id': Location(location).dict()}) + def get_parent_locations(self, location): '''Find all locations that are the parents of this location. Needed for path_to_location(). diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index 43b7cec3af..fd209ee26f 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -13,6 +13,7 @@ from xmodule.modulestore import Location from xmodule.timeparse import parse_time from xmodule.contentstore.content import StaticContent, XASSET_SRCREF_PREFIX +from xmodule.modulestore.exceptions import ItemNotFoundError log = logging.getLogger('mitx.' + __name__) @@ -531,7 +532,11 @@ class XModuleDescriptor(Plugin, HTMLSnippet, ResourceTemplates): if self._child_instances is None: self._child_instances = [] for child_loc in self.definition.get('children', []): - child = self.system.load_item(child_loc) + try: + child = self.system.load_item(child_loc) + except ItemNotFoundError: + log.exception('Unable to load item {loc}, skipping'.format(loc=child_loc)) + continue # TODO (vshnayder): this should go away once we have # proper inheritance support in mongo. The xml # datastore does all inheritance on course load.