Merge pull request #3785 from FinnStutzenstein/no-changeable-first-state

Do not allow changing a workflow's first state (closes #3778)
This commit is contained in:
Emanuel Schütze 2018-08-23 09:24:29 +02:00 committed by GitHub
commit 768c97e89c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 6 additions and 92 deletions

View File

@ -15,14 +15,14 @@ Motions:
- New possibility to sort submitters [#3647].
- New representation of amendments (paragraph based creation, new diff
and list views for amendments) [#3637].
- New feature to customize workflows and states [#3772].
- New feature to customize workflows and states [#3772, #3785].
- New config options to show logos on the right side in PDF [#3768].
- New table of contents with page numbers and categories in PDF [#3766].
- New teporal field "modified final version" where the final version can
be edited [#3781].
- New config to show amendments also in motions table [#3792]
Core:
Core:
- Python 3.4 is not supported anymore [#3777].
- Support Python 3.7 [#3786].
- Updated pdfMake to 0.1.37 [#3766].

View File

@ -101,12 +101,11 @@ class WorkflowSerializer(ModelSerializer):
Serializer for motion.models.Workflow objects.
"""
states = StateSerializer(many=True, read_only=True)
# The first_state is checked in the update() method
first_state = PrimaryKeyRelatedField(queryset=State.objects.all(), required=False)
class Meta:
model = Workflow
fields = ('id', 'name', 'states', 'first_state',)
read_only_fields = ('first_state',)
@transaction.atomic
def create(self, validated_data):
@ -127,17 +126,6 @@ class WorkflowSerializer(ModelSerializer):
workflow.save()
return workflow
@transaction.atomic
def update(self, workflow, validated_data):
"""
Check, if the first state is in the right workflow.
"""
first_state = validated_data.get('first_state')
if first_state is not None:
if workflow.pk != first_state.workflow.pk:
raise ValidationError({'detail': 'You cannot select a state which is not in the workflow as the first state.'})
return super().update(workflow, validated_data)
class MotionCommentsJSONSerializerField(Field):
"""

View File

@ -54,7 +54,7 @@ angular.module('OpenSlidesApp.motions', [
name: 'motions/workflow',
methods: {
getFirstState: function () {
return DS.get('motions/state', this.first_state);
return DS.get('motions/state', this.first_state_id);
},
},
relations: {

View File

@ -120,13 +120,6 @@ angular.module('OpenSlidesApp.motions.workflow', [])
});
};
$scope.setFirstState = function (state) {
$scope.workflow.first_state = state.id;
Workflow.save($scope.workflow).then(null, function (error) {
$scope.alert = ErrorMessage.forAlert(error);
});
};
// Save expand state so the session
if ($sessionStorage.motionStateTableExpandState) {
$scope.toggleExpandContent();

View File

@ -24,22 +24,9 @@
</h1>
</div>
<div class="title">
<h3 ng-mouseover="firstStateHover=true" ng-mouseleave="firstStateHover=false">
<h3>
<translate>First state</translate>:
{{ workflow.getFirstState().name | translate }}
<span uib-dropdown>
<span id="firstStateDropdown" class="pointer" uib-dropdown-toggle>
<i class="fa fa-cog" ng-if="firstStateHover"></i>
</span>
<ul class="dropdown-menu" aria-labelledby="firstStateDropdown">
<li ng-repeat="state in workflow.states">
<a href ng-click="setFirstState(state)">
<i class="fa fa-check" ng-if="workflow.first_state === state.id"></i>
{{ state.name | translate }}
</a>
</li>
</ul>
</span>
</h3>
</div>
</div>
@ -67,7 +54,7 @@
<i class="fa fa-pencil fa-lg"></i></a>
&nbsp;
<!--delete-->
<a href="" class="text-danger" ng-if="state.id !== workflow.first_state"
<a href="" class="text-danger" ng-if="state.id !== workflow.first_state_id"
ng-bootbox-confirm="{{ 'Are you sure you want to delete this entry?' | translate }}<br>
<b>{{ state.name | translate }}</b>"
ng-bootbox-confirm-action="delete(state)">

View File

@ -919,13 +919,6 @@ class WorkflowViewSet(ModelViewSet, ProtectedErrorMessageMixin):
result = False
return result
def create(self, *args, **kwargs):
try:
response = super().create(*args, **kwargs)
except WorkflowError as e:
raise ValidationError({'detail': e.args[0]})
return response
def destroy(self, *args, **kwargs):
"""
Customized view endpoint to delete a motion poll.

View File

@ -1258,21 +1258,6 @@ class CreateWorkflow(TestCase):
first_state = workflow.first_state
self.assertEqual(type(first_state), State)
def test_creation_with_wrong_first_state(self):
response = self.client.post(
reverse('workflow-list'),
{'name': 'test_name_OoCoo3MeiT9li5Iengu9',
'first_state': 1})
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def test_creation_with_not_existing_first_state(self):
Workflow.objects.all().delete()
response = self.client.post(
reverse('workflow-list'),
{'name': 'test_name_OoCoo3MeiT9li5Iengu9',
'first_state': 49})
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
class UpdateWorkflow(TestCase):
"""
@ -1292,38 +1277,6 @@ class UpdateWorkflow(TestCase):
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(workflow.name, 'test_name_wofi38DiWLT"8d3lwfo3')
def test_change_first_state_correct(self):
first_state = self.workflow.first_state
other_workflow_state = self.workflow.states.exclude(pk=first_state.pk).first()
response = self.client.patch(
reverse('workflow-detail', args=[self.workflow.pk]),
{'first_state': other_workflow_state.pk})
workflow = Workflow.objects.get(pk=self.workflow.id)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(workflow.first_state, other_workflow_state)
def test_change_first_state_not_existing(self):
first_state = self.workflow.first_state
response = self.client.patch(
reverse('workflow-detail', args=[self.workflow.pk]),
{'first_state': 42})
workflow = Workflow.objects.get(pk=self.workflow.id)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(workflow.first_state, first_state)
def test_change_first_state_wrong_workflow(self):
first_state = self.workflow.first_state
other_workflow = Workflow.objects.exclude(pk=self.workflow.pk).first()
response = self.client.patch(
reverse('workflow-detail', args=[self.workflow.pk]),
{'first_state': other_workflow.first_state.pk})
workflow = Workflow.objects.get(pk=self.workflow.id)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(workflow.first_state, first_state)
class DeleteWorkflow(TestCase):
"""