GitLab Commit is coming up on August 3-4. Learn how to innovate together using GitLab, the DevOps platform. Register for free: gitlabcommitvirtual2021.com

Commit 7bc4941a authored by Roberto Rosario's avatar Roberto Rosario
Browse files

Refactor workflows app



- Rebalance permissions needed to transition a workflow instance.
  The workflow instance transition permission is now needed for
  the document and for either the transition or the workflow.
- Add more tests including trashed document tests.
- Split API tests into instance and template tests.
- Add `workflow-instance-log-entry-detail` end point.
- Add parent URL fields to serializers.
- Allow passing extra data when transitioning a workflow via the API.
- Limit state options to workflow when using the API. This matches
  the UI behavior.
Signed-off-by: Roberto Rosario's avatarRoberto Rosario <roberto.rosario@mayan-edms.com>
parent 0410f497
This diff is collapsed.
......@@ -20,7 +20,7 @@ from mayan.apps.navigation.classes import SourceColumn
from mayan.apps.views.html_widgets import TwoStateWidget
from .classes import DocumentStateHelper, WorkflowAction
from .events import event_workflow_edited
from .events import event_workflow_template_edited
from .handlers import (
handler_create_workflow_image_cache, handler_index_document,
handler_launch_workflow, handler_trigger_transition
......@@ -29,34 +29,37 @@ from .html_widgets import WorkflowLogExtraDataWidget, widget_transition_events
from .links import (
link_document_multiple_workflow_templates_launch,
link_document_single_workflow_templates_launch,
link_workflow_instance_list, link_document_type_workflow_templates,
link_workflow_template_document_types, link_workflow_template_create,
link_workflow_template_multiple_delete,
link_workflow_template_single_delete, link_workflow_template_edit,
link_workflow_template_launch, link_workflow_template_list,
link_tool_launch_workflows, link_workflow_instance_list,
link_workflow_instance_detail, link_workflow_instance_transition,
link_workflow_runtime_proxy_document_list,
link_workflow_runtime_proxy_list, link_workflow_template_preview,
link_workflow_runtime_proxy_state_document_list,
link_workflow_runtime_proxy_state_list,
link_document_type_workflow_templates, link_workflow_template_create,
link_workflow_template_document_types, link_workflow_template_edit,
link_workflow_template_multiple_delete, link_workflow_template_launch,
link_workflow_template_list, link_workflow_template_single_delete,
link_workflow_template_state_list,
link_workflow_template_state_action_delete,
link_workflow_template_state_action_edit,
link_workflow_template_state_action_list,
link_workflow_template_state_action_selection,
link_workflow_template_state_create, link_workflow_template_state_delete,
link_workflow_template_state_edit, link_workflow_template_transition_list,
link_workflow_template_state_edit,
link_workflow_template_transition_create,
link_workflow_template_transition_delete, link_workflow_template_transition_edit,
link_workflow_template_transition_delete,
link_workflow_template_transition_edit,
link_workflow_template_transition_list,
link_workflow_template_transition_events,
link_workflow_template_transition_field_create,
link_workflow_template_transition_field_delete,
link_workflow_template_transition_field_edit,
link_workflow_template_transition_field_list,
link_tool_launch_workflows, link_workflow_instance_detail,
link_workflow_instance_transition, link_workflow_runtime_proxy_document_list,
link_workflow_runtime_proxy_list, link_workflow_template_preview,
link_workflow_runtime_proxy_state_document_list, link_workflow_runtime_proxy_state_list,
link_workflow_template_transition_events
link_workflow_template_transition_field_list
)
from .permissions import (
permission_workflow_delete, permission_workflow_edit,
permission_workflow_tools, permission_workflow_transition,
permission_workflow_view
permission_workflow_template_delete, permission_workflow_template_edit,
permission_workflow_tools, permission_workflow_instance_transition,
permission_workflow_template_view
)
......@@ -159,7 +162,7 @@ class DocumentStatesApp(MayanAppConfig):
)
ModelEventType.register(
event_types=(event_workflow_edited,), model=Workflow
event_types=(event_workflow_template_edited,), model=Workflow
)
ModelProperty(
......@@ -180,19 +183,22 @@ class DocumentStatesApp(MayanAppConfig):
ModelPermission.register(
model=Document, permissions=(
permission_workflow_tools, permission_workflow_view,
permission_workflow_instance_transition,
permission_workflow_template_view,
permission_workflow_tools
)
)
ModelPermission.register(
model=Workflow, permissions=(
permission_error_log_view, permission_workflow_delete,
permission_workflow_edit, permission_workflow_tools,
permission_workflow_transition, permission_workflow_view
permission_error_log_view, permission_workflow_template_delete,
permission_workflow_template_edit, permission_workflow_tools,
permission_workflow_instance_transition,
permission_workflow_template_view
)
)
ModelPermission.register(
model=WorkflowTransition,
permissions=(permission_workflow_transition,)
permissions=(permission_workflow_instance_transition,)
)
ModelPermission.register_inheritance(
......
......@@ -6,9 +6,9 @@ namespace = EventTypeNamespace(
label=_('Workflows'), name='document_states'
)
event_workflow_created = namespace.add_event_type(
event_workflow_template_created = namespace.add_event_type(
label=_('Workflow created'), name='workflow_created'
)
event_workflow_edited = namespace.add_event_type(
event_workflow_template_edited = namespace.add_event_type(
label=_('Workflow edited'), name='workflow_edited'
)
......@@ -8,7 +8,7 @@ icon_tool_launch_workflows = Icon(
secondary_symbol='play'
)
icon_document_workflow_templates_launch = icon_tool_launch_workflows
icon_document_type_workflow_list = icon_workflow
icon_document_type_workflow_template_list = icon_workflow
icon_workflow_template_create = Icon(
driver_name='fontawesome-dual', primary_symbol='sitemap',
secondary_symbol='plus'
......@@ -43,76 +43,76 @@ icon_workflow_runtime_proxy_state_list = Icon(
# Workflow transition states
icon_workflow_state_action_delete = Icon(
icon_workflow_template_state_action_delete = Icon(
driver_name='fontawesome', symbol='times'
)
icon_workflow_state_action_edit = Icon(
icon_workflow_template_state_action_edit = Icon(
driver_name='fontawesome', symbol='pencil-alt'
)
icon_workflow_state_action_list = Icon(
icon_workflow_template_state_action_list = Icon(
driver_name='fontawesome', symbol='code'
)
icon_workflow_state = Icon(driver_name='fontawesome', symbol='circle')
icon_workflow_state_create = Icon(
icon_workflow_template_state = Icon(driver_name='fontawesome', symbol='circle')
icon_workflow_template_state_create = Icon(
driver_name='fontawesome-dual', primary_symbol='circle',
secondary_symbol='plus'
)
icon_workflow_state_delete = Icon(driver_name='fontawesome', symbol='times')
icon_workflow_state_edit = Icon(
icon_workflow_template_state_delete = Icon(driver_name='fontawesome', symbol='times')
icon_workflow_template_state_edit = Icon(
driver_name='fontawesome', symbol='pencil-alt'
)
# Workflow transition state actions
icon_workflow_state_action = Icon(driver_name='fontawesome', symbol='code')
icon_workflow_state_action_delete = Icon(
icon_workflow_template_state_action = Icon(driver_name='fontawesome', symbol='code')
icon_workflow_template_state_action_delete = Icon(
driver_name='fontawesome', symbol='times'
)
icon_workflow_state_action_edit = Icon(
icon_workflow_template_state_action_edit = Icon(
driver_name='fontawesome', symbol='pencil-alt'
)
icon_workflow_state_action_selection = Icon(
icon_workflow_template_state_action_selection = Icon(
driver_name='fontawesome-dual', primary_symbol='code',
secondary_symbol='plus'
)
icon_workflow_state_action_list = Icon(
icon_workflow_template_state_action_list = Icon(
driver_name='fontawesome', symbol='code'
)
# Workflow transitions
icon_workflow_transition = Icon(
icon_workflow_template_transition = Icon(
driver_name='fontawesome', symbol='arrows-alt-h'
)
icon_workflow_transition_create = Icon(
icon_workflow_template_transition_create = Icon(
driver_name='fontawesome-dual', primary_symbol='arrows-alt-h',
secondary_symbol='plus'
)
icon_workflow_transition_delete = Icon(
icon_workflow_template_transition_delete = Icon(
driver_name='fontawesome', symbol='times'
)
icon_workflow_transition_edit = Icon(
icon_workflow_template_transition_edit = Icon(
driver_name='fontawesome', symbol='pencil-alt'
)
# Workflow transition fields
icon_workflow_transition_field = Icon(
icon_workflow_template_transition_field = Icon(
driver_name='fontawesome', symbol='table'
)
icon_workflow_transition_field_delete = Icon(
icon_workflow_template_transition_field_delete = Icon(
driver_name='fontawesome', symbol='times'
)
icon_workflow_transition_field_edit = Icon(
icon_workflow_template_transition_field_edit = Icon(
driver_name='fontawesome', symbol='pencil-alt'
)
icon_workflow_transition_field_create = Icon(
icon_workflow_template_transition_field_create = Icon(
driver_name='fontawesome-dual', primary_symbol='table',
secondary_symbol='plus'
)
icon_workflow_transition_field_list = Icon(
icon_workflow_template_transition_field_list = Icon(
driver_name='fontawesome', symbol='table'
)
icon_workflow_transition_triggers = Icon(
icon_workflow_template_transition_triggers = Icon(
driver_name='fontawesome', symbol='bolt'
)
......@@ -5,44 +5,50 @@ from mayan.apps.navigation.classes import Link
from mayan.apps.navigation.utils import get_cascade_condition
from .icons import (
icon_document_type_workflow_list, icon_document_workflow_templates_launch,
icon_workflow_template_create, icon_workflow_template_delete,
icon_workflow_template_document_type_list,
icon_workflow_template_edit, icon_workflow_template_launch,
icon_workflow_template_list, icon_workflow_template_preview,
icon_workflow_state, icon_workflow_state_action,
icon_workflow_state_action_delete, icon_workflow_state_action_edit,
icon_workflow_state_action_list, icon_workflow_state_create,
icon_workflow_state_delete, icon_workflow_state_edit,
icon_workflow_transition, icon_workflow_transition_create,
icon_workflow_transition_delete, icon_workflow_transition_edit,
icon_workflow_transition_triggers, icon_workflow_transition_field,
icon_workflow_transition_field_delete,
icon_workflow_transition_field_edit, icon_workflow_transition_field_list,
icon_workflow_instance_detail, icon_workflow_instance_list,
icon_workflow_instance_transition,
icon_workflow_runtime_proxy_document_list,
icon_workflow_runtime_proxy_list,
icon_workflow_runtime_proxy_state_document_list,
icon_workflow_runtime_proxy_state_list, icon_tool_launch_workflows
icon_workflow_runtime_proxy_state_list,
icon_tool_launch_workflows, icon_document_type_workflow_template_list,
icon_workflow_template_create, icon_workflow_template_delete,
icon_workflow_template_document_type_list, icon_workflow_template_edit,
icon_workflow_template_launch, icon_workflow_template_list,
icon_workflow_template_preview, icon_workflow_template_state,
icon_workflow_template_state_action,
icon_workflow_template_state_action_delete,
icon_workflow_template_state_action_edit,
icon_workflow_template_state_action_list,
icon_workflow_template_state_create, icon_workflow_template_state_delete,
icon_workflow_template_state_edit, icon_workflow_template_transition,
icon_workflow_template_transition_create,
icon_workflow_template_transition_delete,
icon_workflow_template_transition_edit,
icon_workflow_template_transition_triggers,
icon_workflow_template_transition_field,
icon_workflow_template_transition_field_delete,
icon_workflow_template_transition_field_edit,
icon_workflow_template_transition_field_list,
icon_document_workflow_templates_launch,
)
from .permissions import (
permission_workflow_create, permission_workflow_delete,
permission_workflow_edit, permission_workflow_tools,
permission_workflow_view,
permission_workflow_template_create, permission_workflow_template_delete,
permission_workflow_template_edit, permission_workflow_tools,
permission_workflow_template_view,
)
# Workflow templates
link_document_type_workflow_templates = Link(
args='resolved_object.pk',
icon=icon_document_type_workflow_list,
icon=icon_document_type_workflow_template_list,
permissions=(permission_document_type_edit,), text=_('Workflows'),
view='document_states:document_type_workflow_templates',
)
link_workflow_template_create = Link(
icon=icon_workflow_template_create,
permissions=(permission_workflow_create,),
permissions=(permission_workflow_template_create,),
text=_('Create workflow'), view='document_states:workflow_template_create'
)
link_workflow_template_multiple_delete = Link(
......@@ -53,20 +59,20 @@ link_workflow_template_multiple_delete = Link(
link_workflow_template_single_delete = Link(
args='resolved_object.pk',
icon=icon_workflow_template_delete,
permissions=(permission_workflow_delete,),
permissions=(permission_workflow_template_delete,),
tags='dangerous', text=_('Delete'),
view='document_states:workflow_template_single_delete',
)
link_workflow_template_document_types = Link(
args='resolved_object.pk',
icon=icon_workflow_template_document_type_list,
permissions=(permission_workflow_edit,), text=_('Document types'),
permissions=(permission_workflow_template_edit,), text=_('Document types'),
view='document_states:workflow_template_document_types',
)
link_workflow_template_edit = Link(
args='resolved_object.pk',
icon=icon_workflow_template_edit,
permissions=(permission_workflow_edit,),
permissions=(permission_workflow_template_edit,),
text=_('Edit'), view='document_states:workflow_template_edit',
)
link_workflow_template_launch = Link(
......@@ -78,13 +84,13 @@ link_workflow_template_launch = Link(
)
link_workflow_template_list = Link(
icon=icon_workflow_template_list,
permissions=(permission_workflow_view,), text=_('Workflows'),
permissions=(permission_workflow_template_view,), text=_('Workflows'),
view='document_states:workflow_template_list'
)
link_workflow_template_preview = Link(
args='resolved_object.pk',
icon=icon_workflow_template_preview,
permissions=(permission_workflow_view,),
permissions=(permission_workflow_template_view,),
text=_('Preview'), view='document_states:workflow_template_preview'
)
......@@ -92,28 +98,28 @@ link_workflow_template_preview = Link(
link_workflow_template_state_action_delete = Link(
args='resolved_object.pk',
icon=icon_workflow_state_action_delete,
permissions=(permission_workflow_edit,),
icon=icon_workflow_template_state_action_delete,
permissions=(permission_workflow_template_edit,),
tags='dangerous', text=_('Delete'),
view='document_states:workflow_template_state_action_delete',
)
link_workflow_template_state_action_edit = Link(
args='resolved_object.pk',
icon=icon_workflow_state_action_edit,
permissions=(permission_workflow_edit,),
icon=icon_workflow_template_state_action_edit,
permissions=(permission_workflow_template_edit,),
text=_('Edit'), view='document_states:workflow_template_state_action_edit',
)
link_workflow_template_state_action_list = Link(
args='resolved_object.pk',
icon=icon_workflow_state_action_list,
permissions=(permission_workflow_edit,),
icon=icon_workflow_template_state_action_list,
permissions=(permission_workflow_template_edit,),
text=_('Actions'),
view='document_states:workflow_template_state_action_list',
)
link_workflow_template_state_action_selection = Link(
args='resolved_object.pk',
icon=icon_workflow_state_action,
permissions=(permission_workflow_edit,), text=_('Create action'),
icon=icon_workflow_template_state_action,
permissions=(permission_workflow_template_edit,), text=_('Create action'),
view='document_states:workflow_template_state_action_selection',
)
......@@ -121,27 +127,27 @@ link_workflow_template_state_action_selection = Link(
link_workflow_template_state_create = Link(
args='workflow.pk',
icon=icon_workflow_state_create,
permissions=(permission_workflow_edit,), text=_('Create state'),
icon=icon_workflow_template_state_create,
permissions=(permission_workflow_template_edit,), text=_('Create state'),
view='document_states:workflow_template_state_create',
)
link_workflow_template_state_delete = Link(
args='resolved_object.pk',
icon=icon_workflow_state_delete,
permissions=(permission_workflow_edit,),
icon=icon_workflow_template_state_delete,
permissions=(permission_workflow_template_edit,),
tags='dangerous', text=_('Delete'),
view='document_states:workflow_template_state_delete',
)
link_workflow_template_state_edit = Link(
args='resolved_object.pk',
icon=icon_workflow_state_edit,
permissions=(permission_workflow_edit,),
icon=icon_workflow_template_state_edit,
permissions=(permission_workflow_template_edit,),
text=_('Edit'), view='document_states:workflow_template_state_edit',
)
link_workflow_template_state_list = Link(
args='resolved_object.pk',
icon=icon_workflow_state,
permissions=(permission_workflow_view,), text=_('States'),
icon=icon_workflow_template_state,
permissions=(permission_workflow_template_view,), text=_('States'),
view='document_states:workflow_template_state_list',
)
......@@ -149,34 +155,34 @@ link_workflow_template_state_list = Link(
link_workflow_template_transition_create = Link(
args='workflow.pk',
icon=icon_workflow_transition_create,
permissions=(permission_workflow_edit,), text=_('Create transition'),
icon=icon_workflow_template_transition_create,
permissions=(permission_workflow_template_edit,), text=_('Create transition'),
view='document_states:workflow_template_transition_create',
)
link_workflow_template_transition_delete = Link(
args='resolved_object.pk',
icon=icon_workflow_transition_delete,
permissions=(permission_workflow_edit,),
icon=icon_workflow_template_transition_delete,
permissions=(permission_workflow_template_edit,),
tags='dangerous', text=_('Delete'),
view='document_states:workflow_template_transition_delete',
)
link_workflow_template_transition_edit = Link(
args='resolved_object.pk',
icon=icon_workflow_transition_edit,
permissions=(permission_workflow_edit,),
icon=icon_workflow_template_transition_edit,
permissions=(permission_workflow_template_edit,),
text=_('Edit'), view='document_states:workflow_template_transition_edit',
)
link_workflow_template_transition_events = Link(
args='resolved_object.pk',
icon=icon_workflow_transition_triggers,
permissions=(permission_workflow_edit,),
icon=icon_workflow_template_transition_triggers,
permissions=(permission_workflow_template_edit,),
text=_('Transition triggers'),
view='document_states:workflow_template_transition_events'
)
link_workflow_template_transition_list = Link(
args='resolved_object.pk',
icon=icon_workflow_transition,
permissions=(permission_workflow_view,), text=_('Transitions'),
icon=icon_workflow_template_transition,
permissions=(permission_workflow_template_view,), text=_('Transitions'),
view='document_states:workflow_template_transition_list',
)
......@@ -195,27 +201,27 @@ link_document_single_workflow_templates_launch = Link(
)
link_workflow_template_transition_field_create = Link(
args='resolved_object.pk',
icon=icon_workflow_transition_field,
permissions=(permission_workflow_edit,), text=_('Create field'),
icon=icon_workflow_template_transition_field,
permissions=(permission_workflow_template_edit,), text=_('Create field'),
view='document_states:workflow_template_transition_field_create',
)
link_workflow_template_transition_field_delete = Link(
args='resolved_object.pk',
icon=icon_workflow_transition_field_delete,
permissions=(permission_workflow_edit,),
icon=icon_workflow_template_transition_field_delete,
permissions=(permission_workflow_template_edit,),
tags='dangerous', text=_('Delete'),
view='document_states:workflow_template_transition_field_delete',
)
link_workflow_template_transition_field_edit = Link(
args='resolved_object.pk',
icon=icon_workflow_transition_field_edit,
permissions=(permission_workflow_edit,),
icon=icon_workflow_template_transition_field_edit,
permissions=(permission_workflow_template_edit,),
text=_('Edit'), view='document_states:workflow_template_transition_field_edit',
)
link_workflow_template_transition_field_list = Link(
args='resolved_object.pk',
icon=icon_workflow_transition_field_list,
permissions=(permission_workflow_edit,),
icon=icon_workflow_template_transition_field_list,
permissions=(permission_workflow_template_edit,),
text=_('Fields'),
view='document_states:workflow_template_transition_field_list',
)
......@@ -225,13 +231,13 @@ link_workflow_template_transition_field_list = Link(
link_workflow_instance_detail = Link(
args='resolved_object.pk',
icon=icon_workflow_instance_detail,
permissions=(permission_workflow_view,),
permissions=(permission_workflow_template_view,),
text=_('Detail'), view='document_states:workflow_instance_detail',
)
link_workflow_instance_list = Link(
args='resolved_object.pk',
icon=icon_workflow_instance_list,
permissions=(permission_workflow_view,), text=_('Workflows'),
permissions=(permission_workflow_template_view,), text=_('Workflows'),
view='document_states:workflow_instance_list',
)
link_workflow_instance_transition = Link(
......@@ -246,28 +252,28 @@ link_workflow_instance_transition = Link(
link_workflow_runtime_proxy_document_list = Link(
args='resolved_object.pk',
icon=icon_workflow_runtime_proxy_document_list,
permissions=(permission_workflow_view,),
permissions=(permission_workflow_template_view,),
text=_('Workflow documents'),
view='document_states:workflow_runtime_proxy_document_list',
)
link_workflow_runtime_proxy_list = Link(
condition=get_cascade_condition(
app_label='document_states', model_name='WorkflowRuntimeProxy',
object_permission=permission_workflow_view,
object_permission=permission_workflow_template_view,
), icon=icon_workflow_runtime_proxy_list,
text=_('Workflows'), view='document_states:workflow_runtime_proxy_list'
)
link_workflow_runtime_proxy_state_document_list = Link(
args='resolved_object.pk',
icon=icon_workflow_runtime_proxy_state_document_list,
permissions=(permission_workflow_view,),
permissions=(permission_workflow_template_view,),
text=_('State documents'),
view='document_states:workflow_runtime_proxy_state_document_list',
)
link_workflow_runtime_proxy_state_list = Link(
args='resolved_object.pk',
icon=icon_workflow_runtime_proxy_state_list,
permissions=(permission_workflow_view,),
permissions=(permission_workflow_template_view,),
text=_('States'), view='document_states:workflow_runtime_proxy_state_list',
)
......
......@@ -2,8 +2,8 @@ import json
import logging
from django.conf import settings
from django.core.exceptions import PermissionDenied, ValidationError
from django.db import models, transaction
from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
......@@ -12,7 +12,7 @@ from mayan.apps.acls.models import AccessControlList
from mayan.apps.documents.models import Document
from ..managers import ValidWorkflowInstanceManager
from ..permissions import permission_workflow_transition
from ..permissions import permission_workflow_instance_transition
from .workflow_models import Workflow
from .workflow_transition_models import (
......@@ -51,23 +51,22 @@ class WorkflowInstance(models.Model):
def do_transition(
self, transition, comment=None, extra_data=None, user=None
):
with transaction.atomic():
try:
if transition in self.get_current_state().origin_transitions.all():
if extra_data:
context = self.loads()
context.update(extra_data)
self.dumps(context=context)
self.log_entries.create(
comment=comment or '',
extra_data=json.dumps(obj=extra_data or {}),
transition=transition, user=user
)
except AttributeError:
# No initial state has been set for this workflow
if settings.DEBUG:
raise
try:
if transition in self.get_transition_choices(_user=user).all():
if extra_data:
context = self.loads()
context.update(extra_data)
self.dumps(context=context)
return self.log_entries.create(
comment=comment or '',
extra_data=json.dumps(obj=extra_data or {}),
transition=transition, user=user
)
except AttributeError:
# No initial state has been set for this workflow
if settings.DEBUG:
raise