Fixed motion states, handled workflow field.

This commit is contained in:
Oskar Hahn 2015-11-03 10:03:44 +01:00 committed by Emanuel Schuetze
parent 5b37a21c87
commit c379544e97
8 changed files with 97 additions and 44 deletions

View File

@ -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) {

View File

@ -111,7 +111,7 @@ angular.module('OpenSlidesApp.core', [
// Load the global data on startup
.run([
'loadGlobalData',
function(loadGlobalData, operator) {
function(loadGlobalData) {
loadGlobalData();
}
])

View File

@ -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) {

View File

@ -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)

View File

@ -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

View File

@ -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) {

View File

@ -6,7 +6,11 @@
</small>
</h1>
{{ motion.agenda_item }}
agenda_id: {{ motion.agenda_item }}
<br><br>state: {{ motion.state }}
<br><br>next states: {{ motion.state.getNextStates() }}
<div id="submenu">
<a ui-sref="motions.motion.list" class="btn btn-sm btn-default">

View File

@ -108,15 +108,17 @@ class CreateMotion(TestCase):
self.assertEqual(motion.tags.get().name, 'test_tag_iRee3kiecoos4rorohth')
def test_with_workflow(self):
self.assertEqual(config['motions_workflow'], '1')
"""
Test to create a motion with a specific workflow.
"""
response = self.client.post(
reverse('motion-list'),
{'title': 'test_title_eemuR5hoo4ru2ahgh5EJ',
'text': 'test_text_ohviePopahPhoili7yee',
'workflow': '2'})
'workflow_id': '2'})
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
motion = Motion.objects.get()
self.assertEqual(motion.state.workflow.pk, 2)
self.assertEqual(Motion.objects.get().state.workflow_id, 2)
class UpdateMotion(TestCase):
@ -141,12 +143,15 @@ class UpdateMotion(TestCase):
self.assertEqual(motion.identifier, 'test_identifier_jieseghohj7OoSah1Ko9')
def test_patch_workflow(self):
self.assertEqual(config['motions_workflow'], '1')
"""
Tests to only update the workflow of a motion.
"""
response = self.client.patch(
reverse('motion-detail', args=[self.motion.pk]),
{'workflow': '2'})
self.assertEqual(response.status_code, status.HTTP_200_OK)
{'workflow_id': '2'})
motion = Motion.objects.get()
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(motion.title, 'test_title_aeng7ahChie3waiR8xoh')
self.assertEqual(motion.workflow, 2)