From 6e1cf570790a23d8de85ef57e2180ef3d6ab52d0 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 20 Feb 2017 02:34:47 -0400 Subject: [PATCH] Implement document workflows transition ACLs. GitLab issue #321. Signed-off-by: Roberto Rosario --- mayan/apps/common/generics.py | 2 +- mayan/apps/common/mixins.py | 20 +- mayan/apps/common/tests/test_views.py | 14 + mayan/apps/document_states/api_views.py | 29 ++- mayan/apps/document_states/apps.py | 16 +- mayan/apps/document_states/forms.py | 38 ++- mayan/apps/document_states/tests/literals.py | 1 + mayan/apps/document_states/tests/test_api.py | 13 + .../apps/document_states/tests/test_views.py | 240 ++++++++++++++---- mayan/apps/document_states/urls.py | 13 +- mayan/apps/document_states/views.py | 39 +-- 11 files changed, 336 insertions(+), 89 deletions(-) diff --git a/mayan/apps/common/generics.py b/mayan/apps/common/generics.py index d79cfb145d..4efc317922 100644 --- a/mayan/apps/common/generics.py +++ b/mayan/apps/common/generics.py @@ -177,7 +177,7 @@ class ConfirmView(ObjectListPermissionFilterMixin, ObjectPermissionCheckMixin, V return HttpResponseRedirect(self.get_success_url()) -class FormView(ViewPermissionCheckMixin, ExtraContextMixin, RedirectionMixin, DjangoFormView): +class FormView(FormExtraKwargsMixin, ViewPermissionCheckMixin, ExtraContextMixin, RedirectionMixin, DjangoFormView): template_name = 'appearance/generic_form.html' diff --git a/mayan/apps/common/mixins.py b/mayan/apps/common/mixins.py index 34b89ff736..aefabb9d57 100644 --- a/mayan/apps/common/mixins.py +++ b/mayan/apps/common/mixins.py @@ -12,8 +12,8 @@ from permissions import Permission __all__ = ( 'DeleteExtraDataMixin', 'ExtraContextMixin', - 'ObjectListPermissionFilterMixin', 'ObjectNameMixin', - 'ObjectPermissionCheckMixin', 'RedirectionMixin', + 'FormExtraKwargsMixin', 'ObjectListPermissionFilterMixin', + 'ObjectNameMixin', 'ObjectPermissionCheckMixin', 'RedirectionMixin', 'ViewPermissionCheckMixin' ) @@ -42,6 +42,22 @@ class ExtraContextMixin(object): return context +class FormExtraKwargsMixin(object): + """ + Mixin that allows a view to pass extra keyword arguments to forms + """ + + form_extra_kwargs = {} + + def get_form_extra_kwargs(self): + return self.form_extra_kwargs + + def get_form_kwargs(self): + result = super(FormExtraKwargsMixin, self).get_form_kwargs() + result.update(self.get_form_extra_kwargs()) + return result + + class MultipleInstanceActionMixin(object): model = None success_message = 'Operation performed on %(count)d object' diff --git a/mayan/apps/common/tests/test_views.py b/mayan/apps/common/tests/test_views.py index 6fa95a8721..ec56a1b9ea 100644 --- a/mayan/apps/common/tests/test_views.py +++ b/mayan/apps/common/tests/test_views.py @@ -76,6 +76,11 @@ class GenericViewTestCase(BaseTestCase): data=data, follow=follow ) + def grant(self, permission): + self.role.permissions.add( + permission.stored_permission + ) + def login(self, username, password): logged_in = self.client.login(username=username, password=password) @@ -84,6 +89,15 @@ class GenericViewTestCase(BaseTestCase): self.assertTrue(logged_in) self.assertTrue(user.is_authenticated()) + def login_user(self): + self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD) + + def login_admin_user(self): + self.login(username=TEST_ADMIN_USERNAME, password=TEST_ADMIN_PASSWORD) + + def logout(self): + self.client.logout() + def post(self, viewname, *args, **kwargs): data = kwargs.pop('data', {}) follow = kwargs.pop('follow', False) diff --git a/mayan/apps/document_states/api_views.py b/mayan/apps/document_states/api_views.py index 2c3735e159..08a1e55d43 100644 --- a/mayan/apps/document_states/api_views.py +++ b/mayan/apps/document_states/api_views.py @@ -6,7 +6,7 @@ from django.shortcuts import get_object_or_404 from rest_framework import generics from acls.models import AccessControlList -from documents.models import Document +from documents.models import Document, DocumentType from documents.permissions import permission_document_type_view from permissions import Permission from rest_api.filters import MayanObjectPermissionsFilter @@ -27,6 +27,33 @@ from .serializers import ( ) +class APIDocumentTypeWorkflowListView(generics.ListAPIView): + serializer_class = WorkflowSerializer + + def get(self, *args, **kwargs): + """ + Returns a list of all the document type workflows. + """ + return super(APIDocumentTypeWorkflowListView, self).get(*args, **kwargs) + + def get_document_type(self): + document_type = get_object_or_404(DocumentType, pk=self.kwargs['pk']) + + try: + Permission.check_permissions( + self.request.user, (permission_workflow_view,) + ) + except PermissionDenied: + AccessControlList.objects.check_access( + permission_workflow_view, self.request.user, document_type + ) + + return document_type + + def get_queryset(self): + return self.get_document_type().workflows.all() + + class APIWorkflowDocumentTypeList(generics.ListCreateAPIView): filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = { diff --git a/mayan/apps/document_states/apps.py b/mayan/apps/document_states/apps.py index 706d7435d3..76ffb2673d 100644 --- a/mayan/apps/document_states/apps.py +++ b/mayan/apps/document_states/apps.py @@ -4,6 +4,8 @@ from django.apps import apps from django.db.models.signals import post_save from django.utils.translation import ugettext_lazy as _ +from acls import ModelPermission +from acls.links import link_acl_list from common import ( MayanAppConfig, menu_facet, menu_object, menu_secondary, menu_setup, menu_sidebar @@ -23,6 +25,7 @@ from .links import ( link_setup_workflow_transition_delete, link_setup_workflow_transition_edit, link_workflow_instance_detail, link_workflow_instance_transition ) +from .permissions import permission_workflow_transition class DocumentStatesApp(MayanAppConfig): @@ -46,6 +49,15 @@ class DocumentStatesApp(MayanAppConfig): WorkflowState = self.get_model('WorkflowState') WorkflowTransition = self.get_model('WorkflowTransition') + ModelPermission.register( + model=Workflow, permissions=(permission_workflow_transition,) + ) + + ModelPermission.register( + model=WorkflowTransition, + permissions=(permission_workflow_transition,) + ) + SourceColumn( source=Workflow, label=_('Initial state'), func=lambda context: context['object'].get_initial_state() or _('None') @@ -118,7 +130,7 @@ class DocumentStatesApp(MayanAppConfig): links=( link_setup_workflow_states, link_setup_workflow_transitions, link_setup_workflow_document_types, link_setup_workflow_edit, - link_setup_workflow_delete + link_acl_list, link_setup_workflow_delete ), sources=(Workflow,) ) menu_object.bind_links( @@ -129,7 +141,7 @@ class DocumentStatesApp(MayanAppConfig): ) menu_object.bind_links( links=( - link_setup_workflow_transition_edit, + link_setup_workflow_transition_edit, link_acl_list, link_setup_workflow_transition_delete ), sources=(WorkflowTransition,) ) diff --git a/mayan/apps/document_states/forms.py b/mayan/apps/document_states/forms.py index 98ead3a160..ed1687296f 100644 --- a/mayan/apps/document_states/forms.py +++ b/mayan/apps/document_states/forms.py @@ -1,9 +1,14 @@ -from __future__ import unicode_literals +from __future__ import absolute_import, unicode_literals from django import forms +from django.core.exceptions import PermissionDenied from django.utils.translation import ugettext_lazy as _ +from acls.models import AccessControlList +from permissions import Permission + from .models import Workflow, WorkflowState, WorkflowTransition +from .permissions import permission_workflow_transition class WorkflowForm(forms.ModelForm): @@ -32,11 +37,36 @@ class WorkflowTransitionForm(forms.ModelForm): class WorkflowInstanceTransitionForm(forms.Form): def __init__(self, *args, **kwargs): - workflow = kwargs.pop('workflow') + user = kwargs.pop('user') + workflow_instance = kwargs.pop('workflow_instance') super(WorkflowInstanceTransitionForm, self).__init__(*args, **kwargs) - self.fields['transition'].choices = workflow.get_transition_choices().values_list('pk', 'label') + queryset = workflow_instance.get_transition_choices().all() - transition = forms.ChoiceField(label=_('Transition')) + try: + Permission.check_permissions( + requester=user, permissions=(permission_workflow_transition,) + ) + except PermissionDenied: + try: + # Check for ACL access to the workflow, if true, allow all + # transition options. + AccessControlList.objects.check_access( + permissions=permission_workflow_transition, user=user, + obj=workflow_instance.workflow + ) + except PermissionDenied: + # If not ACL access to the workflow, filter transition options + # by each transition ACL access + queryset = AccessControlList.objects.filter_by_access( + permission=permission_workflow_transition, user=user, + queryset=queryset + ) + + self.fields['transition'].queryset = queryset + + transition = forms.ModelChoiceField( + label=_('Transition'), queryset=WorkflowTransition.objects.none() + ) comment = forms.CharField( label=_('Comment'), required=False, widget=forms.widgets.Textarea() ) diff --git a/mayan/apps/document_states/tests/literals.py b/mayan/apps/document_states/tests/literals.py index fac41db489..31685e0e70 100644 --- a/mayan/apps/document_states/tests/literals.py +++ b/mayan/apps/document_states/tests/literals.py @@ -9,4 +9,5 @@ TEST_WORKFLOW_STATE_LABEL = 'test state label' TEST_WORKFLOW_STATE_LABEL_EDITED = 'test state label edited' TEST_WORKFLOW_STATE_COMPLETION = 66 TEST_WORKFLOW_TRANSITION_LABEL = 'test transtition label' +TEST_WORKFLOW_TRANSITION_LABEL_2 = 'test transtition label 2' TEST_WORKFLOW_TRANSITION_LABEL_EDITED = 'test transtition label edited' diff --git a/mayan/apps/document_states/tests/test_api.py b/mayan/apps/document_states/tests/test_api.py index 6545450ee7..9ee947abe2 100644 --- a/mayan/apps/document_states/tests/test_api.py +++ b/mayan/apps/document_states/tests/test_api.py @@ -186,6 +186,19 @@ class WorkflowAPITestCase(APITestCase): workflow.refresh_from_db() self.assertEqual(workflow.label, TEST_WORKFLOW_LABEL_EDITED) + def test_document_type_workflow_list(self): + workflow = self._create_workflow() + workflow.document_types.add(self.document_type) + + response = self.client.get( + reverse( + 'rest_api:documenttype-workflow-list', + args=(self.document_type.pk,) + ), + ) + + self.assertEqual(response.data['results'][0]['label'], workflow.label) + @override_settings(OCR_AUTO_OCR=False) class WorkflowStatesAPITestCase(APITestCase): diff --git a/mayan/apps/document_states/tests/test_views.py b/mayan/apps/document_states/tests/test_views.py index 028818247d..5f37b0bacf 100644 --- a/mayan/apps/document_states/tests/test_views.py +++ b/mayan/apps/document_states/tests/test_views.py @@ -5,20 +5,24 @@ from django.core.urlresolvers import reverse from django.test.client import Client from django.test import TestCase +from acls.models import AccessControlList from documents.models import DocumentType from documents.tests.literals import ( TEST_DOCUMENT_TYPE, TEST_SMALL_DOCUMENT_PATH ) +from documents.tests.test_views import GenericDocumentViewTestCase from user_management.tests import ( TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL ) from ..models import Workflow, WorkflowState, WorkflowTransition +from ..permissions import permission_workflow_transition from .literals import ( TEST_WORKFLOW_LABEL, TEST_WORKFLOW_INITIAL_STATE_LABEL, TEST_WORKFLOW_INITIAL_STATE_COMPLETION, TEST_WORKFLOW_STATE_LABEL, - TEST_WORKFLOW_STATE_COMPLETION, TEST_WORKFLOW_TRANSITION_LABEL + TEST_WORKFLOW_STATE_COMPLETION, TEST_WORKFLOW_TRANSITION_LABEL, + TEST_WORKFLOW_TRANSITION_LABEL_2 ) @@ -48,6 +52,26 @@ class DocumentStateViewTestCase(TestCase): def tearDown(self): self.document_type.delete() + def _create_workflow(self): + self.workflow = Workflow.objects.create(label=TEST_WORKFLOW_LABEL) + + def _create_workflow_states(self): + self.workflow_initial_state = WorkflowState.objects.create( + workflow=self.workflow, label=TEST_WORKFLOW_INITIAL_STATE_LABEL, + completion=TEST_WORKFLOW_INITIAL_STATE_COMPLETION, initial=True + ) + self.workflow_state = WorkflowState.objects.create( + workflow=self.workflow, label=TEST_WORKFLOW_STATE_LABEL, + completion=TEST_WORKFLOW_STATE_COMPLETION + ) + + def _create_workflow_transition(self): + self.workflow_transition = WorkflowTransition.objects.create( + workflow=self.workflow, label=TEST_WORKFLOW_TRANSITION_LABEL, + origin_state=self.workflow_initial_state, + destination_state=self.workflow_state + ) + def test_creating_workflow(self): response = self.client.post( reverse( @@ -63,14 +87,12 @@ class DocumentStateViewTestCase(TestCase): self.assertEquals(Workflow.objects.all()[0].label, TEST_WORKFLOW_LABEL) def test_delete_workflow(self): - workflow = Workflow.objects.create(label=TEST_WORKFLOW_LABEL) - - self.assertEquals(Workflow.objects.count(), 1) - self.assertEquals(Workflow.objects.all()[0].label, TEST_WORKFLOW_LABEL) + self._create_workflow() response = self.client.post( reverse( - 'document_states:setup_workflow_delete', args=(workflow.pk,) + 'document_states:setup_workflow_delete', + args=(self.workflow.pk,) ), follow=True ) @@ -79,12 +101,12 @@ class DocumentStateViewTestCase(TestCase): self.assertEquals(Workflow.objects.count(), 0) def test_create_workflow_state(self): - workflow = Workflow.objects.create(label=TEST_WORKFLOW_LABEL) + self._create_workflow() response = self.client.post( reverse( 'document_states:setup_workflow_state_create', - args=(workflow.pk,) + args=(self.workflow.pk,) ), data={ 'label': TEST_WORKFLOW_STATE_LABEL, 'completion': TEST_WORKFLOW_STATE_COMPLETION, @@ -103,43 +125,33 @@ class DocumentStateViewTestCase(TestCase): ) def test_delete_workflow_state(self): - workflow = Workflow.objects.create(label=TEST_WORKFLOW_LABEL) - workflow_state = WorkflowState.objects.create( - workflow=workflow, label=TEST_WORKFLOW_STATE_LABEL, - completion=TEST_WORKFLOW_STATE_COMPLETION - ) + self._create_workflow() + self._create_workflow_states() response = self.client.post( reverse( 'document_states:setup_workflow_state_delete', - args=(workflow_state.pk,) + args=(self.workflow_state.pk,) ), follow=True ) self.assertEquals(response.status_code, 200) - self.assertEquals(WorkflowState.objects.count(), 0) + self.assertEquals(WorkflowState.objects.count(), 1) self.assertEquals(Workflow.objects.count(), 1) def test_create_workflow_transition(self): - workflow = Workflow.objects.create(label=TEST_WORKFLOW_LABEL) - workflow_initial_state = WorkflowState.objects.create( - workflow=workflow, label=TEST_WORKFLOW_INITIAL_STATE_LABEL, - completion=TEST_WORKFLOW_INITIAL_STATE_COMPLETION, initial=True - ) - workflow_state = WorkflowState.objects.create( - workflow=workflow, label=TEST_WORKFLOW_STATE_LABEL, - completion=TEST_WORKFLOW_STATE_COMPLETION - ) + self._create_workflow() + self._create_workflow_states() response = self.client.post( reverse( 'document_states:setup_workflow_transition_create', - args=(workflow.pk,) + args=(self.workflow.pk,) ), data={ 'label': TEST_WORKFLOW_TRANSITION_LABEL, - 'origin_state': workflow_initial_state.pk, - 'destination_state': workflow_state.pk, + 'origin_state': self.workflow_initial_state.pk, + 'destination_state': self.workflow_state.pk, }, follow=True ) @@ -152,35 +164,22 @@ class DocumentStateViewTestCase(TestCase): ) self.assertEquals( WorkflowTransition.objects.all()[0].origin_state, - workflow_initial_state + self.workflow_initial_state ) self.assertEquals( WorkflowTransition.objects.all()[0].destination_state, - workflow_state + self.workflow_state ) def test_delete_workflow_transition(self): - workflow = Workflow.objects.create(label=TEST_WORKFLOW_LABEL) - workflow_initial_state = WorkflowState.objects.create( - workflow=workflow, label=TEST_WORKFLOW_INITIAL_STATE_LABEL, - completion=TEST_WORKFLOW_INITIAL_STATE_COMPLETION, initial=True - ) - workflow_state = WorkflowState.objects.create( - workflow=workflow, label=TEST_WORKFLOW_STATE_LABEL, - completion=TEST_WORKFLOW_STATE_COMPLETION - ) - workflow_transition = WorkflowTransition.objects.create( - workflow=workflow, label=TEST_WORKFLOW_TRANSITION_LABEL, - origin_state=workflow_initial_state, - destination_state=workflow_state - ) - - self.assertEquals(WorkflowTransition.objects.count(), 1) + self._create_workflow() + self._create_workflow_states() + self._create_workflow_transition() response = self.client.post( reverse( 'document_states:setup_workflow_transition_delete', - args=(workflow_transition.pk,) + args=(self.workflow_transition.pk,) ), follow=True ) @@ -189,3 +188,152 @@ class DocumentStateViewTestCase(TestCase): self.assertEquals(WorkflowState.objects.count(), 2) self.assertEquals(Workflow.objects.count(), 1) self.assertEquals(WorkflowTransition.objects.count(), 0) + + +class DocumentStateTransitionViewTestCase(GenericDocumentViewTestCase): + def _create_workflow(self): + self.workflow = Workflow.objects.create(label=TEST_WORKFLOW_LABEL) + self.workflow.document_types.add(self.document_type) + + def _create_workflow_states(self): + self.workflow_initial_state = WorkflowState.objects.create( + workflow=self.workflow, label=TEST_WORKFLOW_INITIAL_STATE_LABEL, + completion=TEST_WORKFLOW_INITIAL_STATE_COMPLETION, initial=True + ) + self.workflow_state = WorkflowState.objects.create( + workflow=self.workflow, label=TEST_WORKFLOW_STATE_LABEL, + completion=TEST_WORKFLOW_STATE_COMPLETION + ) + + def _create_workflow_transitions(self): + self.workflow_transition = WorkflowTransition.objects.create( + workflow=self.workflow, label=TEST_WORKFLOW_TRANSITION_LABEL, + origin_state=self.workflow_initial_state, + destination_state=self.workflow_state + ) + + self.workflow_transition_2 = WorkflowTransition.objects.create( + workflow=self.workflow, label=TEST_WORKFLOW_TRANSITION_LABEL_2, + origin_state=self.workflow_initial_state, + destination_state=self.workflow_state + ) + + def _create_document(self): + with open(TEST_SMALL_DOCUMENT_PATH) as file_object: + self.document_2 = self.document_type.new_document( + file_object=file_object + ) + + def _request_workflow_transition(self, workflow_instance): + return self.post( + 'document_states:workflow_instance_transition', + args=(workflow_instance.pk,), data={ + 'transition': self.workflow_transition.pk, + } + ) + + def test_transition_workflow_no_permission(self): + self.login_user() + self._create_workflow() + self._create_workflow_states() + self._create_workflow_transitions() + self._create_document() + + workflow_instance = self.document_2.workflows.first() + + response = self._request_workflow_transition( + workflow_instance=workflow_instance + ) + + self.assertEqual(response.status_code, 200) + + # Workflow should remain in the same initial state + self.assertEqual( + workflow_instance.get_current_state(), self.workflow_initial_state + ) + + def test_transition_workflow_with_permission(self): + """ + Test transitioning a workflow by granting the transition workflow + permission to the role. + """ + + self.login_user() + self._create_workflow() + self._create_workflow_states() + self._create_workflow_transitions() + self._create_document() + + workflow_instance = self.document_2.workflows.first() + + self.grant(permission_workflow_transition) + response = self._request_workflow_transition( + workflow_instance=workflow_instance + ) + + self.assertEqual(response.status_code, 302) + + # Workflow should remain in the same initial state + self.assertEqual( + workflow_instance.get_current_state(), self.workflow_state + ) + + def test_transition_workflow_with_workflow_acl(self): + """ + Test transitioning a workflow by granting the transition workflow + permission to the workflow itself via ACL. + """ + + self.login_user() + self._create_workflow() + self._create_workflow_states() + self._create_workflow_transitions() + self._create_document() + + workflow_instance = self.document_2.workflows.first() + + acl = AccessControlList.objects.create( + content_object=self.workflow, role=self.role + ) + acl.permissions.add(permission_workflow_transition.stored_permission) + + response = self._request_workflow_transition( + workflow_instance=workflow_instance + ) + + self.assertEqual(response.status_code, 302) + + # Workflow should remain in the same initial state + self.assertEqual( + workflow_instance.get_current_state(), self.workflow_state + ) + + def test_transition_workflow_with_transition_acl(self): + """ + Test transitioning a workflow by granting the transition workflow + permission to the transition via ACL. + """ + + self.login_user() + self._create_workflow() + self._create_workflow_states() + self._create_workflow_transitions() + self._create_document() + + workflow_instance = self.document_2.workflows.first() + + acl = AccessControlList.objects.create( + content_object=self.workflow_transition, role=self.role + ) + acl.permissions.add(permission_workflow_transition.stored_permission) + + response = self._request_workflow_transition( + workflow_instance=workflow_instance + ) + + self.assertEqual(response.status_code, 302) + + # Workflow should remain in the same initial state + self.assertEqual( + workflow_instance.get_current_state(), self.workflow_state + ) diff --git a/mayan/apps/document_states/urls.py b/mayan/apps/document_states/urls.py index d612b28324..2194d26285 100644 --- a/mayan/apps/document_states/urls.py +++ b/mayan/apps/document_states/urls.py @@ -3,10 +3,10 @@ from __future__ import unicode_literals from django.conf.urls import patterns, url from .api_views import ( - APIWorkflowDocumentTypeList, APIWorkflowDocumentTypeView, - APIWorkflowInstanceListView, APIWorkflowInstanceView, - APIWorkflowInstanceLogEntryListView, APIWorkflowListView, - APIWorkflowStateListView, APIWorkflowStateView, + APIDocumentTypeWorkflowListView, APIWorkflowDocumentTypeList, + APIWorkflowDocumentTypeView, APIWorkflowInstanceListView, + APIWorkflowInstanceView, APIWorkflowInstanceLogEntryListView, + APIWorkflowListView, APIWorkflowStateListView, APIWorkflowStateView, APIWorkflowTransitionListView, APIWorkflowTransitionView, APIWorkflowView ) from .views import ( @@ -150,4 +150,9 @@ api_urls = [ APIWorkflowInstanceLogEntryListView.as_view(), name='workflowinstancelogentry-list' ), + url( + r'^document_type/(?P[0-9]+)/workflows/$', + APIDocumentTypeWorkflowListView.as_view(), + name='documenttype-workflow-list' + ), ] diff --git a/mayan/apps/document_states/views.py b/mayan/apps/document_states/views.py index 132212c8f0..d8cb69611b 100644 --- a/mayan/apps/document_states/views.py +++ b/mayan/apps/document_states/views.py @@ -7,12 +7,11 @@ from django.db.utils import IntegrityError from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404 from django.utils.translation import ugettext_lazy as _ -from django.views.generic import FormView from acls.models import AccessControlList from common.views import ( - AssignRemoveView, SingleObjectCreateView, SingleObjectDeleteView, - SingleObjectEditView, SingleObjectListView + AssignRemoveView, FormView, SingleObjectCreateView, + SingleObjectDeleteView, SingleObjectEditView, SingleObjectListView ) from documents.models import Document from documents.views import DocumentListView @@ -25,8 +24,7 @@ from .forms import ( from .models import Workflow, WorkflowInstance, WorkflowState, WorkflowTransition from .permissions import ( permission_workflow_create, permission_workflow_delete, - permission_workflow_edit, permission_workflow_transition, - permission_workflow_view, + permission_workflow_edit, permission_workflow_view, ) @@ -130,28 +128,10 @@ class WorkflowInstanceTransitionView(FormView): form_class = WorkflowInstanceTransitionForm template_name = 'appearance/generic_form.html' - def dispatch(self, request, *args, **kwargs): - try: - Permission.check_permissions( - request.user, (permission_workflow_transition,) - ) - except PermissionDenied: - AccessControlList.objects.check_access( - permission_workflow_transition, request.user, - self.get_workflow_instance().document - ) - - return super( - WorkflowInstanceTransitionView, self - ).dispatch(request, *args, **kwargs) - def form_valid(self, form): - transition = self.get_workflow_instance().workflow.transitions.get( - pk=form.cleaned_data['transition'] - ) self.get_workflow_instance().do_transition( - comment=form.cleaned_data['comment'], transition=transition, - user=self.request.user + comment=form.cleaned_data['comment'], + transition=form.cleaned_data['transition'], user=self.request.user ) return HttpResponseRedirect(self.get_success_url()) @@ -166,10 +146,11 @@ class WorkflowInstanceTransitionView(FormView): 'workflow_instance': self.get_workflow_instance(), } - def get_form_kwargs(self): - kwargs = super(WorkflowInstanceTransitionView, self).get_form_kwargs() - kwargs['workflow'] = self.get_workflow_instance() - return kwargs + def get_form_extra_kwargs(self): + return { + 'user': self.request.user, + 'workflow_instance': self.get_workflow_instance() + } def get_success_url(self): return self.get_workflow_instance().get_absolute_url()