Convert workflow document types to AddRemove view

Add worflow created and edited events.

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
Roberto Rosario
2019-05-04 20:47:21 -04:00
parent 9c92b9a59e
commit 3d240a7f42
6 changed files with 148 additions and 64 deletions

View File

@@ -223,6 +223,9 @@
* Remove mayan_permission_attribute_check from
API permission.
* Update Bootstrap and Bootswatch to version 3.4.1.
* Convert the workflow document types view to use
the new AddRemove view.
* Add the workflow created and edited events.
3.1.11 (2019-04-XX)
===================

View File

@@ -256,6 +256,9 @@ Other changes
* Remove mayan_permission_attribute_check from
API permission.
* Update Bootstrap and Bootswatch to version 3.4.1.
* Convert the workflow document types view to use
the new AddRemove view.
* Add the workflow created and edited events.
Removals
--------

View File

@@ -17,10 +17,15 @@ from mayan.apps.common.menus import (
menu_setup, menu_tools
)
from mayan.apps.common.permissions_runtime import permission_error_log_view
from mayan.apps.events.classes import ModelEventType
from mayan.apps.events.links import (
link_events_for_object, link_object_event_types_user_subcriptions_list
)
from mayan.apps.navigation.classes import SourceColumn
from mayan.celery import app
from .classes import DocumentStateHelper, WorkflowAction
from .events import event_workflow_created, event_workflow_edited
from .dependencies import * # NOQA
from .handlers import (
handler_index_document, handler_launch_workflow, handler_trigger_transition
@@ -61,6 +66,7 @@ class DocumentStatesApp(MayanAppConfig):
def ready(self):
super(DocumentStatesApp, self).ready()
from actstream import registry
Action = apps.get_model(
app_label='actstream', model_name='Action'
@@ -107,6 +113,13 @@ class DocumentStatesApp(MayanAppConfig):
'selected workflow'
)
)
ModelEventType.register(
event_types=(
event_workflow_created, event_workflow_edited
), model=Workflow
)
ModelPermission.register(
model=Document, permissions=(permission_workflow_view,)
)
@@ -260,9 +273,11 @@ class DocumentStatesApp(MayanAppConfig):
)
menu_list_facet.bind_links(
links=(
link_acl_list, link_events_for_object,
link_object_event_types_user_subcriptions_list,
link_setup_workflow_document_types,
link_setup_workflow_states, link_setup_workflow_transitions,
link_workflow_preview, link_acl_list
link_workflow_preview
), sources=(Workflow,)
)
menu_main.bind_links(links=(link_workflow_runtime_proxy_list,), position=10)
@@ -369,3 +384,5 @@ class DocumentStatesApp(MayanAppConfig):
receiver=handler_trigger_transition,
sender=Action
)
registry.register(Workflow)

View File

@@ -0,0 +1,16 @@
from __future__ import absolute_import, unicode_literals
from django.utils.translation import ugettext_lazy as _
from mayan.apps.events.classes import EventTypeNamespace
namespace = EventTypeNamespace(
label=_('Workflows'), name='document_states'
)
event_workflow_created = namespace.add_event_type(
label=_('Workflow created'), name='workflow_created'
)
event_workflow_edited = namespace.add_event_type(
label=_('Workflow edited'), name='workflow_edited'
)

View File

