from __future__ import absolute_import, unicode_literals import logging from furl import furl from django.conf import settings from django.contrib import messages from django.shortcuts import get_object_or_404, resolve_url from django.urls import reverse from django.utils.encoding import force_text from django.utils.http import urlencode from django.utils.translation import ugettext_lazy as _ from django.views.generic import RedirectView from mayan.apps.acls.models import AccessControlList from mayan.apps.common.generics import SimpleView, SingleObjectListView from mayan.apps.common.utils import resolve from mayan.apps.converter.literals import DEFAULT_ROTATION, DEFAULT_ZOOM_LEVEL from ..forms import DocumentPageForm from ..models import Document, DocumentPage from ..permissions import permission_document_view from ..settings import ( setting_rotation_step, setting_zoom_max_level, setting_zoom_min_level, setting_zoom_percent_step ) __all__ = ( 'DocumentPageListView', 'DocumentPageNavigationFirst', 'DocumentPageNavigationLast', 'DocumentPageNavigationNext', 'DocumentPageNavigationPrevious', 'DocumentPageRotateLeftView', 'DocumentPageRotateRightView', 'DocumentPageView', 'DocumentPageViewResetView', 'DocumentPageZoomInView', 'DocumentPageZoomOutView', ) logger = logging.getLogger(__name__) class DocumentPageInteractiveTransformation(RedirectView): def dispatch(self, request, *args, **kwargs): obj = self.get_object() AccessControlList.objects.check_access( obj=obj, permissions=permission_document_view, user=request.user, ) return super(DocumentPageInteractiveTransformation, self).dispatch( request, *args, **kwargs ) def get_object(self): return get_object_or_404( klass=DocumentPage, pk=self.kwargs['document_page_pk'] ) def get_redirect_url(self, *args, **kwargs): url = reverse( viewname='documents:document_page_view', kwargs={'document_page_pk': self.kwargs['document_page_pk']} ) query_dict = { 'rotation': int( self.request.GET.get('rotation', DEFAULT_ROTATION) ), 'zoom': int(self.request.GET.get('zoom', DEFAULT_ZOOM_LEVEL)) } self.transformation_function(query_dict) return '{}?{}'.format(url, urlencode(query_dict)) class DocumentPageListView(SingleObjectListView): def dispatch(self, request, *args, **kwargs): AccessControlList.objects.check_access( obj=self.get_document(), permissions=permission_document_view, user=self.request.user, ) return super( DocumentPageListView, self ).dispatch(request, *args, **kwargs) def get_document(self): return get_object_or_404(klass=Document, pk=self.kwargs['document_pk']) def get_extra_context(self): return { 'column_class': 'col-xs-12 col-sm-6 col-md-4 col-lg-3', 'hide_object': True, 'list_as_items': True, 'object': self.get_document(), 'table_cell_container_classes': 'td-container-thumbnail', 'title': _('Pages for document: %s') % self.get_document(), } def get_object_list(self): return self.get_document().pages.all() class DocumentPageNavigationBase(RedirectView): def dispatch(self, request, *args, **kwargs): document_page = self.get_object() AccessControlList.objects.check_access( permissions=permission_document_view, user=request.user, obj=document_page.document ) return super(DocumentPageNavigationBase, self).dispatch( request, *args, **kwargs ) def get_object(self): return get_object_or_404( klass=DocumentPage, pk=self.kwargs['document_page_pk'] ) def get_redirect_url(self, *args, **kwargs): """ Attempt to jump to the same kind of view but resolved to a new object of the same kind. """ previous_url = self.request.META.get('HTTP_REFERER', None) if not previous_url: try: previous_url = self.get_object().get_absolute_url() except AttributeError: previous_url = resolve_url(settings.LOGIN_REDIRECT_URL) parsed_url = furl(url=previous_url) # Obtain the view name to be able to resolve it back with new keyword # arguments. resolver_match = resolve(path=force_text(parsed_url.path)) new_kwargs = self.get_new_kwargs() if set(new_kwargs) == set(resolver_match.kwargs): # It is the same type of object, reuse the URL to stay in the # same kind of view but pointing to a new object url = reverse( viewname=resolver_match.view_name, kwargs=new_kwargs ) else: url = parsed_url.path # Update just the path to retain the querystring in case there is # transformation data. parsed_url.path = url return parsed_url.tostr() class DocumentPageNavigationFirst(DocumentPageNavigationBase): def get_new_kwargs(self): document_page = self.get_object() return {'document_page_pk': document_page.siblings.first().pk} class DocumentPageNavigationLast(DocumentPageNavigationBase): def get_new_kwargs(self): document_page = self.get_object() return {'document_page_pk': document_page.siblings.last().pk} class DocumentPageNavigationNext(DocumentPageNavigationBase): def get_new_kwargs(self): document_page = self.get_object() try: document_page = document_page.siblings.get( page_number=document_page.page_number + 1 ) except DocumentPage.DoesNotExist: messages.warning( request=self.request, message=_( 'There are no more pages in this document' ) ) finally: return {'document_page_pk': document_page.pk} class DocumentPageNavigationPrevious(DocumentPageNavigationBase): def get_new_kwargs(self): document_page = self.get_object() try: document_page = document_page.siblings.get( page_number=document_page.page_number - 1 ) except DocumentPage.DoesNotExist: messages.warning( request=self.request, message=_( 'You are already at the first page of this document' ) ) finally: return {'document_page_pk': document_page.pk} class DocumentPageRotateLeftView(DocumentPageInteractiveTransformation): def transformation_function(self, query_dict): query_dict['rotation'] = ( query_dict['rotation'] - setting_rotation_step.value ) % 360 class DocumentPageRotateRightView(DocumentPageInteractiveTransformation): def transformation_function(self, query_dict): query_dict['rotation'] = ( query_dict['rotation'] + setting_rotation_step.value ) % 360 class DocumentPageView(SimpleView): template_name = 'appearance/generic_form.html' def dispatch(self, request, *args, **kwargs): AccessControlList.objects.check_access( permissions=permission_document_view, user=request.user, obj=self.get_object().document ) return super( DocumentPageView, self ).dispatch(request, *args, **kwargs) def get_extra_context(self): zoom = int(self.request.GET.get('zoom', DEFAULT_ZOOM_LEVEL)) rotation = int(self.request.GET.get('rotation', DEFAULT_ROTATION)) document_page_form = DocumentPageForm( instance=self.get_object(), zoom=zoom, rotation=rotation ) base_title = _('Image of: %s') % self.get_object() if zoom != DEFAULT_ZOOM_LEVEL: zoom_text = '({}%)'.format(zoom) else: zoom_text = '' return { 'form': document_page_form, 'hide_labels': True, 'navigation_object_list': ('page',), 'page': self.get_object(), 'rotation': rotation, 'title': ' '.join((base_title, zoom_text,)), 'read_only': True, 'zoom': zoom, } def get_object(self): return get_object_or_404( klass=DocumentPage, pk=self.kwargs['document_page_pk'] ) class DocumentPageViewResetView(RedirectView): pattern_name = 'documents:document_page_view' class DocumentPageZoomInView(DocumentPageInteractiveTransformation): def transformation_function(self, query_dict): zoom = query_dict['zoom'] + setting_zoom_percent_step.value if zoom > setting_zoom_max_level.value: zoom = setting_zoom_max_level.value query_dict['zoom'] = zoom class DocumentPageZoomOutView(DocumentPageInteractiveTransformation): def transformation_function(self, query_dict): zoom = query_dict['zoom'] - setting_zoom_percent_step.value if zoom < setting_zoom_min_level.value: zoom = setting_zoom_min_level.value query_dict['zoom'] = zoom