From 9ddc558085f63abc15f55ecb21ac7f409088a291 Mon Sep 17 00:00:00 2001 From: Emanuel Schuetze Date: Fri, 22 Jan 2016 23:19:41 +0100 Subject: [PATCH] Add checkbox 'show as agenda item'. (Fixes #1783) Used for customslide, motion and assignment forms. Changed default value of agenda.type to HIDDEN_ITEM (=2) in model.py. --- .../migrations/0002_auto_20160122_2318.py | 19 +++++++ openslides/agenda/models.py | 2 +- .../assignments/static/js/assignments/site.js | 56 +++++++++++++++++-- openslides/core/static/js/core/site.js | 19 ++++++- openslides/motions/static/js/motions/site.js | 49 ++++++++++++++-- tests/integration/agenda/test_viewsets.py | 5 ++ 6 files changed, 138 insertions(+), 12 deletions(-) create mode 100644 openslides/agenda/migrations/0002_auto_20160122_2318.py diff --git a/openslides/agenda/migrations/0002_auto_20160122_2318.py b/openslides/agenda/migrations/0002_auto_20160122_2318.py new file mode 100644 index 000000000..e6b23632a --- /dev/null +++ b/openslides/agenda/migrations/0002_auto_20160122_2318.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('agenda', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='item', + name='type', + field=models.IntegerField(default=2, choices=[(1, 'Agenda item'), (2, 'Hidden item')]), + ), + ] diff --git a/openslides/agenda/models.py b/openslides/agenda/models.py index f1ee02de0..4bfc2983c 100644 --- a/openslides/agenda/models.py +++ b/openslides/agenda/models.py @@ -181,7 +181,7 @@ class Item(RESTModelMixin, models.Model): type = models.IntegerField( choices=ITEM_TYPE, - default=AGENDA_ITEM) + default=HIDDEN_ITEM) """ Type of the agenda item. diff --git a/openslides/assignments/static/js/assignments/site.js b/openslides/assignments/static/js/assignments/site.js index 63c3383ec..4b8a0587d 100644 --- a/openslides/assignments/static/js/assignments/site.js +++ b/openslides/assignments/static/js/assignments/site.js @@ -72,7 +72,11 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments']) closeByEscape: false, closeByDocument: false, resolve: { - assignment: function() {return Assignment.find($stateParams.id)} + assignment: function() { + return Assignment.find($stateParams.id).then(function(assignment) { + return Assignment.loadRelations(assignment, 'agenda_item'); + }); + }, }, preCloseCallback: function() { $state.go('assignments.assignment.detail', {assignment: $stateParams.id}); @@ -88,13 +92,19 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments']) // Service for generic assignment form (create and update) .factory('AssignmentForm', [ 'gettextCatalog', - function (gettextCatalog) { + 'operator', + function (gettextCatalog, operator) { return { // ngDialog for assignment form getDialog: function (assignment) { if (assignment) { var resolve = { - assignment: function(Assignment) {return Assignment.find(assignment.id);} + assignment: function() { + return assignment; + }, + agenda_item: function(Assignment) { + return Assignment.loadRelations(assignment, 'agenda_item'); + } }; } return { @@ -139,6 +149,15 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments']) templateOptions: { label: gettextCatalog.getString('Default comment on the ballot paper') } + }, + { + key: 'showAsAgendaItem', + type: 'checkbox', + templateOptions: { + label: gettextCatalog.getString('Show as agenda item'), + description: gettextCatalog.getString('If deactivated the election appears as internal item on agenda.') + }, + hide: !operator.hasPerms('assignments.can_manage') }]; } } @@ -385,7 +404,8 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments']) '$state', 'Assignment', 'AssignmentForm', - function($scope, $state, Assignment, AssignmentForm) { + 'Agenda', + function($scope, $state, Assignment, AssignmentForm, Agenda) { $scope.model = {}; // set default value for open posts form field $scope.model.open_posts = 1; @@ -396,6 +416,16 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments']) $scope.save = function(assignment) { Assignment.create(assignment).then( function(success) { + // find related agenda item + Agenda.find(success.agenda_item_id).then(function(item) { + // check form element and set item type (AGENDA_ITEM = 1, HIDDEN_ITEM = 2) + var type = assignment.showAsAgendaItem ? 1 : 2; + // save only if agenda item type is modified + if (item.type != type) { + item.type = type; + Agenda.save(item); + } + }); $scope.closeThisDialog(); } ); @@ -408,22 +438,36 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments']) '$state', 'Assignment', 'AssignmentForm', + 'Agenda', 'assignment', - function($scope, $state, Assignment, AssignmentForm, assignment) { + function($scope, $state, Assignment, AssignmentForm, Agenda, assignment) { $scope.alert = {}; // set initial values for form model by create deep copy of assignment object // so list/detail view is not updated while editing $scope.model = angular.copy(assignment); // get all form fields $scope.formFields = AssignmentForm.getFormFields(); + for (var i = 0; i < $scope.formFields.length; i++) { + if ($scope.formFields[i].key == "showAsAgendaItem") { + // get state from agenda item (hidden/internal or agenda item) + $scope.formFields[i].defaultValue = !assignment.agenda_item.is_hidden; + } + } // save assignment $scope.save = function (assignment) { // inject the changed assignment (copy) object back into DS store Assignment.inject(assignment); - // save change motion object on server + // save change assignment object on server Assignment.save(assignment).then( function(success) { + // check form element and set item type (AGENDA_ITEM = 1, HIDDEN_ITEM = 2) + var type = assignment.showAsAgendaItem ? 1 : 2; + // save only if agenda item type is modified + if (assignment.agenda_item.type != type) { + assignment.agenda_item.type = type; + Agenda.save(assignment.agenda_item); + } $scope.closeThisDialog(); }, function (error) { diff --git a/openslides/core/static/js/core/site.js b/openslides/core/static/js/core/site.js index 452c62d8f..b42cdf155 100644 --- a/openslides/core/static/js/core/site.js +++ b/openslides/core/static/js/core/site.js @@ -504,6 +504,14 @@ angular.module('OpenSlidesApp.core.site', [ placeholder: gettextCatalog.getString('Select or search an attachment ...') } }, + { + key: 'showOnAgenda', + type: 'checkbox', + templateOptions: { + label: gettextCatalog.getString('Show on agenda'), + description: gettextCatalog.getString('If deactivated it appears as internal item.') + } + }, ]; } } @@ -729,7 +737,8 @@ angular.module('OpenSlidesApp.core.site', [ '$state', 'Customslide', 'CustomslideForm', - function($scope, $state, Customslide, CustomslideForm) { + 'Agenda', + function($scope, $state, Customslide, CustomslideForm, Agenda) { $scope.customslide = {}; // get all form fields $scope.formFields = CustomslideForm.getFormFields(); @@ -738,6 +747,14 @@ angular.module('OpenSlidesApp.core.site', [ $scope.save = function (customslide) { Customslide.create(customslide).then( function(success) { + // show as agenda item + if (customslide.showOnAgenda) { + Agenda.find(success.agenda_item_id).then(function(item) { + // set item type to AGENDA_ITEM = 1 (default is HIDDEN_ITEM = 2) + item.type = 1; + Agenda.save(item); + }); + } $scope.closeThisDialog(); } ); diff --git a/openslides/motions/static/js/motions/site.js b/openslides/motions/static/js/motions/site.js index 2c1c4c79e..cc1d692da 100644 --- a/openslides/motions/static/js/motions/site.js +++ b/openslides/motions/static/js/motions/site.js @@ -83,7 +83,11 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions']) closeByEscape: false, closeByDocument: false, resolve: { - motion: function() {return Motion.find($stateParams.id)} + motion: function() { + return Motion.find($stateParams.id).then(function(motion) { + return Motion.loadRelations(motion, 'agenda_item'); + }); + }, }, preCloseCallback: function() { $state.go('motions.motion.detail', {motion: $stateParams.id}); @@ -153,7 +157,12 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions']) getDialog: function (motion) { if (motion) { var resolve = { - motion: function(Motion) { return Motion.find(motion.id); } + motion: function() { + return motion; + }, + agenda_item: function(Motion) { + return Motion.loadRelations(motion, 'agenda_item'); + } }; } return { @@ -224,6 +233,15 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions']) }, hide: true }, + { + key: 'showAsAgendaItem', + type: 'checkbox', + templateOptions: { + label: gettextCatalog.getString('Show as agenda item'), + description: gettextCatalog.getString('If deactivated the motion appears as internal item on agenda.') + }, + hide: !operator.hasPerms('motions.can_manage') + }, { key: 'more', type: 'checkbox', @@ -595,7 +613,8 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions']) 'Tag', 'User', 'Workflow', - function($scope, $state, gettext, Motion, MotionForm, Category, Config, Mediafile, Tag, User, Workflow) { + 'Agenda', + function($scope, $state, gettext, Motion, MotionForm, Category, Config, Mediafile, Tag, User, Workflow, Agenda) { Category.bindAll({}, $scope, 'categories'); Mediafile.bindAll({}, $scope, 'mediafiles'); Tag.bindAll({}, $scope, 'tags'); @@ -614,6 +633,16 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions']) $scope.save = function (motion) { Motion.create(motion).then( function(success) { + // find related agenda item + Agenda.find(success.agenda_item_id).then(function(item) { + // check form element and set item type (AGENDA_ITEM = 1, HIDDEN_ITEM = 2) + var type = motion.showAsAgendaItem ? 1 : 2; + // save only if agenda item type is modified + if (item.type != type) { + item.type = type; + Agenda.save(item); + } + }); $scope.closeThisDialog(); } ); @@ -632,8 +661,9 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions']) 'Tag', 'User', 'Workflow', + 'Agenda', 'motion', - function($scope, $state, Motion, Category, Config, Mediafile, MotionForm, Tag, User, Workflow, motion) { + function($scope, $state, Motion, Category, Config, Mediafile, MotionForm, Tag, User, Workflow, Agenda, motion) { Category.bindAll({}, $scope, 'categories'); Mediafile.bindAll({}, $scope, 'mediafiles'); Tag.bindAll({}, $scope, 'tags'); @@ -673,6 +703,10 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions']) $scope.formFields[i].hide = false; } } + if ($scope.formFields[i].key == "showAsAgendaItem") { + // get state from agenda item (hidden/internal or agenda item) + $scope.formFields[i].defaultValue = !motion.agenda_item.is_hidden; + } if ($scope.formFields[i].key == "workflow_id") { // get saved workflow id from state $scope.formFields[i].defaultValue = motion.state.workflow_id; @@ -686,6 +720,13 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions']) // save change motion object on server Motion.save(motion, { method: 'PATCH' }).then( function(success) { + // check form element and set item type (AGENDA_ITEM = 1, HIDDEN_ITEM = 2) + var type = motion.showAsAgendaItem ? 1 : 2; + // save only if agenda item type is modified + if (motion.agenda_item.type != type) { + motion.agenda_item.type = type; + Agenda.save(motion.agenda_item); + } $scope.closeThisDialog(); }, function (error) { diff --git a/tests/integration/agenda/test_viewsets.py b/tests/integration/agenda/test_viewsets.py index c82bec1b1..4a7a0ff0b 100644 --- a/tests/integration/agenda/test_viewsets.py +++ b/tests/integration/agenda/test_viewsets.py @@ -243,13 +243,18 @@ class Numbering(TestCase): self.client = APIClient() self.client.login(username='admin', password='admin') self.item_1 = CustomSlide.objects.create(title='test_title_thuha8eef7ohXar3eech').agenda_item + self.item_1.type = Item.AGENDA_ITEM + self.item_1.save() self.item_2 = CustomSlide.objects.create(title='test_title_eisah7thuxa1eingaeLo').agenda_item + self.item_2.type = Item.AGENDA_ITEM self.item_2.weight = 2 self.item_2.save() self.item_2_1 = CustomSlide.objects.create(title='test_title_Qui0audoaz5gie1phish').agenda_item + self.item_2_1.type = Item.AGENDA_ITEM self.item_2_1.parent = self.item_2 self.item_2_1.save() self.item_3 = CustomSlide.objects.create(title='test_title_ah7tphisheineisgaeLo').agenda_item + self.item_3.type = Item.AGENDA_ITEM self.item_3.weight = 3 self.item_3.save()