@@ -7,7 +7,7 @@ from graphviz import Digraph
from django.conf import settings
from django.core.exceptions import PermissionDenied, ValidationError
from django.db import IntegrityError, models
from django.db import IntegrityError, models, transaction
from django.db.models import F, Max, Q
from django.urls import reverse
from django.utils.encoding import force_text, python_2_unicode_compatible
@@ -20,6 +20,7 @@ from mayan.apps.documents.models import Document, DocumentType
from mayan.apps.events.models import StoredEventType
from .error_logs import error_log_state_actions
from .events import event_workflow_created, event_workflow_edited
from .literals import (
WORKFLOW_ACTION_WHEN_CHOICES, WORKFLOW_ACTION_ON_ENTRY,
WORKFLOW_ACTION_ON_EXIT
@@ -133,6 +134,21 @@ class Workflow(models.Model):
return diagram.pipe()
def save(self, *args, **kwargs):
_user = kwargs.pop('_user', None)
with transaction.atomic():
is_new = not self.pk
super(Workflow, self).save(*args, **kwargs)
if is_new:
event_workflow_created.commit(
actor=_user, target=self
)
else:
event_workflow_edited.commit(
actor=_user, target=self
)
@python_2_unicode_compatible
class WorkflowState(models.Model):

View File

@@ -12,15 +12,19 @@ from django.utils.translation import ugettext_lazy as _
from mayan.apps.acls.models import AccessControlList
from mayan.apps.common.generics import (
AssignRemoveView, ConfirmView, FormView, SingleObjectCreateView,
AddRemoveView, ConfirmView, FormView, SingleObjectCreateView,
SingleObjectDeleteView, SingleObjectDetailView,
SingleObjectDynamicFormCreateView, SingleObjectDynamicFormEditView,
SingleObjectDownloadView, SingleObjectEditView, SingleObjectListView
)
from mayan.apps.documents.events import event_document_type_edited
from mayan.apps.documents.models import DocumentType
from mayan.apps.documents.permissions import permission_document_type_edit
from mayan.apps.events.classes import EventType
from mayan.apps.events.models import StoredEventType
from ..classes import WorkflowAction
from ..events import event_workflow_edited
from ..forms import (
WorkflowActionSelectionForm, WorkflowForm, WorkflowPreviewForm,
WorkflowStateActionDynamicForm, WorkflowStateForm, WorkflowTransitionForm,
@@ -86,37 +90,51 @@ class SetupWorkflowListView(SingleObjectListView):
class SetupWorkflowCreateView(SingleObjectCreateView):
form_class = WorkflowForm
model = Workflow
post_action_redirect = reverse_lazy('document_states:setup_workflow_list')
post_action_redirect = reverse_lazy(
viewname='document_states:setup_workflow_list'
)
view_permission = permission_workflow_create
def get_actions_extra_kwargs(self):
return {'_user': self.request.user}
class SetupWorkflowEditView(SingleObjectEditView):
form_class = WorkflowForm
model = Workflow
object_permission = permission_workflow_edit
post_action_redirect = reverse_lazy('document_states:setup_workflow_list')
post_action_redirect = reverse_lazy(
viewname='document_states:setup_workflow_list'
)
def get_actions_extra_kwargs(self):
return {'_user': self.request.user}
class SetupWorkflowDeleteView(SingleObjectDeleteView):
model = Workflow
object_permission = permission_workflow_delete
post_action_redirect = reverse_lazy('document_states:setup_workflow_list')
post_action_redirect = reverse_lazy(
viewname='document_states:setup_workflow_list'
)
class SetupWorkflowDocumentTypesView(AssignRemoveView):
decode_content_type = True
left_list_title = _('Available document types')
object_permission = permission_workflow_edit
right_list_title = _('Document types assigned this workflow')
class SetupWorkflowDocumentTypesView(AddRemoveView):
main_object_permission = permission_workflow_edit
main_object_model = Workflow
main_object_pk_url_kwarg = 'pk'
secondary_object_model = DocumentType
secondary_object_permission = permission_document_type_edit
list_available_title = _('Available document types')
list_added_title = _('Document types assigned this workflow')
related_field = 'document_types'
def add(self, item):
self.get_object().document_types.add(item)
# TODO: add task launching this workflow for all the document types
# of item
def get_actions_extra_kwargs(self):
return {'_user': self.request.user}
def get_extra_context(self):
return {
'object': self.get_object(),
'object': self.main_object,
'subtitle': _(
'Removing a document type from a workflow will also '
'remove all running instances of that workflow for '
@@ -124,28 +142,36 @@ class SetupWorkflowDocumentTypesView(AssignRemoveView):
),
'title': _(
'Document types assigned the workflow: %s'
) % self.get_object(),
) % self.main_object,
}
def get_object(self):
return get_object_or_404(klass=Workflow, pk=self.kwargs['pk'])
def left_list(self):
return AssignRemoveView.generate_choices(
self.get_object().get_document_types_not_in_workflow()
)
def right_list(self):
return AssignRemoveView.generate_choices(
self.get_object().document_types.all()
)
def remove(self, item):
# When removing a document type to workflow association
# also remove all running workflows in documents of that type.
def action_add(self, queryset, _user):
with transaction.atomic():
self.get_object().document_types.remove(item)
self.get_object().instances.filter(document__document_type=item).delete()
event_workflow_edited.commit(
actor=_user, target=self.main_object
)
for obj in queryset:
self.main_object.document_types.add(obj)
event_document_type_edited.commit(
action_object=self.main_object, actor=_user, target=obj
)
def action_remove(self, queryset, _user):
with transaction.atomic():
event_workflow_edited.commit(
actor=_user, target=self.main_object
)
for obj in queryset:
self.main_object.document_types.remove(obj)
event_document_type_edited.commit(
action_object=self.main_object, actor=_user,
target=obj
)
self.main_object.instances.filter(
document__document_type=obj
).delete()
# Workflow state actions
@@ -193,8 +219,8 @@ class SetupWorkflowStateActionCreateView(SingleObjectDynamicFormCreateView):
def get_post_action_redirect(self):
return reverse(
'document_states:setup_workflow_state_action_list',
args=(self.get_object().pk,)
viewname='document_states:setup_workflow_state_action_list',
kwargs={'pk': self.get_object().pk}
)
@@ -215,8 +241,8 @@ class SetupWorkflowStateActionDeleteView(SingleObjectDeleteView):
def get_post_action_redirect(self):
return reverse(
'document_states:setup_workflow_state_action_list',
args=(self.get_object().state.pk,)
viewname='document_states:setup_workflow_state_action_list',
kwargs={'pk': self.get_object().state.pk}
)
@@ -249,8 +275,8 @@ class SetupWorkflowStateActionEditView(SingleObjectDynamicFormEditView):
def get_post_action_redirect(self):
return reverse(
'document_states:setup_workflow_state_action_list',
args=(self.get_object().state.pk,)
viewname='document_states:setup_workflow_state_action_list',
kwargs={'pk': self.get_object().state.pk}
)
@@ -300,9 +326,9 @@ class SetupWorkflowStateActionSelectionView(FormView):
def form_valid(self, form):
klass = form.cleaned_data['klass']
return HttpResponseRedirect(
reverse(
'document_states:setup_workflow_state_action_create',
args=(self.get_object().pk, klass,),
redirect_to=reverse(
viewname='document_states:setup_workflow_state_action_create',
kwargs={'pk': self.get_object().pk, 'class_path': klass}
)
)
@@ -339,7 +365,9 @@ class SetupWorkflowStateCreateView(SingleObjectCreateView):
def get_success_url(self):
return reverse(
'document_states:setup_workflow_state_list', args=(self.kwargs['pk'],)
viewname='document_states:setup_workflow_state_list', kwargs={
'pk': self.kwargs['pk']
}
)
def get_workflow(self):
@@ -373,8 +401,8 @@ class SetupWorkflowStateDeleteView(SingleObjectDeleteView):
def get_success_url(self):
return reverse(
'document_states:setup_workflow_state_list',
args=(self.get_object().workflow.pk,)
viewname='document_states:setup_workflow_state_list',
kwargs={'pk': self.get_object().workflow.pk}
)
def get_workflow(self):
@@ -400,8 +428,8 @@ class SetupWorkflowStateEditView(SingleObjectEditView):
def get_success_url(self):
return reverse(
'document_states:setup_workflow_state_list',
args=(self.get_object().workflow.pk,)
viewname='document_states:setup_workflow_state_list',
kwargs={'pk': self.get_object().workflow.pk}
)
@@ -457,7 +485,8 @@ class SetupWorkflowTransitionCreateView(SingleObjectCreateView):
self.object.save()
except IntegrityError:
messages.error(
self.request, _('Unable to save transition; integrity error.')
message=_('Unable to save transition; integrity error.'),
request=self.request
)
return super(
SetupWorkflowTransitionCreateView, self
@@ -485,8 +514,8 @@ class SetupWorkflowTransitionCreateView(SingleObjectCreateView):
def get_success_url(self):
return reverse(
'document_states:setup_workflow_transition_list',
args=(self.kwargs['pk'],)
viewname='document_states:setup_workflow_transition_list',
kwargs={'pk': self.kwargs['pk']}
)
def get_workflow(self):
@@ -511,8 +540,8 @@ class SetupWorkflowTransitionDeleteView(SingleObjectDeleteView):
def get_success_url(self):
return reverse(
'document_states:setup_workflow_transition_list',
args=(self.get_object().workflow.pk,)
viewname='document_states:setup_workflow_transition_list',
kwargs={'pk': self.get_object().workflow.pk}
)
@@ -537,8 +566,8 @@ class SetupWorkflowTransitionEditView(SingleObjectEditView):
def get_success_url(self):
return reverse(
'document_states:setup_workflow_transition_list',
args=(self.get_object().workflow.pk,)
viewname='document_states:setup_workflow_transition_list',
kwargs={'pk': self.get_object().workflow.pk}
)
@@ -596,16 +625,15 @@ class SetupWorkflowTransitionTriggerEventListView(FormView):
instance.save()
except Exception as exception:
messages.error(
self.request,
_(
message=_(
'Error updating workflow transition trigger events; %s'
) % exception
) % exception, request=self.request
)
else:
messages.success(
self.request, _(
message=_(
'Workflow transition trigger events updated successfully'
)
), request=self.request
)
return super(
@@ -649,8 +677,8 @@ class SetupWorkflowTransitionTriggerEventListView(FormView):
def get_post_action_redirect(self):
return reverse(
'document_states:setup_workflow_transition_list',
args=(self.get_object().workflow.pk,)
viewname='document_states:setup_workflow_transition_list',
kwargs={'pk': self.get_object().workflow.pk}
)
@@ -667,7 +695,8 @@ class ToolLaunchAllWorkflows(ConfirmView):
def view_action(self):
task_launch_all_workflows.apply_async()
messages.success(
self.request, _('Workflow launch queued successfully.')
message=_('Workflow launch queued successfully.'),
request=self.request
)