From 48fc36d54e389ec31cb1ade8d82d05ec38d9658f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 2 Aug 2017 03:54:21 -0400 Subject: [PATCH] Convert the document version list view to item view mode. Add document version preview and thumbnail widgets. Update the new version upload event have the version as the target and the document as the action object. Signed-off-by: Roberto Rosario --- mayan/apps/document_signatures/views.py | 30 ++++--------- mayan/apps/documents/apps.py | 39 ++++++++++++++--- mayan/apps/documents/forms.py | 16 +++++++ mayan/apps/documents/links.py | 16 +++++++ mayan/apps/documents/models.py | 10 ++++- mayan/apps/documents/urls.py | 10 +++-- .../documents/views/document_version_views.py | 35 +++++++++++++++- mayan/apps/documents/widgets.py | 42 +++++++++++++++++++ 8 files changed, 163 insertions(+), 35 deletions(-) diff --git a/mayan/apps/document_signatures/views.py b/mayan/apps/document_signatures/views.py index 4cf27a4507..6fc866c638 100644 --- a/mayan/apps/document_signatures/views.py +++ b/mayan/apps/document_signatures/views.py @@ -111,9 +111,7 @@ class DocumentVersionDetachedSignatureCreateView(FormView): def get_extra_context(self): return { - 'document': self.get_document_version().document, - 'document_version': self.get_document_version(), - 'navigation_object_list': ('document', 'document_version'), + 'object': self.get_document_version(), 'title': _( 'Sign document version "%s" with a detached signature' ) % self.get_document_version(), @@ -212,9 +210,7 @@ class DocumentVersionEmbeddedSignatureCreateView(FormView): def get_extra_context(self): return { - 'document': self.get_document_version().document, - 'document_version': self.get_document_version(), - 'navigation_object_list': ('document', 'document_version'), + 'object': self.get_document_version(), 'title': _( 'Sign document version "%s" with a embedded signature' ) % self.get_document_version(), @@ -237,11 +233,7 @@ class DocumentVersionSignatureDeleteView(SingleObjectDeleteView): def get_extra_context(self): return { - 'document': self.get_object().document_version.document, - 'document_version': self.get_object().document_version, - 'navigation_object_list': ( - 'document', 'document_version', 'signature' - ), + 'object': self.get_object().document_version, 'signature': self.get_object(), 'title': _('Delete detached signature: %s') % self.get_object() } @@ -260,13 +252,9 @@ class DocumentVersionSignatureDetailView(SingleObjectDetailView): def get_extra_context(self): return { - 'document': self.get_object().document_version.document, - 'document_version': self.get_object().document_version, - 'signature': self.get_object(), - 'navigation_object_list': ( - 'document', 'document_version', 'signature' - ), 'hide_object': True, + 'object': self.get_object().document_version, + 'signature': self.get_object(), 'title': _( 'Details for signature: %s' ) % self.get_object(), @@ -305,10 +293,8 @@ class DocumentVersionSignatureListView(SingleObjectListView): def get_extra_context(self): return { - 'document': self.get_document_version().document, - 'document_version': self.get_document_version(), - 'navigation_object_list': ('document', 'document_version'), 'hide_object': True, + 'object': self.get_document_version(), 'title': _( 'Signatures for document version: %s' ) % self.get_document_version(), @@ -337,9 +323,7 @@ class DocumentVersionSignatureUploadView(SingleObjectCreateView): def get_extra_context(self): return { - 'document': self.get_document_version().document, - 'document_version': self.get_document_version(), - 'navigation_object_list': ('document', 'document_version'), + 'object': self.get_document_version(), 'title': _( 'Upload detached signature for document version: %s' ) % self.get_document_version(), diff --git a/mayan/apps/documents/apps.py b/mayan/apps/documents/apps.py index e7d258d64e..b9f3d76b43 100644 --- a/mayan/apps/documents/apps.py +++ b/mayan/apps/documents/apps.py @@ -67,8 +67,10 @@ from .links import ( link_document_type_filename_list, link_document_type_list, link_document_type_setup, link_document_update_page_count, link_document_version_download, link_document_version_list, - link_document_version_revert, link_duplicated_document_list, - link_duplicated_document_scan, link_trash_can_empty + link_document_version_return_document, link_document_version_return_list, + link_document_version_revert, link_document_version_view, + link_duplicated_document_list, link_duplicated_document_scan, + link_trash_can_empty ) from .literals import ( CHECK_DELETE_PERIOD_INTERVAL, CHECK_TRASH_PERIOD_INTERVAL, @@ -95,7 +97,10 @@ from .statistics import ( new_document_versions_per_month, total_document_per_month, total_document_page_per_month, total_document_version_per_month ) -from .widgets import DocumentThumbnailWidget, DocumentPageThumbnailWidget +from .widgets import ( + DocumentThumbnailWidget, DocumentPageThumbnailWidget, + DocumentVersionThumbnailWidget +) class DocumentsApp(MayanAppConfig): @@ -234,9 +239,11 @@ class DocumentsApp(MayanAppConfig): ) # Document and document page thumbnail widget - document_thumbnail_widget = DocumentThumbnailWidget() document_page_thumbnail_widget = DocumentPageThumbnailWidget() + document_thumbnail_widget = DocumentThumbnailWidget() + document_version_thumbnail_widget = DocumentVersionThumbnailWidget() + # Document SourceColumn( source=Document, label=_('Thumbnail'), func=lambda context: document_thumbnail_widget.render( @@ -247,6 +254,7 @@ class DocumentsApp(MayanAppConfig): source=Document, label=_('Type'), attribute='document_type' ) + # DocumentPage SourceColumn( source=DocumentPage, label=_('Thumbnail'), func=lambda context: document_page_thumbnail_widget.render( @@ -266,6 +274,7 @@ class DocumentsApp(MayanAppConfig): attribute='document_version.document.document_type' ) + # DocumentType SourceColumn( source=DocumentType, label=_('Documents'), func=lambda context: context['object'].get_document_count( @@ -278,6 +287,7 @@ class DocumentsApp(MayanAppConfig): func=lambda context: two_state_template(context['object'].enabled) ) + # DeletedDocument SourceColumn( source=DeletedDocument, label=_('Thumbnail'), func=lambda context: document_thumbnail_widget.render( @@ -293,6 +303,7 @@ class DocumentsApp(MayanAppConfig): attribute='deleted_date_time' ) + # DocumentVersion SourceColumn( source=DocumentVersion, label=_('Time and date'), attribute='timestamp' @@ -309,6 +320,14 @@ class DocumentsApp(MayanAppConfig): source=DocumentVersion, label=_('Comment'), attribute='comment' ) + SourceColumn( + source=DocumentVersion, label=_('Thumbnail'), + func=lambda context: document_version_thumbnail_widget.render( + instance=context['object'] + ) + ) + + # DuplicatedDocument SourceColumn( source=DuplicatedDocument, label=_('Thumbnail'), func=lambda context: document_thumbnail_widget.render( @@ -478,7 +497,8 @@ class DocumentsApp(MayanAppConfig): # Document actions menu_object.bind_links( links=( - link_document_version_revert, link_document_version_download + link_document_version_view, link_document_version_revert, + link_document_version_download ), sources=(DocumentVersion,) ) @@ -520,6 +540,14 @@ class DocumentsApp(MayanAppConfig): links=(link_transformation_list,), sources=(DocumentPage,) ) + # Document versions + menu_facet.bind_links( + links=( + link_document_version_return_document, + link_document_version_return_list + ), sources=(DocumentVersion,) + ) + namespace = StatisticNamespace(slug='documents', label=_('Documents')) namespace.add_statistic( slug='new-documents-per-month', @@ -576,3 +604,4 @@ class DocumentsApp(MayanAppConfig): registry.register(DeletedDocument) registry.register(Document) registry.register(DocumentType) + registry.register(DocumentVersion) diff --git a/mayan/apps/documents/forms.py b/mayan/apps/documents/forms.py index ab3dad828d..702c65913a 100644 --- a/mayan/apps/documents/forms.py +++ b/mayan/apps/documents/forms.py @@ -56,6 +56,22 @@ class DocumentPreviewForm(forms.Form): preview = forms.CharField(widget=DocumentPagesCarouselWidget()) +class DocumentVersionPreviewForm(forms.Form): + def __init__(self, *args, **kwargs): + document_version = kwargs.pop('instance', None) + super(DocumentVersionPreviewForm, self).__init__(*args, **kwargs) + + self.fields['preview'].initial = document_version + try: + self.fields['preview'].label = _( + 'Document pages (%d)' + ) % document_version.pages.count() + except AttributeError: + self.fields['preview'].label = _('Document version pages (%d)') % 0 + + preview = forms.CharField(widget=DocumentPagesCarouselWidget()) + + class DocumentForm(forms.ModelForm): """ Form sub classes from DocumentForm used only when editing a document diff --git a/mayan/apps/documents/links.py b/mayan/apps/documents/links.py index 29ce7ffaf2..5e6b2a5ff4 100644 --- a/mayan/apps/documents/links.py +++ b/mayan/apps/documents/links.py @@ -142,10 +142,26 @@ link_document_multiple_update_page_count = Link( link_document_multiple_restore = Link( text=_('Restore'), view='documents:document_multiple_restore' ) + +# Versions link_document_version_download = Link( args='resolved_object.pk', permissions=(permission_document_download,), text=_('Download version'), view='documents:document_version_download_form' ) +link_document_version_return_document = Link( + icon='fa fa-file', permissions=(permission_document_view,), + text=_('Document'), view='documents:document_preview', + args='resolved_object.document.pk' +) +link_document_version_return_list = Link( + icon='fa fa-code-fork', permissions=(permission_document_version_view,), + text=_('Versions'), view='documents:document_version_list', + args='resolved_object.document.pk' +) +link_document_version_view = Link( + args='resolved_object.pk', permissions=(permission_document_version_view,), + text=_('Details'), view='documents:document_version_view' +) # Views link_document_list = Link( diff --git a/mayan/apps/documents/models.py b/mayan/apps/documents/models.py index cca6a18471..1e2151831b 100644 --- a/mayan/apps/documents/models.py +++ b/mayan/apps/documents/models.py @@ -7,6 +7,7 @@ import uuid from django.conf import settings from django.core.files import File from django.db import models, transaction +from django.template import Template, Context from django.urls import reverse from django.utils.encoding import force_text, python_2_unicode_compatible from django.utils.timezone import now @@ -399,7 +400,9 @@ class DocumentVersion(models.Model): verbose_name_plural = _('Document version') def __str__(self): - return '{0} - {1}'.format(self.document, self.timestamp) + return Template( + '{{ instance.document }} - {{ instance.timestamp }}' + ).render(context=Context({'instance': self})) def delete(self, *args, **kwargs): for page in self.pages.all(): @@ -409,6 +412,9 @@ class DocumentVersion(models.Model): return super(DocumentVersion, self).delete(*args, **kwargs) + def get_absolute_url(self): + return reverse('documents:document_version_view', args=(self.pk,)) + def save(self, *args, **kwargs): """ Overloaded save method that updates the document version's checksum, @@ -457,7 +463,7 @@ class DocumentVersion(models.Model): else: if new_document_version: event_document_new_version.commit( - actor=user, target=self.document + actor=user, target=self, action_object=self.document ) post_version_upload.send(sender=DocumentVersion, instance=self) diff --git a/mayan/apps/documents/urls.py b/mayan/apps/documents/urls.py index e5c2250b3d..1fe04436f7 100644 --- a/mayan/apps/documents/urls.py +++ b/mayan/apps/documents/urls.py @@ -30,9 +30,9 @@ from .views import ( DocumentTypeFilenameEditView, DocumentTypeFilenameListView, DocumentTypeListView, DocumentTypeEditView, DocumentUpdatePageCountView, DocumentVersionDownloadFormView, DocumentVersionDownloadView, - DocumentVersionListView, DocumentVersionRevertView, DocumentView, - DuplicatedDocumentListView, EmptyTrashCanView, RecentDocumentListView, - ScanDuplicatedDocuments + DocumentVersionListView, DocumentVersionRevertView, DocumentVersionView, + DocumentView, DuplicatedDocumentListView, EmptyTrashCanView, + RecentDocumentListView, ScanDuplicatedDocuments ) @@ -148,6 +148,10 @@ urlpatterns = [ DocumentVersionDownloadFormView.as_view(), name='document_version_download_form' ), + url( + r'^document/version/(?P\d+)/$', DocumentVersionView.as_view(), + name='document_version_view' + ), url( r'^document/version/(?P\d+)/download/$', DocumentVersionDownloadView.as_view(), name='document_version_download' diff --git a/mayan/apps/documents/views/document_version_views.py b/mayan/apps/documents/views/document_version_views.py index 4140b262db..83e909d96b 100644 --- a/mayan/apps/documents/views/document_version_views.py +++ b/mayan/apps/documents/views/document_version_views.py @@ -7,8 +7,12 @@ from django.shortcuts import get_object_or_404 from django.utils.translation import ugettext_lazy as _ from acls.models import AccessControlList -from common.generics import ConfirmView, SingleObjectListView +from common.generics import ( + ConfirmView, SingleObjectDetailView, SingleObjectListView +) +from ..events import event_document_view +from ..forms import DocumentVersionPreviewForm from ..models import Document, DocumentVersion from ..permissions import ( permission_document_download, permission_document_version_revert, @@ -38,7 +42,8 @@ class DocumentVersionListView(SingleObjectListView): def get_extra_context(self): return { - 'hide_object': True, 'object': self.get_document(), + 'list_as_items': True, + 'object': self.get_document(), 'title': _('Versions of document: %s') % self.get_document(), } @@ -96,3 +101,29 @@ class DocumentVersionDownloadFormView(DocumentDownloadFormView): class DocumentVersionDownloadView(DocumentDownloadView): model = DocumentVersion object_permission = permission_document_download + + +class DocumentVersionView(SingleObjectDetailView): + form_class = DocumentVersionPreviewForm + model = DocumentVersion + object_permission = permission_document_version_view + + def dispatch(self, request, *args, **kwargs): + result = super( + DocumentVersionView, self + ).dispatch(request, *args, **kwargs) + self.get_object().document.add_as_recent_document_for_user( + request.user + ) + event_document_view.commit( + actor=request.user, target=self.get_object().document + ) + + return result + + def get_extra_context(self): + return { + 'hide_labels': True, + 'object': self.get_object(), + 'title': _('Preview of document version: %s') % self.get_object(), + } diff --git a/mayan/apps/documents/widgets.py b/mayan/apps/documents/widgets.py index 55cf0dc673..9e6d961bc5 100644 --- a/mayan/apps/documents/widgets.py +++ b/mayan/apps/documents/widgets.py @@ -333,6 +333,48 @@ class DocumentPageThumbnailWidget(BaseDocumentThumbnailWidget): return force_text(instance) +class DocumentVersionThumbnailWidget(DocumentThumbnailWidget): + width = '100%' + + def get_click_view_kwargs(self, instance): + return { + 'pk': instance.document.pk, + 'version_pk': instance.pk, + 'page_pk': instance.pages.first().pk + } + + def get_click_view_url(self, instance): + first_page = instance.pages.first() + if first_page: + return super(DocumentVersionThumbnailWidget, self).get_click_view_url( + instance=instance + ) + else: + return '#' + + def get_preview_view_kwargs(self, instance): + return { + 'pk': instance.document.pk, + 'version_pk': instance.pk, + 'page_pk': instance.pages.first().pk + } + + def get_preview_view_url(self, instance): + first_page = instance.pages.first() + if first_page: + return super(DocumentVersionThumbnailWidget, self).get_preview_view_url( + instance=instance + ) + else: + return '' + + def get_title(self, instance): + return getattr(instance, 'label', None) + + def is_valid(self, instance): + return instance.pages + + class InteractiveDocumentPageWidget(BaseDocumentThumbnailWidget): click_view_name = None