diff --git a/mayan/apps/document_states/api_views.py b/mayan/apps/document_states/api_views.py index aff3529f01..3caf7e78bf 100644 --- a/mayan/apps/document_states/api_views.py +++ b/mayan/apps/document_states/api_views.py @@ -250,7 +250,6 @@ class APIWorkflowView(generics.RetrieveUpdateDestroyAPIView): class APIWorkflowStateListView(generics.ListCreateAPIView): serializer_class = WorkflowStateSerializer - queryset = WorkflowState.objects.all() def get(self, *args, **kwargs): """ @@ -258,6 +257,39 @@ class APIWorkflowStateListView(generics.ListCreateAPIView): """ return super(APIWorkflowStateListView, self).get(*args, **kwargs) + def get_queryset(self): + return self.get_workflow().states.all() + + def get_serializer_context(self): + """ + Extra context provided to the serializer class. + """ + return { + 'format': self.format_kwarg, + 'request': self.request, + 'workflow': self.get_workflow(), + 'view': self + } + + def get_workflow(self): + if self.request.method == 'GET': + permission_required = permission_workflow_view + else: + permission_required = permission_workflow_edit + + workflow = get_object_or_404(Workflow, pk=self.kwargs['pk']) + + try: + Permission.check_permissions( + self.request.user, (permission_required,) + ) + except PermissionDenied: + AccessControlList.objects.check_access( + permission_required, self.request.user, workflow + ) + + return workflow + def post(self, *args, **kwargs): """ Create a new workflow state. @@ -265,6 +297,74 @@ class APIWorkflowStateListView(generics.ListCreateAPIView): return super(APIWorkflowStateListView, self).post(*args, **kwargs) -class APIWorkflowStateView(generics.RetrieveAPIView): - queryset = WorkflowState.objects.all() - serializer_class = WorkflowStateSerializer +class APIWorkflowStateView(generics.RetrieveUpdateDestroyAPIView): + lookup_url_kwarg = 'state_pk' + + def delete(self, *args, **kwargs): + """ + Delete the selected workflow state. + """ + + return super(APIWorkflowStateView, self).delete(*args, **kwargs) + + def get(self, *args, **kwargs): + """ + Return the details of the selected workflow state. + """ + + return super(APIWorkflowStateView, self).get(*args, **kwargs) + + def get_queryset(self): + return self.get_workflow().states.all() + + def get_serializer_class(self): + if self.request.method == 'GET': + return WorkflowStateSerializer + else: + return WorkflowStateSerializer # TODO: Writable + + def get_serializer_context(self): + """ + Extra context provided to the serializer class. + """ + return { + 'format': self.format_kwarg, + 'request': self.request, + 'workflow': self.get_workflow(), + 'view': self + } + + def get_workflow(self): + if self.request.method == 'GET': + permission_required = permission_workflow_view + else: + permission_required = permission_workflow_edit + + workflow = get_object_or_404(Workflow, pk=self.kwargs['pk']) + + try: + Permission.check_permissions( + self.request.user, (permission_required,) + ) + except PermissionDenied: + AccessControlList.objects.check_access( + permission_required, self.request.user, workflow + ) + + return workflow + + def patch(self, *args, **kwargs): + """ + Edit the selected workflow state. + """ + + return super(APIWorkflowStateView, self).patch(*args, **kwargs) + + def put(self, *args, **kwargs): + """ + Edit the selected workflow state. + """ + + return super(APIWorkflowStateView, self).put(*args, **kwargs) + + diff --git a/mayan/apps/document_states/serializers.py b/mayan/apps/document_states/serializers.py index 322c37743e..947d9ced86 100644 --- a/mayan/apps/document_states/serializers.py +++ b/mayan/apps/document_states/serializers.py @@ -49,14 +49,33 @@ class WorkflowDocumentTypeSerializer(DocumentTypeSerializer): class WorkflowStateSerializer(serializers.HyperlinkedModelSerializer): + workflow_url = serializers.SerializerMethodField() + url = serializers.SerializerMethodField() + class Meta: - extra_kwargs = { - 'url': {'view_name': 'rest_api:workflowstate-detail'}, - 'workflow': {'view_name': 'rest_api:workflow-detail'}, - } - fields = ('completion', 'id', 'initial', 'label', 'workflow', 'url') + fields = ( + 'completion', 'id', 'initial', 'label', 'url', 'workflow_url', + ) model = WorkflowState + def create(self, validated_data): + validated_data['workflow'] = self.context['workflow'] + return super(WorkflowStateSerializer, self).create(validated_data) + + def get_url(self, instance): + return reverse( + 'rest_api:workflowstate-detail', args=( + instance.workflow.pk, instance.pk + ), request=self.context['request'], format=self.context['format'] + ) + + def get_workflow_url(self, instance): + return reverse( + 'rest_api:workflow-detail', args=( + instance.workflow.pk, + ), request=self.context['request'], format=self.context['format'] + ) + class WorkflowSerializer(serializers.HyperlinkedModelSerializer): document_types_url = serializers.HyperlinkedIdentityField( diff --git a/mayan/apps/document_states/tests/test_api.py b/mayan/apps/document_states/tests/test_api.py index d1276791e4..7da2cecd1a 100644 --- a/mayan/apps/document_states/tests/test_api.py +++ b/mayan/apps/document_states/tests/test_api.py @@ -18,7 +18,10 @@ from user_management.tests.literals import ( from ..models import Workflow -from .literals import TEST_WORKFLOW_LABEL, TEST_WORKFLOW_LABEL_EDITED +from .literals import ( + TEST_WORKFLOW_LABEL, TEST_WORKFLOW_LABEL_EDITED, + TEST_WORKFLOW_STATE_COMPLETION, TEST_WORKFLOW_STATE_LABEL +) @override_settings(OCR_AUTO_OCR=False) @@ -208,15 +211,68 @@ class WorkflowStatesAPITestCase(APITestCase): self.document_type.delete() def _create_workflow(self): - return Workflow.objects.create(label=TEST_WORKFLOW_LABEL) + self.workflow = Workflow.objects.create(label=TEST_WORKFLOW_LABEL) + + def _create_workflow_state(self): + self._create_workflow() + self.workflow_state = self.workflow.states.create( + completion=TEST_WORKFLOW_STATE_COMPLETION, + label=TEST_WORKFLOW_STATE_LABEL + ) + + def test_workflow_state_create_view(self): + self._create_workflow() - def test_workflow_create_view(self): response = self.client.post( - reverse('rest_api:workflow-list'), { - 'label': TEST_WORKFLOW_LABEL + reverse( + 'rest_api:workflowstate-list', args=(self.workflow.pk,) + ), data={ + 'completion': TEST_WORKFLOW_STATE_COMPLETION, + 'label': TEST_WORKFLOW_STATE_LABEL } ) - workflow = Workflow.objects.first() - self.assertEqual(Workflow.objects.count(), 1) - self.assertEqual(response.data['id'], workflow.pk) + self.workflow.refresh_from_db() + + self.assertEqual( + self.workflow.states.first().label, TEST_WORKFLOW_STATE_LABEL + ) + + def test_workflow_state_delete_view(self): + self._create_workflow_state() + + response = self.client.delete( + reverse( + 'rest_api:workflowstate-detail', + args=(self.workflow.pk, self.workflow_state.pk) + ), + ) + + self.workflow.refresh_from_db() + + self.assertEqual(self.workflow.states.count(), 0) + + def test_workflow_state_detail_view(self): + self._create_workflow_state() + + response = self.client.get( + reverse( + 'rest_api:workflowstate-detail', + args=(self.workflow.pk, self.workflow_state.pk) + ), + ) + + self.assertEqual( + response.data['label'], TEST_WORKFLOW_STATE_LABEL + ) + + def test_workflow_state_list_view(self): + self._create_workflow_state() + + response = self.client.get( + reverse('rest_api:workflowstate-list', args=(self.workflow.pk,)), + ) + + self.assertEqual( + response.data['results'][0]['label'], TEST_WORKFLOW_STATE_LABEL + ) diff --git a/mayan/apps/document_states/urls.py b/mayan/apps/document_states/urls.py index bfdcac7617..5eced2ab0c 100644 --- a/mayan/apps/document_states/urls.py +++ b/mayan/apps/document_states/urls.py @@ -105,13 +105,12 @@ urlpatterns = patterns( api_urls = [ url( - r'^states/$', APIWorkflowStateListView.as_view(), - name='workflowstate-list' + r'^workflows/(?P[0-9]+)/states/$', + APIWorkflowStateListView.as_view(), name='workflowstate-list' ), url( - r'^states/(?P[0-9]+)/$', - APIWorkflowStateView.as_view(), - name='workflowstate-detail' + r'^workflows/(?P[0-9]+)/states/(?P[0-9]+)/$', + APIWorkflowStateView.as_view(), name='workflowstate-detail' ), url(r'^workflows/$', APIWorkflowListView.as_view(), name='workflow-list'), url(