From 3d39893f17c86653ff7714b4ca9aed8069a2d2e1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 24 Jun 2019 23:03:06 -0400 Subject: [PATCH] Add columns to show document count per workflow Signed-off-by: Roberto Rosario --- CHANGES.rst | 3 + mayan/apps/document_states/apps.py | 13 +++++ mayan/apps/document_states/models.py | 22 +++++++ mayan/apps/navigation/classes.py | 85 +++++++++++++++------------- 4 files changed, 85 insertions(+), 38 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 4b9346f9a9..6d209570c9 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1 +1,4 @@ - Use Select2 widget for the document type selection form. +- Update source column matching to be additive and not exclusive. +- Add two columns to show the number of documents per workflow and + workflow state. diff --git a/mayan/apps/document_states/apps.py b/mayan/apps/document_states/apps.py index f49310b836..dff0c11b27 100644 --- a/mayan/apps/document_states/apps.py +++ b/mayan/apps/document_states/apps.py @@ -256,6 +256,19 @@ class DocumentStatesApp(MayanAppConfig): ) ) + SourceColumn( + source=WorkflowRuntimeProxy, label=_('Documents'), + func=lambda context: context['object'].get_document_count( + user=context['request'].user + ), order=99 + ) + SourceColumn( + source=WorkflowStateRuntimeProxy, label=_('Documents'), + func=lambda context: context['object'].get_document_count( + user=context['request'].user + ), order=99 + ) + menu_facet.bind_links( links=(link_document_workflow_instance_list,), sources=(Document,) ) diff --git a/mayan/apps/document_states/models.py b/mayan/apps/document_states/models.py index 5a5336ee91..ccfeec72a0 100644 --- a/mayan/apps/document_states/models.py +++ b/mayan/apps/document_states/models.py @@ -17,6 +17,7 @@ from django.utils.translation import ugettext_lazy as _ from mayan.apps.acls.models import AccessControlList from mayan.apps.common.validators import validate_internal_name from mayan.apps.documents.models import Document, DocumentType +from mayan.apps.documents.permissions import permission_document_view from mayan.apps.events.models import StoredEventType from .error_logs import error_log_state_actions @@ -531,9 +532,30 @@ class WorkflowRuntimeProxy(Workflow): verbose_name = _('Workflow runtime proxy') verbose_name_plural = _('Workflow runtime proxies') + def get_document_count(self, user): + """ + Return the numeric count of documents executing this workflow. + The count is filtered by access. + """ + return AccessControlList.objects.restrict_queryset( + permission=permission_document_view, + queryset=Document.objects.filter(workflows__workflow=self), + user=user + ).count() + class WorkflowStateRuntimeProxy(WorkflowState): class Meta: proxy = True verbose_name = _('Workflow state runtime proxy') verbose_name_plural = _('Workflow state runtime proxies') + + def get_document_count(self, user): + """ + Return the numeric count of documents at this workflow state. + The count is filtered by access. + """ + return AccessControlList.objects.restrict_queryset( + permission=permission_document_view, queryset=self.get_documents(), + user=user + ).count() diff --git a/mayan/apps/navigation/classes.py b/mayan/apps/navigation/classes.py index 1cc9b1c3af..d51c3db2d8 100644 --- a/mayan/apps/navigation/classes.py +++ b/mayan/apps/navigation/classes.py @@ -577,44 +577,53 @@ class SourceColumn(object): @classmethod def get_for_source(cls, context, source, exclude_identifier=False, only_identifier=False): - try: - result = cls._registry[source] - except KeyError: - try: - # Might be an instance, try its class - result = cls._registry[source.__class__] - except KeyError: - try: - # Might be a subclass, try its root class - result = cls._registry[source.__class__.__mro__[-2]] - except KeyError: - try: - # Might be an inherited class insance, try its source class - result = cls._registry[source.source_ptr.__class__] - except (KeyError, AttributeError): - try: - # Try it as a queryset - result = cls._registry[source.model] - except AttributeError: - try: - # Special case for queryset items produced from - # .defer() or .only() optimizations - result = cls._registry[list(source._meta.parents.items())[0][0]] - except (AttributeError, KeyError, IndexError): - result = () - except TypeError: - # unhashable type: list - result = () + columns = [] - result = SourceColumn.sort(columns=result) + try: + columns.extend(cls._registry[source]) + except KeyError: + pass + + try: + # Might be an instance, try its class + columns.extend(cls._registry[source.__class__]) + except KeyError: + pass + + try: + # Might be a subclass, try its root class + columns.extend(cls._registry[source.__class__.__mro__[-2]]) + except KeyError: + pass + + try: + # Might be an inherited class insance, try its source class + columns.extend(cls._registry[source.source_ptr.__class__]) + except (KeyError, AttributeError): + pass + + try: + # Try it as a queryset + columns.extend(cls._registry[source.model]) + except AttributeError: + pass + + try: + # Special case for queryset items produced from + # .defer() or .only() optimizations + columns.extend(cls._registry[list(source._meta.parents.items())[0][0]]) + except (AttributeError, KeyError, IndexError): + pass + + columns = SourceColumn.sort(columns=columns) if exclude_identifier: - result = [item for item in result if not item.is_identifier] + columns = [column for column in columns if not column.is_identifier] else: if only_identifier: - for item in result: - if item.is_identifier: - return item + for column in columns: + if column.is_identifier: + return column return None final_result = [] @@ -635,12 +644,12 @@ class SourceColumn(object): return result current_view_name = get_current_view_name(request=request) - for item in result: - if item.views: - if current_view_name in item.views: - final_result.append(item) + for column in columns: + if column.views: + if current_view_name in column.views: + final_result.append(column) else: - final_result.append(item) + final_result.append(column) return final_result