diff --git a/openslides/agenda/static/js/agenda/site.js b/openslides/agenda/static/js/agenda/site.js index a373d890d..f622bf870 100644 --- a/openslides/agenda/static/js/agenda/site.js +++ b/openslides/agenda/static/js/agenda/site.js @@ -585,6 +585,7 @@ angular.module('OpenSlidesApp.agenda.site', [ $scope.items = AgendaTree.getTree(Agenda.getAll()); }); $scope.showInternalItems = true; + $scope.alert = {}; // save parent and weight of moved agenda item (and all items on same level) $scope.treeOptions = { @@ -594,7 +595,15 @@ angular.module('OpenSlidesApp.agenda.site', [ if (event.dest.nodesScope.item) { parentID = event.dest.nodesScope.item.id; } - $http.post('/rest/agenda/item/sort/', {nodes: event.dest.nodesScope.$modelValue, parent_id: parentID}); + $http.post('/rest/agenda/item/sort/', { + nodes: event.dest.nodesScope.$modelValue, + parent_id: parentID} + ).then( + function(success) {}, + function(error){ + $scope.alert = {type: 'danger', msg: error.data.detail, show: true}; + } + ); } }; } diff --git a/openslides/agenda/static/templates/agenda/item-sort.html b/openslides/agenda/static/templates/agenda/item-sort.html index eebe04d65..d92342624 100644 --- a/openslides/agenda/static/templates/agenda/item-sort.html +++ b/openslides/agenda/static/templates/agenda/item-sort.html @@ -19,6 +19,10 @@ Show internal items +
+ {{ alert.msg }} +
+
  1. diff --git a/openslides/agenda/views.py b/openslides/agenda/views.py index 75d8d1cbe..b8a8e1c82 100644 --- a/openslides/agenda/views.py +++ b/openslides/agenda/views.py @@ -241,7 +241,8 @@ class ItemViewSet(ListModelMixin, RetrieveModelMixin, UpdateModelMixin, GenericV @list_route(methods=['post']) def sort(self, request): """ - Sort agenda items. + Sort agenda items. Also checks parent field to prevent hierarchical + loops. """ nodes = request.data.get('nodes', []) parent_id = request.data.get('parent_id') @@ -253,5 +254,15 @@ class ItemViewSet(ListModelMixin, RetrieveModelMixin, UpdateModelMixin, GenericV item.weight = index item.save(skip_autoupdate=True) items.append(item) + + # Now check consistency. TODO: Try to use less DB queries. + item = Item.objects.get(pk=node['id']) + ancestor = item.parent + while ancestor is not None: + if ancestor == item: + raise ValidationError({'detail': _( + 'There must not be a hierarchical loop. Please reload the page.')}) + ancestor = ancestor.parent + inform_changed_data(items) return Response({'detail': _('The agenda has been sorted.')})