diff --git a/HISTORY.rst b/HISTORY.rst index f7cedceddd..f9af9942ff 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -97,6 +97,9 @@ ActionError exception. - Add favorite documents per user. Adds new setting option DOCUMENTS_FAVORITE_COUNT. +- Add new class based dashboard widget. This new widget supports + subclassing and is template based. All exising widgets have been + converted. ACL filtering was added to the widget results. 3.0.3 (2018-08-17) ================== diff --git a/mayan/apps/appearance/templates/appearance/home.html b/mayan/apps/appearance/templates/appearance/home.html index b62d1c427b..4a6bdd4c11 100644 --- a/mayan/apps/appearance/templates/appearance/home.html +++ b/mayan/apps/appearance/templates/appearance/home.html @@ -67,11 +67,6 @@ - {% get_dashboard 'main' as dashboard %} -
- {% for widget in dashboard.get_widgets %} - {% include 'appearance/dashboard_widget.html' %} - {% endfor %} -
+ {% render_dashboard 'main' %} {% endblock %} diff --git a/mayan/apps/appearance/templates/dashboard/dashboard.html b/mayan/apps/appearance/templates/dashboard/dashboard.html new file mode 100644 index 0000000000..51ca515970 --- /dev/null +++ b/mayan/apps/appearance/templates/dashboard/dashboard.html @@ -0,0 +1,5 @@ +
+ {% for widget in widgets %} + {{ widget }} + {% endfor %} +
diff --git a/mayan/apps/appearance/templates/appearance/dashboard_widget.html b/mayan/apps/appearance/templates/dashboard/numeric_widget.html similarity index 61% rename from mayan/apps/appearance/templates/appearance/dashboard_widget.html rename to mayan/apps/appearance/templates/dashboard/numeric_widget.html index fbf0629437..9a41cce301 100644 --- a/mayan/apps/appearance/templates/appearance/dashboard_widget.html +++ b/mayan/apps/appearance/templates/dashboard/numeric_widget.html @@ -5,28 +5,24 @@
- {% if widget.icon %} - - {% elif widget.icon_class %} + {% if icon %} + + {% elif icon_class %}
- {{ widget.icon_class.render }} + {{ icon_class.render }}
{% endif %}
- {{ widget.label }} + {{ label }}
- {% if widget.func %} - {{ widget.func }} - {% else %} - {{ widget.queryset.count }} - {% endif %} + {{ count }}
- {% if widget.link %} - + {% if link %} + + diff --git a/mayan/apps/checkouts/apps.py b/mayan/apps/checkouts/apps.py index 55848353a9..56f21be914 100644 --- a/mayan/apps/checkouts/apps.py +++ b/mayan/apps/checkouts/apps.py @@ -14,7 +14,7 @@ from common.dashboards import dashboard_main from events import ModelEventType from mayan.celery import app -from .dashboard_widgets import widget_checkouts +from .dashboard_widgets import DashboardWidgetTotalCheckouts from .events import ( event_document_auto_check_in, event_document_check_in, event_document_check_out, event_document_forceful_check_in @@ -117,7 +117,9 @@ class CheckoutsApp(MayanAppConfig): } ) - dashboard_main.add_widget(order=-1, widget=widget_checkouts) + dashboard_main.add_widget( + widget=DashboardWidgetTotalCheckouts, order=-1 + ) menu_facet.bind_links(links=(link_checkout_info,), sources=(Document,)) menu_main.bind_links(links=(link_checkout_list,), position=98) diff --git a/mayan/apps/checkouts/dashboard_widgets.py b/mayan/apps/checkouts/dashboard_widgets.py index 1678434af4..723600208a 100644 --- a/mayan/apps/checkouts/dashboard_widgets.py +++ b/mayan/apps/checkouts/dashboard_widgets.py @@ -4,21 +4,33 @@ from django.apps import apps from django.urls import reverse_lazy from django.utils.translation import ugettext_lazy as _ -from common.classes import DashboardWidget +from common.classes import DashboardWidgetNumeric +from documents.permissions import permission_document_view from .icons import icon_dashboard_checkouts +from .permissions import permission_document_checkout_detail_view -def checkedout_documents_queryset(): - DocumentCheckout = apps.get_model( - app_label='checkouts', model_name='DocumentCheckout' - ) - return DocumentCheckout.objects.all() +class DashboardWidgetTotalCheckouts(DashboardWidgetNumeric): + icon_class = icon_dashboard_checkouts + label = _('Checkedout documents') + link = reverse_lazy('checkouts:checkout_list') - -widget_checkouts = DashboardWidget( - icon_class=icon_dashboard_checkouts, - label=_('Checkedout documents'), - link=reverse_lazy('checkouts:checkout_list'), - queryset=checkedout_documents_queryset -) + def render(self, request): + AccessControlList = apps.get_model( + app_label='acls', model_name='AccessControlList' + ) + DocumentCheckout = apps.get_model( + app_label='checkouts', model_name='DocumentCheckout' + ) + queryset = AccessControlList.objects.filter_by_access( + permission=permission_document_checkout_detail_view, + user=request.user, + queryset=DocumentCheckout.objects.checked_out_documents() + ) + queryset = AccessControlList.objects.filter_by_access( + permission=permission_document_view, user=request.user, + queryset=queryset + ) + self.count = queryset.count() + return super(DashboardWidgetTotalCheckouts, self).render(request) diff --git a/mayan/apps/common/classes.py b/mayan/apps/common/classes.py index 2824b6f93b..6a3a54b41c 100644 --- a/mayan/apps/common/classes.py +++ b/mayan/apps/common/classes.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.apps import apps from django.db import models +from django.template import loader from django.urls import reverse from django.utils.encoding import force_text, python_2_unicode_compatible from django.utils.translation import ugettext @@ -83,24 +84,57 @@ class Dashboard(object): def remove_widget(self, widget): self.removed_widgets.append(widget) + def render(self, request): + rendered_widgets = [widget().render(request=request) for widget in self.get_widgets()] -class DashboardWidget(object): - _registry = [] + return loader.render_to_string( + template_name='dashboard/dashboard.html', context={ + 'widgets': rendered_widgets + } + ) + + +class BaseDashboardWidget(object): + _registry = {} + context = {} + template_name = None + + @classmethod + def get(cls, name): + return cls._registry[name] @classmethod def get_all(cls): - return cls._registry + return cls._registry.items() - def __init__(self, label, func=None, icon=None, icon_class=None, link=None, queryset=None, statistic_slug=None): - self.label = label - self.icon = icon - self.icon_class = icon_class - self.link = link - self.queryset = queryset - self.func = func - self.statistic_slug = statistic_slug + @classmethod + def register(cls, klass): + cls._registry[klass.name] = klass - self.__class__._registry.append(self) + def get_context(self): + return self.context + + def render(self, request): + if self.template_name: + return loader.render_to_string( + template_name=self.template_name, context=self.get_context(), + ) + + +class DashboardWidgetNumeric(BaseDashboardWidget): + count = 0 + icon_class = None + label = None + link = None + template_name = 'dashboard/numeric_widget.html' + + def get_context(self): + return { + 'count': self.count, + 'icon_class': self.icon_class, + 'label': self.label, + 'link': self.link, + } @python_2_unicode_compatible diff --git a/mayan/apps/common/templatetags/common_tags.py b/mayan/apps/common/templatetags/common_tags.py index 0ea471ed13..7193c677ee 100644 --- a/mayan/apps/common/templatetags/common_tags.py +++ b/mayan/apps/common/templatetags/common_tags.py @@ -45,12 +45,6 @@ def check_sqlite(): def get_collections(): return Collection.get_all() - -@register.simple_tag -def get_dashboard(name): - return Dashboard.get(name=name) - - @register.filter def get_encoded_parameter(item, parameters_dict): result = {} @@ -74,6 +68,11 @@ def project_information(attribute_name): return getattr(mayan, attribute_name) +@register.simple_tag(takes_context=True) +def render_dashboard(context, name): + return Dashboard.get(name=name).render(request=context.request) + + @register.simple_tag(takes_context=True) def render_subtemplate(context, template_name, template_context): """ diff --git a/mayan/apps/documents/apps.py b/mayan/apps/documents/apps.py index e19a5d35b8..3e42965c4f 100644 --- a/mayan/apps/documents/apps.py +++ b/mayan/apps/documents/apps.py @@ -35,9 +35,9 @@ from navigation import SourceColumn from rest_api.fields import DynamicSerializerField from .dashboard_widgets import ( - widget_document_types, widget_documents_in_trash, - widget_new_documents_this_month, widget_pages_per_month, - widget_total_documents + DashboardWidgetDocumentsInTrash, DashboardWidgetDocumentsNewThisMonth, + DashboardWidgetDocumentsPagesNewThisMonth, DashboardWidgetDocumentsTotal, + DashboardWidgetDocumentsTypesTotal, ) from .events import ( event_document_create, event_document_download, @@ -195,7 +195,7 @@ class DocumentsApp(MayanAppConfig): model=Document, related='document_type', ) ModelPermission.register_inheritance( - model=DocumentPage, related='document', + model=DocumentPage, related='document_version__document', ) ModelPermission.register_inheritance( model=DocumentPageResult, related='document_version__document', @@ -389,11 +389,21 @@ class DocumentsApp(MayanAppConfig): } ) - dashboard_main.add_widget(widget=widget_document_types) - dashboard_main.add_widget(widget=widget_documents_in_trash) - dashboard_main.add_widget(widget=widget_new_documents_this_month) - dashboard_main.add_widget(widget=widget_pages_per_month) - dashboard_main.add_widget(widget=widget_total_documents) + dashboard_main.add_widget( + widget=DashboardWidgetDocumentsTotal, order=0 + ) + dashboard_main.add_widget( + widget=DashboardWidgetDocumentsInTrash, order=1 + ) + dashboard_main.add_widget( + widget=DashboardWidgetDocumentsTypesTotal, order=2 + ) + dashboard_main.add_widget( + widget=DashboardWidgetDocumentsNewThisMonth, order=3 + ) + dashboard_main.add_widget( + widget=DashboardWidgetDocumentsPagesNewThisMonth, order=4 + ) menu_documents.bind_links( links=( diff --git a/mayan/apps/documents/dashboard_widgets.py b/mayan/apps/documents/dashboard_widgets.py index 5e9237a200..a951c5a4c3 100644 --- a/mayan/apps/documents/dashboard_widgets.py +++ b/mayan/apps/documents/dashboard_widgets.py @@ -4,78 +4,99 @@ from django.apps import apps from django.urls import reverse_lazy from django.utils.translation import ugettext_lazy as _ -from common.classes import DashboardWidget +from common.classes import DashboardWidgetNumeric from .icons import ( icon_dashboard_documents_in_trash, icon_dashboard_document_types, icon_dashboard_pages_per_month, icon_dashboard_new_documents_this_month, icon_dashboard_total_document ) +from .permissions import ( + permission_document_view, permission_document_type_view +) from .statistics import ( new_document_pages_this_month, new_documents_this_month, ) -def get_total_documents_queryset(): - Document = apps.get_model( - app_label='documents', model_name='Document' - ) - return Document.objects.all() +class DashboardWidgetDocumentsTotal(DashboardWidgetNumeric): + icon_class = icon_dashboard_total_document + label = _('Total documents') + link = reverse_lazy('documents:document_list') + + def render(self, request): + AccessControlList = apps.get_model( + app_label='acls', model_name='AccessControlList' + ) + Document = apps.get_model( + app_label='documents', model_name='Document' + ) + self.count = AccessControlList.objects.filter_by_access( + permission=permission_document_view, user=request.user, + queryset=Document.objects.filter(is_stub=False) + ).count() + return super(DashboardWidgetDocumentsTotal, self).render(request) -def get_document_types_queryset(): - DocumentType = apps.get_model( - app_label='documents', model_name='DocumentType' - ) - return DocumentType.objects.all() +class DashboardWidgetDocumentsInTrash(DashboardWidgetNumeric): + icon_class = icon_dashboard_documents_in_trash + label = _('Documents in trash') + link = reverse_lazy('documents:document_list_deleted') + + def render(self, request): + AccessControlList = apps.get_model( + app_label='acls', model_name='AccessControlList' + ) + DeletedDocument = apps.get_model( + app_label='documents', model_name='DeletedDocument' + ) + self.count = AccessControlList.objects.filter_by_access( + permission=permission_document_view, user=request.user, + queryset=DeletedDocument.objects.all() + ).count() + return super(DashboardWidgetDocumentsInTrash, self).render(request) -def get_deleted_documents_queryset(): - DeletedDocument = apps.get_model( - app_label='documents', model_name='DeletedDocument' - ) - return DeletedDocument.objects.all() +class DashboardWidgetDocumentsTypesTotal(DashboardWidgetNumeric): + icon_class = icon_dashboard_document_types + label = _('Document types') + link = reverse_lazy('documents:document_type_list') + + def render(self, request): + AccessControlList = apps.get_model( + app_label='acls', model_name='AccessControlList' + ) + DocumentType = apps.get_model( + app_label='documents', model_name='DocumentType' + ) + self.count = AccessControlList.objects.filter_by_access( + permission=permission_document_type_view, user=request.user, + queryset=DocumentType.objects.all() + ).count() + return super(DashboardWidgetDocumentsTypesTotal, self).render(request) -widget_pages_per_month = DashboardWidget( - func=new_document_pages_this_month, - icon_class=icon_dashboard_pages_per_month, - label=_('New pages this month'), - link=reverse_lazy( - 'statistics:statistic_detail', - args=('new-document-pages-per-month',) - ) -) - -widget_new_documents_this_month = DashboardWidget( - func=new_documents_this_month, - icon_class=icon_dashboard_new_documents_this_month, - label=_('New documents this month'), +class DashboardWidgetDocumentsNewThisMonth(DashboardWidgetNumeric): + icon_class = icon_dashboard_new_documents_this_month + label = _('New documents this month') link=reverse_lazy( 'statistics:statistic_detail', args=('new-documents-per-month',) ) -) -widget_total_documents = DashboardWidget( - icon_class=icon_dashboard_total_document, - queryset=get_total_documents_queryset, - label=_('Total documents'), - link=reverse_lazy('documents:document_list') -) + def render(self, request): + self.count = new_documents_this_month(user=request.user) + return super(DashboardWidgetDocumentsNewThisMonth, self).render(request) -widget_document_types = DashboardWidget( - icon_class=icon_dashboard_document_types, - queryset=get_document_types_queryset, - label=_('Document types'), - link=reverse_lazy('documents:document_type_list') -) +class DashboardWidgetDocumentsPagesNewThisMonth(DashboardWidgetNumeric): + icon_class = icon_dashboard_pages_per_month + label = _('New pages this month') + link=reverse_lazy( + 'statistics:statistic_detail', + args=('new-document-pages-per-month',) + ) - -widget_documents_in_trash = DashboardWidget( - icon_class=icon_dashboard_documents_in_trash, - queryset=get_deleted_documents_queryset, - label=_('Documents in trash'), - link=reverse_lazy('documents:document_list_deleted') -) + def render(self, request): + self.count = new_document_pages_this_month(user=request.user) + return super(DashboardWidgetDocumentsPagesNewThisMonth, self).render(request)