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:
commit
768c97e89c
@ -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].
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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: {
|
||||
|
@ -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();
|
||||
|
@ -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>
|
||||
|
||||
<!--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)">
|
||||
|
@ -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.
|
||||
|
@ -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):
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user