From c379544e9778408039a9b314c49335446e840087 Mon Sep 17 00:00:00 2001 From: Oskar Hahn Date: Tue, 3 Nov 2015 10:03:44 +0100 Subject: [PATCH] Fixed motion states, handled workflow field. --- .../assignments/static/js/assignments/site.js | 2 +- openslides/core/static/js/core/base.js | 2 +- openslides/core/static/js/core/site.js | 2 +- openslides/motions/models.py | 5 +- openslides/motions/serializers.py | 27 ++++--- .../motions/static/js/motions/motions.js | 78 ++++++++++++++----- .../templates/motions/motion-detail.html | 6 +- tests/integration/motions/test_viewset.py | 19 +++-- 8 files changed, 97 insertions(+), 44 deletions(-) diff --git a/openslides/assignments/static/js/assignments/site.js b/openslides/assignments/static/js/assignments/site.js index a7e35c065..8759b9cf7 100644 --- a/openslides/assignments/static/js/assignments/site.js +++ b/openslides/assignments/static/js/assignments/site.js @@ -79,7 +79,7 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments']) .controller('AssignmentDetailCtrl', function($scope, Assignment, assignment) { Assignment.bindOne(assignment.id, $scope, 'assignment'); - Assignment.loadRelations(assignment); + Assignment.loadRelations(assignment, 'agenda_item'); }) .controller('AssignmentCreateCtrl', function($scope, $state, Assignment) { diff --git a/openslides/core/static/js/core/base.js b/openslides/core/static/js/core/base.js index 84d6771f4..5c1053d36 100644 --- a/openslides/core/static/js/core/base.js +++ b/openslides/core/static/js/core/base.js @@ -111,7 +111,7 @@ angular.module('OpenSlidesApp.core', [ // Load the global data on startup .run([ 'loadGlobalData', - function(loadGlobalData, operator) { + function(loadGlobalData) { loadGlobalData(); } ]) diff --git a/openslides/core/static/js/core/site.js b/openslides/core/static/js/core/site.js index 4aba97a13..014351ca8 100644 --- a/openslides/core/static/js/core/site.js +++ b/openslides/core/static/js/core/site.js @@ -646,7 +646,7 @@ angular.module('OpenSlidesApp.core.site', [ .controller('CustomslideDetailCtrl', function($scope, Customslide, customslide) { Customslide.bindOne(customslide.id, $scope, 'customslide'); - Customslide.loadRelations(customslide); + Customslide.loadRelations(customslide, 'agenda_item'); }) .controller('CustomslideCreateCtrl', function($scope, $state, Customslide) { diff --git a/openslides/motions/models.py b/openslides/motions/models.py index a410c28cd..9067f43b8 100644 --- a/openslides/motions/models.py +++ b/openslides/motions/models.py @@ -409,6 +409,7 @@ class Motion(RESTModelMixin, models.Model): """ Returns the id of the workflow of the motion. """ + # TODO: Rename to workflow_id return self.state.workflow.pk def set_state(self, state): @@ -442,7 +443,7 @@ class Motion(RESTModelMixin, models.Model): new_state = self.state.workflow.first_state else: new_state = (Workflow.objects.get(pk=config['motions_workflow']).first_state or - Workflow.objects.get(pk=config['motions_workflow']).state_set.all()[0]) + Workflow.objects.get(pk=config['motions_workflow']).states.all()[0]) self.set_state(new_state) def get_agenda_title(self): @@ -729,7 +730,7 @@ class State(RESTModelMixin, models.Model): action_word = models.CharField(max_length=255) """An alternative string to be used for a button to switch to this state.""" - workflow = models.ForeignKey('Workflow') + workflow = models.ForeignKey('Workflow', related_name='states') """A many-to-one relation to a workflow.""" next_states = models.ManyToManyField('self', symmetrical=False) diff --git a/openslides/motions/serializers.py b/openslides/motions/serializers.py index 67eddad0c..f9732fdac 100644 --- a/openslides/motions/serializers.py +++ b/openslides/motions/serializers.py @@ -1,7 +1,6 @@ from django.db import transaction from django.utils.translation import ugettext as _ -from openslides.core.config import config from openslides.utils.rest_api import ( CharField, DictField, @@ -58,19 +57,20 @@ class StateSerializer(ModelSerializer): 'versioning', 'leave_old_version_active', 'dont_set_identifier', - 'next_states',) + 'next_states', + 'workflow') class WorkflowSerializer(ModelSerializer): """ Serializer for motion.models.Workflow objects. """ - state_set = StateSerializer(many=True, read_only=True) + states = StateSerializer(many=True, read_only=True) first_state = PrimaryKeyRelatedField(read_only=True) class Meta: model = Workflow - fields = ('id', 'name', 'state_set', 'first_state',) + fields = ('id', 'name', 'states', 'first_state',) class MotionLogSerializer(ModelSerializer): @@ -180,11 +180,14 @@ class MotionSerializer(ModelSerializer): log_messages = MotionLogSerializer(many=True, read_only=True) polls = MotionPollSerializer(many=True, read_only=True) reason = CharField(allow_blank=True, required=False, write_only=True) - state = StateSerializer(read_only=True) text = CharField(write_only=True) title = CharField(max_length=255, write_only=True) versions = MotionVersionSerializer(many=True, read_only=True) - workflow = IntegerField(min_value=1, required=False, validators=[validate_workflow_field]) + workflow_id = IntegerField( + min_value=1, + required=False, + validators=[validate_workflow_field], + write_only=True) class Meta: model = Motion @@ -201,13 +204,13 @@ class MotionSerializer(ModelSerializer): 'submitters', 'supporters', 'state', - 'workflow', + 'workflow_id', 'tags', 'attachments', 'polls', 'agenda_item_id', 'log_messages',) - read_only_fields = ('parent',) # Some other fields are also read_only. See definitions above. + read_only_fields = ('parent', 'state') # Some other fields are also read_only. See definitions above. @transaction.atomic def create(self, validated_data): @@ -220,7 +223,7 @@ class MotionSerializer(ModelSerializer): motion.reason = validated_data.get('reason', '') motion.identifier = validated_data.get('identifier') motion.category = validated_data.get('category') - motion.reset_state(validated_data.get('workflow', int(config['motions_workflow']))) + motion.reset_state(validated_data.get('workflow_id')) motion.save() if validated_data.get('submitters'): motion.submitters.add(*validated_data['submitters']) @@ -242,9 +245,9 @@ class MotionSerializer(ModelSerializer): setattr(motion, key, validated_data[key]) # Workflow. - workflow = validated_data.get('workflow') - if workflow is not None and workflow != motion.workflow: - motion.reset_state(workflow) + workflow_id = validated_data.get('workflow_id') + if workflow_id is not None and workflow_id != motion.workflow: + motion.reset_state(workflow_id) # Decide if a new version is saved to the database. if (motion.state.versioning and diff --git a/openslides/motions/static/js/motions/motions.js b/openslides/motions/static/js/motions/motions.js index e4ba67e26..41d83f393 100644 --- a/openslides/motions/static/js/motions/motions.js +++ b/openslides/motions/static/js/motions/motions.js @@ -2,14 +2,58 @@ angular.module('OpenSlidesApp.motions', []) +.factory('WorkflowState', [ + 'DS', + function (DS) { + return DS.defineResource({ + name: 'motions/workflowstate', + methods: { + getNextStates: function () { + var states = []; + _.forEach(this.next_states_id, function (stateId) { + states.push(DS.get('motions/workflowstate', stateId)); + }) + return states; + } + } + }) + } +]) + +.factory('Workflow', [ + 'DS', + 'jsDataModel', + 'WorkflowState', + function (DS, jsDataModel, WorkflowState) { + return DS.defineResource({ + name: 'motions/workflow', + useClass: jsDataModel, + relations: { + hasMany: { + 'motions/workflowstate': { + localField: 'states', + foreignKey: 'workflow_id', + } + } + } + }) + } +]) + +// Load all MotionWorkflows at stateup +.run([ + 'Workflow', + function (Workflow) { + Workflow.findAll(); + } +]) + .factory('MotionPoll', [ 'DS', 'Config', - 'jsDataModel', - function(DS, Config, jsDataModel) { + function (DS, Config) { return DS.defineResource({ - name: 'motions/motionpoll', - useClass: jsDataModel, + name: 'motions/poll', relations: { belongsTo: { 'motions/motion': { @@ -149,10 +193,16 @@ angular.module('OpenSlidesApp.motions', []) localKeys: 'supporters_id', } ], - 'motions/motionpoll': { + 'motions/poll': { localField: 'polls', foreignKey: 'motion_id', } + }, + hasOne: { + 'motions/workflowstate': { + localField: 'state', + localKey: 'state_id', + } } } }); @@ -165,13 +215,7 @@ angular.module('OpenSlidesApp.motions', []) }); }]) -.factory('Workflow', ['DS', function(DS) { - return DS.defineResource({ - name: 'motions/workflow', - }); -}]) - -.run(['Motion', 'Category', 'Workflow', function(Motion, Category, Workflow) {}]); +.run(['Motion', 'Category', function(Motion, Category) {}]); angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions']) @@ -221,9 +265,6 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions']) categories: function(Category) { return Category.findAll(); }, - workflows: function(Workflow) { - return Workflow.findAll(); - }, tags: function(Tag) { return Tag.findAll(); }, @@ -262,9 +303,6 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions']) categories: function(Category) { return Category.findAll(); }, - workflows: function(Workflow) { - return Workflow.findAll(); - }, tags: function(Tag) { return Tag.findAll(); }, @@ -405,7 +443,9 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions']) Category.bindAll({}, $scope, 'categories'); Workflow.bindAll({}, $scope, 'workflows'); User.bindAll({}, $scope, 'users'); - Motion.loadRelations(motion); + Motion.loadRelations(motion, 'agenda_item'); + var state = motion.state; + state.getNextStates() $scope.alert = {}; // TODO: show alert in template $scope.update_state = function (state_id) { diff --git a/openslides/motions/static/templates/motions/motion-detail.html b/openslides/motions/static/templates/motions/motion-detail.html index 3efb17c2a..9cc830743 100644 --- a/openslides/motions/static/templates/motions/motion-detail.html +++ b/openslides/motions/static/templates/motions/motion-detail.html @@ -6,7 +6,11 @@ -{{ motion.agenda_item }} +agenda_id: {{ motion.agenda_item }} + +

state: {{ motion.state }} + +

next states: {{ motion.state.getNextStates() }}