diff --git a/mayan/apps/appearance/templates/appearance/base.html b/mayan/apps/appearance/templates/appearance/base.html index 733d926704..f988399503 100644 --- a/mayan/apps/appearance/templates/appearance/base.html +++ b/mayan/apps/appearance/templates/appearance/base.html @@ -319,18 +319,13 @@ function load_document_image(image) { $.get( image.attr('data-src'), function(result) { - if (result.status == 'success') { - image.attr('src', result.data); - image.addClass(image.attr('data-post-load-class')); - } else { - image.parent().parent().html(''); - set_image_noninteractive(image); - } + image.attr('src', result.data); + image.addClass(image.attr('data-post-load-class')); + }) + .fail(function() { + image.parent().parent().html(''); + set_image_noninteractive(image); }) - .fail(function() { - image.parent().parent().html(''); - set_image_noninteractive(image); - }) } function dismissAlert(element) { diff --git a/mayan/apps/checkouts/apps.py b/mayan/apps/checkouts/apps.py index 6cf2454f18..021df978ef 100644 --- a/mayan/apps/checkouts/apps.py +++ b/mayan/apps/checkouts/apps.py @@ -35,7 +35,7 @@ class CheckoutsApp(MayanAppConfig): def ready(self): super(CheckoutsApp, self).ready() - APIEndPoint('checkouts') + APIEndPoint(app=self, version_string='1') Document.add_to_class( 'check_in', diff --git a/mayan/apps/common/apps.py b/mayan/apps/common/apps.py index 044ca95dda..1869ad6016 100644 --- a/mayan/apps/common/apps.py +++ b/mayan/apps/common/apps.py @@ -96,12 +96,13 @@ class CommonApp(MayanAppConfig): 'common:tools_list' ) ) - user_logged_in.connect( - user_locale_profile_session_config, - dispatch_uid='user_locale_profile_session_config' - ) + post_save.connect( user_locale_profile_create, dispatch_uid='user_locale_profile_create', sender=settings.AUTH_USER_MODEL ) + user_logged_in.connect( + user_locale_profile_session_config, + dispatch_uid='user_locale_profile_session_config' + ) diff --git a/mayan/apps/converter/apps.py b/mayan/apps/converter/apps.py index 3d05b192d2..97dabf5e46 100644 --- a/mayan/apps/converter/apps.py +++ b/mayan/apps/converter/apps.py @@ -18,6 +18,10 @@ class ConverterApp(MayanAppConfig): def ready(self): super(ConverterApp, self).ready() + menu_object.bind_links( + links=(link_transformation_edit, link_transformation_delete), + sources=(Transformation,) + ) menu_sidebar.bind_links( links=(link_transformation_create,), sources=(Transformation,) ) @@ -28,7 +32,3 @@ class ConverterApp(MayanAppConfig): 'converter:transformation_list' ) ) - menu_object.bind_links( - links=(link_transformation_edit, link_transformation_delete), - sources=(Transformation,) - ) diff --git a/mayan/apps/document_indexing/apps.py b/mayan/apps/document_indexing/apps.py index 9ff62ac43e..14d229629e 100644 --- a/mayan/apps/document_indexing/apps.py +++ b/mayan/apps/document_indexing/apps.py @@ -39,7 +39,7 @@ class DocumentIndexingApp(MayanAppConfig): def ready(self): super(DocumentIndexingApp, self).ready() - APIEndPoint('indexes', app_name='document_indexing') + APIEndPoint(app=self, version_string='1') app.conf.CELERY_QUEUES.append( Queue('indexing', Exchange('indexing'), routing_key='indexing'), @@ -85,15 +85,6 @@ class DocumentIndexingApp(MayanAppConfig): menu_setup.bind_links(links=(link_index_setup,)) menu_tools.bind_links(links=(link_rebuild_index_instances,)) - post_document_created.connect( - document_created_index_update, - dispatch_uid='document_created_index_update', sender=Document - ) - post_save.connect( - document_metadata_index_update, - dispatch_uid='document_metadata_index_update', - sender=DocumentMetadata - ) post_delete.connect( document_index_delete, dispatch_uid='document_index_delete', sender=Document @@ -103,3 +94,12 @@ class DocumentIndexingApp(MayanAppConfig): dispatch_uid='document_metadata_index_post_delete', sender=DocumentMetadata ) + post_document_created.connect( + document_created_index_update, + dispatch_uid='document_created_index_update', sender=Document + ) + post_save.connect( + document_metadata_index_update, + dispatch_uid='document_metadata_index_update', + sender=DocumentMetadata + ) diff --git a/mayan/apps/documents/api_views.py b/mayan/apps/documents/api_views.py index a9a2ed03e6..5da20cf536 100644 --- a/mayan/apps/documents/api_views.py +++ b/mayan/apps/documents/api_views.py @@ -1,6 +1,5 @@ from __future__ import absolute_import, unicode_literals -# TODO: Improve API methods docstrings import logging from django.core.exceptions import PermissionDenied @@ -10,51 +9,93 @@ from rest_framework import generics, status from rest_framework.response import Response from acls.models import AccessControlList -from common.models import SharedUploadedFile -from converter.exceptions import UnkownConvertError, UnknownFileFormat -from converter.literals import ( - DEFAULT_PAGE_NUMBER, DEFAULT_ROTATION, DEFAULT_ZOOM_LEVEL -) from permissions import Permission from rest_api.filters import MayanObjectPermissionsFilter from rest_api.permissions import MayanPermission -from .literals import DOCUMENT_IMAGE_TASK_TIMEOUT from .models import ( Document, DocumentPage, DocumentType, DocumentVersion, RecentDocument ) from .permissions import ( permission_document_create, permission_document_delete, permission_document_edit, permission_document_new_version, - permission_document_properties_edit, permission_document_view, - permission_document_type_create, permission_document_type_delete, - permission_document_type_edit, permission_document_type_view + permission_document_properties_edit, permission_document_restore, + permission_document_trash, permission_document_version_revert, + permission_document_view, permission_document_type_create, + permission_document_type_delete, permission_document_type_edit, + permission_document_type_view ) from .serializers import ( - DocumentImageSerializer, DocumentPageSerializer, DocumentSerializer, - DocumentTypeSerializer, DocumentVersionSerializer, NewDocumentSerializer, + DeletedDocumentSerializer, DocumentPageImageSerializer, + DocumentPageSerializer, DocumentSerializer, DocumentTypeSerializer, + DocumentVersionSerializer, DocumentVersionRevertSerializer, + NewDocumentSerializer, NewDocumentVersionSerializer, RecentDocumentSerializer ) -from .settings import ( - setting_display_size, setting_language, setting_zoom_max_level, - setting_zoom_min_level -) -from .tasks import task_get_document_page_image, task_upload_new_version logger = logging.getLogger(__name__) +class APIDeletedDocumentListView(generics.ListAPIView): + """ + Returns a list of all the deleted documents. + """ + + filter_backends = (MayanObjectPermissionsFilter,) + mayan_object_permissions = {'GET': (permission_document_view,)} + permission_classes = (MayanPermission,) + queryset = Document.trash.all() + serializer_class = DeletedDocumentSerializer + + +class APIDeletedDocumentView(generics.RetrieveDestroyAPIView): + """ + Returns the selected deleted document details. + """ + + mayan_object_permissions = { + 'DELETE': (permission_document_delete,) + } + permission_classes = (MayanPermission,) + queryset = Document.trash.all() + serializer_class = DeletedDocumentSerializer + + def delete(self, *args, **kwargs): + """ + Delete the selected document. + """ + + return super(APIDeletedDocumentView, self).delete(*args, **kwargs) + + +class APIDeletedDocumentRestoreView(generics.GenericAPIView): + """ + Restore a deleted document. + """ + + mayan_object_permissions = { + 'POST': (permission_document_restore,) + } + + permission_classes = (MayanPermission,) + queryset = Document.trash.all() + serializer_class = DeletedDocumentSerializer + + def post(self, *args, **kwargs): + self.get_object().restore() + return Response(status=status.HTTP_200_OK) + + class APIDocumentListView(generics.ListCreateAPIView): """ Returns a list of all the documents. """ - queryset = Document.objects.all() - - permission_classes = (MayanPermission,) filter_backends = (MayanObjectPermissionsFilter,) - mayan_object_permissions = {'GET': [permission_document_view], - 'POST': [permission_document_create]} + mayan_object_permissions = {'GET': (permission_document_view,)} + mayan_view_permissions = {'POST': (permission_document_create,)} + permission_classes = (MayanPermission,) + queryset = Document.objects.all() def get_serializer_class(self): if self.request.method == 'GET': @@ -62,203 +103,75 @@ class APIDocumentListView(generics.ListCreateAPIView): elif self.request.method == 'POST': return NewDocumentSerializer + def perform_create(self, serializer): + serializer.save(_user=self.request.user) + def post(self, *args, **kwargs): - """Create a new document.""" + """ + Create a new document. + """ + return super(APIDocumentListView, self).post(*args, **kwargs) - def create(self, request, *args, **kwargs): - serializer = self.get_serializer( - data=request.DATA, files=request.FILES - ) - - if serializer.is_valid(): - document_type = get_object_or_404( - DocumentType, pk=serializer.data['document_type'] - ) - - logger.info( - 'Creating document version for document type: %s', document_type - ) - - document = Document.objects.create( - description=serializer.data['description'] or '', - document_type=document_type, - label=serializer.data['label'] or serializer.data['file'], - language=serializer.data['language'] or setting_language.value - ) - document.save(_user=request.user) - - shared_uploaded_file = SharedUploadedFile.objects.create( - file=request.FILES['file'] - ) - - task_upload_new_version.delay( - shared_uploaded_file_id=shared_uploaded_file.pk, - document_id=document.pk, user_id=request.user.pk, - ) - - logger.info( - 'New document version queued for document: %s', document - ) - - serializer.object = document - - headers = self.get_success_headers(serializer.data) - return Response( - serializer.data, status=status.HTTP_201_CREATED, - headers=headers - ) - - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - class APIDocumentView(generics.RetrieveUpdateDestroyAPIView): """ Returns the selected document details. """ - serializer_class = DocumentSerializer - queryset = Document.objects.all() - - permission_classes = (MayanPermission,) mayan_object_permissions = { - 'GET': [permission_document_view], - 'PUT': [permission_document_properties_edit], - 'PATCH': [permission_document_properties_edit], - 'DELETE': [permission_document_delete] + 'GET': (permission_document_view,), + 'PUT': (permission_document_properties_edit,), + 'PATCH': (permission_document_properties_edit,), + 'DELETE': (permission_document_trash,) } + permission_classes = (MayanPermission,) + queryset = Document.objects.all() + serializer_class = DocumentSerializer def delete(self, *args, **kwargs): - """Delete the selected document.""" + """ + Move the selected document to the thrash. + """ + return super(APIDocumentView, self).delete(*args, **kwargs) def get(self, *args, **kwargs): - """Return the details of the selected document.""" + """ + Return the details of the selected document. + """ + return super(APIDocumentView, self).get(*args, **kwargs) def patch(self, *args, **kwargs): - """Edit the properties of the selected document.""" + """ + Edit the properties of the selected document. + """ + return super(APIDocumentView, self).patch(*args, **kwargs) def put(self, *args, **kwargs): - """Edit the properties of the selected document.""" + """ + Edit the properties of the selected document. + """ + return super(APIDocumentView, self).put(*args, **kwargs) -class APIDocumentVersionCreateView(generics.CreateAPIView): - """ - Create a new document version. - """ - - serializer_class = DocumentVersionSerializer - queryset = DocumentVersion.objects.all() - - permission_classes = (MayanPermission,) - mayan_view_permissions = {'POST': [permission_document_new_version]} - - def create(self, request, *args, **kwargs): - serializer = self.get_serializer( - data=request.DATA, files=request.FILES - ) - - if serializer.is_valid(): - # Nested resource we take the document pk from the URL and insert - # it so that it needs not to be specified by the user, we mark - # it as a read only field in the serializer - document = get_object_or_404(Document, pk=kwargs['pk']) - - document.new_version( - file_object=serializer.object.file, - comment=serializer.object.comment, _user=request.user - ) - - headers = self.get_success_headers(serializer.data) - return Response(status=status.HTTP_202_ACCEPTED, headers=headers) - - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - -class APIDocumentVersionView(generics.RetrieveAPIView): - """ - Returns the selected document version details. - """ - - allowed_methods = ['GET'] - serializer_class = DocumentVersionSerializer - queryset = DocumentVersion.objects.all() - - permission_classes = (MayanPermission,) - mayan_object_permissions = {'GET': [permission_document_view]} - mayan_permission_attribute_check = 'document' - - -class APIDocumentImageView(generics.GenericAPIView): +class APIDocumentPageImageView(generics.RetrieveAPIView): """ Returns an image representation of the selected document. size -- 'x' seprated width and height of the desired image representation. - page -- Page number of the document to be imaged. zoom -- Zoom level of the image to be generated, numeric value only. - version -- Version number of the document to be imaged. """ - serializer_class = DocumentImageSerializer - def get(self, request, pk): - document = get_object_or_404(Document, pk=pk) - - try: - Permission.check_permissions( - request.user, [permission_document_view] - ) - except PermissionDenied: - AccessControlList.objects.check_access( - permission_document_view, request.user, document - ) - - size = request.GET.get('size', setting_display_size.value) - - page = int(request.GET.get('page', DEFAULT_PAGE_NUMBER)) - - zoom = int(request.GET.get('zoom', DEFAULT_ZOOM_LEVEL)) - - version = int(request.GET.get('version', document.latest_version.pk)) - - if zoom < setting_zoom_min_level.value: - zoom = setting_zoom_min_level.value - - if zoom > setting_zoom_max_level.value: - zoom = setting_zoom_max_level.value - - rotation = int(request.GET.get('rotation', DEFAULT_ROTATION)) % 360 - - document_page = document.pages.get(page_number=page) - - try: - task = task_get_document_page_image.apply_async( - kwargs=dict( - document_page_id=document_page.pk, size=size, zoom=zoom, - rotation=rotation, as_base64=True, version=version - ) - ) - # TODO: prepend 'data:%s;base64,%s' based on format specified in - # async call - return Response({ - 'status': 'success', - 'data': task.get(timeout=DOCUMENT_IMAGE_TASK_TIMEOUT) - }) - except UnknownFileFormat as exception: - return Response( - { - 'status': 'error', 'detail': 'unknown_file_format', - 'message': unicode(exception) - } - ) - except UnkownConvertError as exception: - return Response( - { - 'status': 'error', 'detail': 'converter_error', - 'message': unicode(exception) - } - ) + mayan_object_permissions = { + 'GET': (permission_document_view,), + } + mayan_permission_attribute_check = 'document' + permission_classes = (MayanPermission,) + queryset = DocumentPage.objects.all() + serializer_class = DocumentPageImageSerializer class APIDocumentPageView(generics.RetrieveUpdateAPIView): @@ -266,45 +179,58 @@ class APIDocumentPageView(generics.RetrieveUpdateAPIView): Returns the selected document page details. """ - serializer_class = DocumentPageSerializer - queryset = DocumentPage.objects.all() - - permission_classes = (MayanPermission,) mayan_object_permissions = { - 'GET': [permission_document_view], - 'PUT': [permission_document_edit], - 'PATCH': [permission_document_edit] + 'GET': (permission_document_view,), + 'PUT': (permission_document_edit,), + 'PATCH': (permission_document_edit,) } mayan_permission_attribute_check = 'document' + permission_classes = (MayanPermission,) + queryset = DocumentPage.objects.all() + serializer_class = DocumentPageSerializer def get(self, *args, **kwargs): - """Returns the selected document page details.""" + """ + Returns the selected document page details. + """ + return super(APIDocumentPageView, self).get(*args, **kwargs) def patch(self, *args, **kwargs): - """Edit the selected document page.""" + """ + Edit the selected document page. + """ + return super(APIDocumentPageView, self).patch(*args, **kwargs) def put(self, *args, **kwargs): - """Edit the selected document page.""" + """ + Edit the selected document page. + """ + return super(APIDocumentPageView, self).put(*args, **kwargs) class APIDocumentTypeListView(generics.ListCreateAPIView): - serializer_class = DocumentTypeSerializer - queryset = DocumentType.objects.all() - - permission_classes = (MayanPermission,) filter_backends = (MayanObjectPermissionsFilter,) - mayan_object_permissions = {'GET': [permission_document_type_view]} - mayan_view_permissions = {'POST': [permission_document_type_create]} + mayan_object_permissions = {'GET': (permission_document_type_view,)} + mayan_view_permissions = {'POST': (permission_document_type_create,)} + permission_classes = (MayanPermission,) + queryset = DocumentType.objects.all() + serializer_class = DocumentTypeSerializer def get(self, *args, **kwargs): - """Returns a list of all the document types.""" + """ + Returns a list of all the document types. + """ + return super(APIDocumentTypeListView, self).get(*args, **kwargs) def post(self, *args, **kwargs): - """Create a new document type.""" + """ + Create a new document type. + """ + return super(APIDocumentTypeListView, self).post(*args, **kwargs) @@ -313,31 +239,42 @@ class APIDocumentTypeView(generics.RetrieveUpdateDestroyAPIView): Returns the selected document type details. """ - serializer_class = DocumentTypeSerializer - queryset = DocumentType.objects.all() - - permission_classes = (MayanPermission,) mayan_object_permissions = { - 'GET': [permission_document_type_view], - 'PUT': [permission_document_type_edit], - 'PATCH': [permission_document_type_edit], - 'DELETE': [permission_document_type_delete] + 'GET': (permission_document_type_view,), + 'PUT': (permission_document_type_edit,), + 'PATCH': (permission_document_type_edit,), + 'DELETE': (permission_document_type_delete,) } + permission_classes = (MayanPermission,) + queryset = DocumentType.objects.all() + serializer_class = DocumentTypeSerializer def delete(self, *args, **kwargs): - """Delete the selected document type.""" + """ + Delete the selected document type. + """ + return super(APIDocumentTypeView, self).delete(*args, **kwargs) def get(self, *args, **kwargs): - """Return the details of the selected document type.""" + """ + Return the details of the selected document type. + """ + return super(APIDocumentTypeView, self).get(*args, **kwargs) def patch(self, *args, **kwargs): - """Edit the properties of the selected document type.""" + """ + Edit the properties of the selected document type. + """ + return super(APIDocumentTypeView, self).patch(*args, **kwargs) def put(self, *args, **kwargs): - """Edit the properties of the selected document type.""" + """ + Edit the properties of the selected document type. + """ + return super(APIDocumentTypeView, self).put(*args, **kwargs) @@ -347,17 +284,14 @@ class APIDocumentTypeDocumentListView(generics.ListAPIView): """ filter_backends = (MayanObjectPermissionsFilter,) - mayan_object_permissions = {'GET': [permission_document_view]} - - def get_serializer_class(self): - from documents.serializers import DocumentSerializer - return DocumentSerializer + mayan_object_permissions = {'GET': (permission_document_view,)} + serializer_class = DocumentSerializer def get_queryset(self): document_type = get_object_or_404(DocumentType, pk=self.kwargs['pk']) try: Permission.check_permissions( - self.request.user, [permission_document_type_view] + self.request.user, (permission_document_type_view,) ) except PermissionDenied: AccessControlList.objects.check_access( @@ -375,5 +309,100 @@ class APIRecentDocumentListView(generics.ListAPIView): return RecentDocument.objects.filter(user=self.request.user) def get(self, *args, **kwargs): - """Return a list of the recent documents for the current user.""" + """ + Return a list of the recent documents for the current user. + """ + return super(APIRecentDocumentListView, self).get(*args, **kwargs) + + +class APIDocumentVersionsListView(generics.ListCreateAPIView): + """ + Return a list of the selected document's versions. + """ + + mayan_object_permissions = { + 'GET': (permission_document_view,), + } + mayan_permission_attribute_check = 'document' + mayan_view_permissions = {'POST': (permission_document_new_version,)} + permission_classes = (MayanPermission,) + + def get_serializer_class(self): + if self.request.method == 'GET': + return DocumentVersionSerializer + elif self.request.method == 'POST': + return NewDocumentVersionSerializer + + def get_queryset(self): + return get_object_or_404(Document, pk=self.kwargs['pk']).versions.all() + + def perform_create(self, serializer): + serializer.save( + document=get_object_or_404(Document, pk=self.kwargs['pk']), + _user=self.request.user + ) + + def post(self, request, *args, **kwargs): + """ + Create a new document version. + """ + + return super( + APIDocumentVersionsListView, self + ).post(request, *args, **kwargs) + + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + headers = self.get_success_headers(serializer.data) + return Response(status=status.HTTP_202_ACCEPTED, headers=headers) + + +class APIDocumentVersionView(generics.RetrieveUpdateAPIView): + """ + Returns the selected document version details. + """ + + mayan_object_permissions = { + 'GET': (permission_document_view,), + 'PATCH': (permission_document_edit,), + 'PUT': (permission_document_edit,), + } + mayan_permission_attribute_check = 'document' + permission_classes = (MayanPermission,) + queryset = DocumentVersion.objects.all() + serializer_class = DocumentVersionSerializer + + def patch(self, *args, **kwargs): + """ + Edit the selected document version. + """ + + return super(APIDocumentVersionView, self).patch(*args, **kwargs) + + def put(self, *args, **kwargs): + """ + Edit the selected document version. + """ + + return super(APIDocumentVersionView, self).put(*args, **kwargs) + + +class APIDocumentVersionRevertView(generics.GenericAPIView): + """ + Revert to an earlier document version. + """ + + mayan_object_permissions = { + 'POST': (permission_document_version_revert,) + } + mayan_permission_attribute_check = 'document' + permission_classes = (MayanPermission,) + queryset = DocumentVersion.objects.all() + serializer_class = DocumentVersionRevertSerializer + + def post(self, *args, **kwargs): + self.get_object().revert() + return Response(status=status.HTTP_200_OK) diff --git a/mayan/apps/documents/apps.py b/mayan/apps/documents/apps.py index 175a78edcf..e0e19146ea 100644 --- a/mayan/apps/documents/apps.py +++ b/mayan/apps/documents/apps.py @@ -80,7 +80,7 @@ class DocumentsApp(MayanAppConfig): def ready(self): super(DocumentsApp, self).ready() - APIEndPoint('documents') + APIEndPoint(app=self, version_string='1') MissingItem( label=_('Create a document type'), diff --git a/mayan/apps/documents/models.py b/mayan/apps/documents/models.py index 13b9b6d60b..7c016b9863 100644 --- a/mayan/apps/documents/models.py +++ b/mayan/apps/documents/models.py @@ -20,7 +20,9 @@ from converter import ( converter_class, TransformationResize, TransformationRotate, TransformationZoom ) -from converter.exceptions import InvalidOfficeFormat, UnknownFileFormat +from converter.exceptions import ( + InvalidOfficeFormat, PageCountError, UnknownFileFormat +) from converter.literals import DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION from converter.models import Transformation from mimetype.api import get_mimetype @@ -150,6 +152,7 @@ class Document(models.Model): in_trash = models.BooleanField( default=False, editable=False, verbose_name=_('In trash?') ) + #TODO: set editable to False deleted_date_time = models.DateTimeField( blank=True, editable=True, null=True, verbose_name=_('Date and time trashed') @@ -431,25 +434,24 @@ class DocumentVersion(models.Model): file_object=file_object, mime_type=self.mimetype ) detected_pages = converter.get_page_count() - except UnknownFileFormat: + except PageCountError: # If converter backend doesn't understand the format, # use 1 as the total page count - detected_pages = 1 - # TODO: should be no pages instead? + pass + else: + with transaction.atomic(): + self.pages.all().delete() - with transaction.atomic(): - self.pages.all().delete() + for page_number in range(detected_pages): + DocumentPage.objects.create( + document_version=self, page_number=page_number + 1 + ) - for page_number in range(detected_pages): - DocumentPage.objects.create( - document_version=self, page_number=page_number + 1 - ) + # TODO: is this needed anymore + if save: + self.save() - # TODO: is this needed anymore - if save: - self.save() - - return detected_pages + return detected_pages def revert(self, user=None): """ @@ -670,8 +672,8 @@ class DocumentPage(models.Model): as_base64 = kwargs.pop('as_base64', False) transformations = kwargs.pop('transformations', []) size = kwargs.pop('size', setting_display_size.value) - rotation = kwargs.pop('rotation', DEFAULT_ROTATION) - zoom_level = kwargs.pop('zoom', DEFAULT_ZOOM_LEVEL) + rotation = int(kwargs.pop('rotation', DEFAULT_ROTATION) or DEFAULT_ROTATION) + zoom_level = int(kwargs.pop('zoom', DEFAULT_ZOOM_LEVEL) or DEFAULT_ZOOM_LEVEL) if zoom_level < setting_zoom_min_level.value: zoom_level = setting_zoom_min_level.value diff --git a/mayan/apps/documents/serializers.py b/mayan/apps/documents/serializers.py index 365330c9bf..9bab192971 100644 --- a/mayan/apps/documents/serializers.py +++ b/mayan/apps/documents/serializers.py @@ -2,66 +2,181 @@ from __future__ import unicode_literals from rest_framework import serializers -from .models import (Document, DocumentVersion, DocumentPage, DocumentType, - RecentDocument) -from .settings import setting_language, setting_language_choices +from common.models import SharedUploadedFile + +from .literals import DOCUMENT_IMAGE_TASK_TIMEOUT +from .models import ( + Document, DocumentVersion, DocumentPage, DocumentType, RecentDocument +) +from .settings import setting_language +from .tasks import task_get_document_page_image, task_upload_new_version + + +class DocumentPageImageSerializer(serializers.Serializer): + data = serializers.SerializerMethodField() + + def get_data(self, instance): + request = self.context['request'] + size = request.GET.get('size') + zoom = request.GET.get('zoom') + rotation = request.GET.get('rotation') + + task = task_get_document_page_image.apply_async( + kwargs=dict( + document_page_id=instance.pk, size=size, zoom=zoom, + rotation=rotation, as_base64=True + ) + ) + # TODO: prepend 'data:%s;base64,%s' based on format specified in + # async call + return task.get(timeout=DOCUMENT_IMAGE_TASK_TIMEOUT) class DocumentPageSerializer(serializers.HyperlinkedModelSerializer): + image = serializers.HyperlinkedIdentityField( + view_name='rest_api:documentpage-image' + ) + class Meta: + extra_kwargs = { + 'url': {'view_name': 'rest_api:documentpage-detail'}, + 'document_version': {'view_name': 'rest_api:documentversion-detail'} + } model = DocumentPage -class DocumentVersionSerializer(serializers.HyperlinkedModelSerializer): - pages = DocumentPageSerializer(many=True, required=False, read_only=True) - - class Meta: - model = DocumentVersion - read_only_fields = ('document',) - - -class DocumentImageSerializer(serializers.Serializer): - status = serializers.CharField() - data = serializers.CharField() - - -class DocumentTypeSerializer(serializers.ModelSerializer): - documents = serializers.SerializerMethodField('get_documents_count') - - class Meta: - model = DocumentType - fields = ('id', 'name', 'documents') +class DocumentTypeSerializer(serializers.HyperlinkedModelSerializer): + documents = serializers.HyperlinkedIdentityField( + view_name='rest_api:documenttype-document-list', + ) + documents_count = serializers.SerializerMethodField() def get_documents_count(self, obj): return obj.documents.count() + class Meta: + extra_kwargs = { + 'url': {'view_name': 'rest_api:documenttype-detail'}, + } + fields = ( + 'delete_time_period', 'delete_time_unit', 'documents', + 'documents_count', 'id', 'label', 'trash_time_period', + 'trash_time_unit', 'url' + ) + model = DocumentType -class DocumentSerializer(serializers.ModelSerializer): - versions = DocumentVersionSerializer(many=True, read_only=True) - # TODO: Deprecate, move this as an entry point of DocumentVersion's pages - image = serializers.HyperlinkedIdentityField(view_name='document-image') - new_version = serializers.HyperlinkedIdentityField( - view_name='document-new-version' - ) - document_type = DocumentTypeSerializer() + +class DocumentVersionSerializer(serializers.HyperlinkedModelSerializer): + pages = DocumentPageSerializer(many=True, required=False, read_only=True) + revert = serializers.HyperlinkedIdentityField(view_name='rest_api:documentversion-revert') class Meta: + extra_kwargs = { + 'document': {'view_name': 'rest_api:document-detail'}, + 'file': {'use_url': False}, + 'url': {'view_name': 'rest_api:documentversion-detail'}, + } + model = DocumentVersion + read_only_fields = ('document', 'file') + + +class DocumentVersionRevertSerializer(DocumentVersionSerializer): + class Meta(DocumentVersionSerializer.Meta): + read_only_fields = ('comment', 'document',) + + +class NewDocumentVersionSerializer(serializers.Serializer): + comment = serializers.CharField(allow_blank=True) + file = serializers.FileField(use_url=False) + + def save(self, document, _user): + shared_uploaded_file = SharedUploadedFile.objects.create( + file=self.validated_data['file'] + ) + + task_upload_new_version.delay( + comment=self.validated_data.get('comment', ''), + document_id=document.pk, + shared_uploaded_file_id=shared_uploaded_file.pk, user_id=_user.pk + ) + + +class DeletedDocumentSerializer(serializers.HyperlinkedModelSerializer): + document_type_label = serializers.SerializerMethodField() + restore = serializers.HyperlinkedIdentityField(view_name='rest_api:deleteddocument-restore') + + def get_document_type_label(self, instance): + return instance.document_type.label + + class Meta: + extra_kwargs = { + 'document_type': {'view_name': 'rest_api:documenttype-detail'}, + 'url': {'view_name': 'rest_api:deleteddocument-detail'} + } fields = ( - 'id', 'label', 'image', 'new_version', 'uuid', 'document_type', - 'description', 'date_added', 'versions' + 'date_added', 'deleted_date_time', 'description', 'document_type', + 'document_type_label', 'id', 'label', 'language', 'restore', + 'url', 'uuid', + ) + model = Document + read_only_fields = ( + 'deleted_date_time', 'description', 'document_type', 'label', + 'language' + ) + + +class DocumentSerializer(serializers.HyperlinkedModelSerializer): + document_type_label = serializers.SerializerMethodField() + latest_version = DocumentVersionSerializer(many=False, read_only=True) + versions = serializers.HyperlinkedIdentityField( + view_name='rest_api:document-version-list', + ) + + def get_document_type_label(self, instance): + return instance.document_type.label + + class Meta: + extra_kwargs = { + 'document_type': {'view_name': 'rest_api:documenttype-detail'}, + 'url': {'view_name': 'rest_api:document-detail'} + } + fields = ( + 'date_added', 'description', 'document_type', 'document_type_label', + 'id', 'label', 'language', 'latest_version', 'url', 'uuid', + 'versions', ) model = Document -class NewDocumentSerializer(serializers.Serializer): - description = serializers.CharField(required=False) - document_type = serializers.IntegerField() - file = serializers.FileField() - label = serializers.CharField(required=False) - language = serializers.ChoiceField( - blank_display_value=None, choices=setting_language_choices.value, - default=setting_language.value, required=False - ) +class NewDocumentSerializer(serializers.ModelSerializer): + file = serializers.FileField(write_only=True) + + def save(self, _user): + document = Document.objects.create( + description=self.validated_data.get('description', ''), + document_type=self.validated_data['document_type'], + label=self.validated_data.get('label', unicode(self.validated_data['file'])), + language=self.validated_data.get('language', setting_language.value) + ) + document.save(_user=_user) + + shared_uploaded_file = SharedUploadedFile.objects.create( + file=self.validated_data['file'] + ) + + task_upload_new_version.delay( + document_id=document.pk, + shared_uploaded_file_id=shared_uploaded_file.pk, user_id=_user.pk + ) + + self.instance = document + return document + + class Meta: + fields = ( + 'description', 'document_type', 'id', 'file', 'label', 'language', + ) + model = Document class RecentDocumentSerializer(serializers.ModelSerializer): diff --git a/mayan/apps/documents/tasks.py b/mayan/apps/documents/tasks.py index 96014d8b0a..c25bdf14fd 100644 --- a/mayan/apps/documents/tasks.py +++ b/mayan/apps/documents/tasks.py @@ -181,7 +181,7 @@ def task_upload_new_version(self, document_id, shared_uploaded_file_id, user_id, with shared_file.open() as file_object: document_version = DocumentVersion( - document=document, comment=comment, file=file_object + document=document, comment=comment or '', file=file_object ) try: document_version.save(_user=user) diff --git a/mayan/apps/documents/test_api.py b/mayan/apps/documents/test_api.py index 726e221c52..24468b5e48 100644 --- a/mayan/apps/documents/test_api.py +++ b/mayan/apps/documents/test_api.py @@ -5,25 +5,23 @@ from __future__ import unicode_literals from json import loads from django.contrib.auth.models import User +from django.core.files import File from django.core.urlresolvers import reverse -from django.test import TestCase from rest_framework import status -from rest_framework.test import APIClient +from rest_framework.test import APITestCase from .models import Document, DocumentType from .test_models import ( - TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL, - TEST_SMALL_DOCUMENT_FILENAME, TEST_DOCUMENT_PATH, - TEST_SMALL_DOCUMENT_PATH, - TEST_DOCUMENT_TYPE + TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, + TEST_DOCUMENT_FILENAME, TEST_DOCUMENT_PATH, TEST_DOCUMENT_TYPE, + TEST_SMALL_DOCUMENT_FILENAME, TEST_SMALL_DOCUMENT_PATH, ) -class DocumentAPICreateDocumentTestCase(TestCase): +class DocumentTypeAPITestCase(APITestCase): """ - Functional test to make sure all the moving parts to create a document - from the API are working correctly + Test the document type API endpoints """ def setUp(self): @@ -31,6 +29,65 @@ class DocumentAPICreateDocumentTestCase(TestCase): username=TEST_ADMIN_USERNAME, email=TEST_ADMIN_EMAIL, password=TEST_ADMIN_PASSWORD ) + + self.client.force_authenticate(user=self.admin_user) + + def testDown(self): + self.admin_user.delete() + + def test_document_type_create(self): + self.assertEqual(DocumentType.objects.all().count(), 0) + + self.client.post(reverse('rest_api:documenttype-list'), {'label': TEST_DOCUMENT_TYPE}) + + self.assertEqual(DocumentType.objects.all().count(), 1) + self.assertEqual(DocumentType.objects.all().first().label, TEST_DOCUMENT_TYPE) + + def test_document_type_edit_via_put(self): + document_type = DocumentType.objects.create(label=TEST_DOCUMENT_TYPE) + + self.client.put( + reverse('rest_api:documenttype-detail', args=[document_type.pk]), + {'label': TEST_DOCUMENT_TYPE + 'edited'} + ) + + document_type = DocumentType.objects.get(pk=document_type.pk) + self.assertEqual(document_type.label, TEST_DOCUMENT_TYPE + 'edited') + + def test_document_type_edit_via_patch(self): + document_type = DocumentType.objects.create(label=TEST_DOCUMENT_TYPE) + + self.client.patch( + reverse('rest_api:documenttype-detail', args=[document_type.pk]), + {'label': TEST_DOCUMENT_TYPE + 'edited'} + ) + + document_type = DocumentType.objects.get(pk=document_type.pk) + self.assertEqual(document_type.label, TEST_DOCUMENT_TYPE + 'edited') + + def test_document_type_delete(self): + document_type = DocumentType.objects.create(label=TEST_DOCUMENT_TYPE) + + self.client.delete( + reverse('rest_api:documenttype-detail', args=(document_type.pk,)) + ) + + self.assertEqual(DocumentType.objects.all().count(), 0) + + +class DocumentAPITestCase(APITestCase): + """ + Test document API endpoints + """ + + def setUp(self): + self.admin_user = User.objects.create_superuser( + username=TEST_ADMIN_USERNAME, email=TEST_ADMIN_EMAIL, + password=TEST_ADMIN_PASSWORD + ) + + self.client.force_authenticate(user=self.admin_user) + self.document_type = DocumentType.objects.create( label=TEST_DOCUMENT_TYPE ) @@ -40,90 +97,133 @@ class DocumentAPICreateDocumentTestCase(TestCase): ocr_settings.save() def tearDown(self): - self.document_type.delete() self.admin_user.delete() + self.document_type.delete() - def test_uploading_a_document_using_token_auth(self): - # Get the an user token - token_client = APIClient() - response = token_client.post( - reverse('auth_token_obtain'), { - 'username': TEST_ADMIN_USERNAME, - 'password': TEST_ADMIN_PASSWORD - } - ) - - # Be able to get authentication token - self.assertEqual(response.status_code, status.HTTP_200_OK) - - # Make sure a token was returned - self.assertTrue('token' in response.content) - - token = loads(response.content)['token'] - - # Create a new client to simulate a different request - document_client = APIClient() - - # Create a blank document with no token in the header - # TODO: Fix, must not be able to create the document with API token - # with open(TEST_SMALL_DOCUMENT_PATH) as file_descriptor: - # response = document_client.post(reverse('document-list'), {'document_type': self.document_type.pk, 'file': file_descriptor}) - - # Make sure toke authentication is working, should fail - # TODO: FIX failing test: self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) - - document_client.credentials(HTTP_AUTHORIZATION='Token ' + token) - - # Create a blank document - with open(TEST_SMALL_DOCUMENT_PATH) as file_descriptor: - document_response = document_client.post( - reverse('document-list'), { + def test_document_upload(self): + with open(TEST_DOCUMENT_PATH) as file_descriptor: + document_response = self.client.post( + reverse('rest_api:document-list'), { 'document_type': self.document_type.pk, 'file': file_descriptor } ) + document_data = loads(document_response.content) + self.assertEqual(document_response.status_code, status.HTTP_201_CREATED) - # The document was created in the DB? self.assertEqual(Document.objects.count(), 1) - new_version_url = reverse( - 'document-new-version', args=[Document.objects.first().pk] - ) - - with open(TEST_DOCUMENT_PATH) as file_descriptor: - response = document_client.post( - new_version_url, {'file': file_descriptor} - ) - - # Make sure the document uploaded correctly document = Document.objects.first() + + self.assertEqual(document.pk, document_data['id']) + + self.assertEqual(document.versions.count(), 1) + self.assertEqual(document.exists(), True) self.assertEqual(document.size, 272213) self.assertEqual(document.file_mimetype, 'application/pdf') self.assertEqual(document.file_mime_encoding, 'binary') - self.assertEqual(document.label, TEST_SMALL_DOCUMENT_FILENAME) + self.assertEqual(document.label, TEST_DOCUMENT_FILENAME) self.assertEqual( document.checksum, 'c637ffab6b8bb026ed3784afdb07663fddc60099853fae2be93890852a69ecf3' ) self.assertEqual(document.page_count, 47) - # Make sure we can edit the document via the API - document_url = reverse( - 'document-detail', args=[Document.objects.first().pk] - ) + def test_document_move_to_trash(self): + with open(TEST_SMALL_DOCUMENT_PATH) as file_object: + document = self.document_type.new_document( + file_object=File(file_object), + ) - response = document_client.post( - document_url, {'description': 'edited test document'} - ) + self.client.delete(reverse('rest_api:document-detail', args=(document.pk,))) - # self.assertTrue(document.description, 'edited test document') - - # Make sure we can delete the document via the API - response = document_client.delete(document_url) - - # The document was deleted from the the DB? self.assertEqual(Document.objects.count(), 0) + self.assertEqual(Document.trash.count(), 1) + + def test_deleted_document_delete_from_trash(self): + with open(TEST_SMALL_DOCUMENT_PATH) as file_object: + document = self.document_type.new_document( + file_object=File(file_object), + ) + + document.delete() + + self.assertEqual(Document.objects.count(), 0) + self.assertEqual(Document.trash.count(), 1) + + self.client.delete(reverse('rest_api:deleteddocument-detail', args=(document.pk,))) + + self.assertEqual(Document.trash.count(), 0) + + def test_deleted_document_restore(self): + with open(TEST_SMALL_DOCUMENT_PATH) as file_object: + document = self.document_type.new_document( + file_object=File(file_object), + ) + + document.delete() + + self.client.post(reverse('rest_api:deleteddocument-restore', args=(document.pk,))) + + self.assertEqual(Document.trash.count(), 0) + self.assertEqual(Document.objects.count(), 1) + + def test_document_new_version_upload(self): + with open(TEST_SMALL_DOCUMENT_PATH) as file_object: + document = self.document_type.new_document( + file_object=File(file_object), + ) + + with open(TEST_DOCUMENT_PATH) as file_descriptor: + response = self.client.post( + reverse( + 'rest_api:document-version-list', args=(document.pk,) + ), { + 'comment': '', + 'file': file_descriptor, + } + ) + print response + + self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) + + self.assertEqual(document.versions.count(), 2) + self.assertEqual(document.exists(), True) + self.assertEqual(document.size, 272213) + self.assertEqual(document.file_mimetype, 'application/pdf') + self.assertEqual(document.file_mime_encoding, 'binary') + self.assertEqual( + document.checksum, + 'c637ffab6b8bb026ed3784afdb07663fddc60099853fae2be93890852a69ecf3' + ) + self.assertEqual(document.page_count, 47) + + def test_document_version_revert(self): + with open(TEST_SMALL_DOCUMENT_PATH) as file_object: + document = self.document_type.new_document( + file_object=File(file_object), + ) + + with open(TEST_DOCUMENT_PATH) as file_object: + document.new_version(file_object=File(file_object)) + + document_version = document.versions.first() + + self.assertEqual(document.versions.count(), 2) + + self.client.post( + reverse( + 'rest_api:documentversion-revert', args=(document_version.pk,) + ) + ) + + self.assertEqual(document.versions.count(), 1) + + self.assertEqual(document_version, document.latest_version) + + #def test_document_set_document_type(self): + # pass diff --git a/mayan/apps/documents/test_models.py b/mayan/apps/documents/test_models.py index be1ef7ef1b..eee2553c99 100644 --- a/mayan/apps/documents/test_models.py +++ b/mayan/apps/documents/test_models.py @@ -18,8 +18,9 @@ TEST_SMALL_DOCUMENT_FILENAME = 'title_page.png' TEST_MULTI_PAGE_TIFF = 'multi_page.tiff' TEST_NON_ASCII_DOCUMENT_FILENAME = 'I18N_title_áéíóúüñÑ.png' TEST_NON_ASCII_COMPRESSED_DOCUMENT_FILENAME = 'I18N_title_áéíóúüñÑ.png.zip' +TEST_DOCUMENT_FILENAME = 'mayan_11_1.pdf' TEST_DOCUMENT_PATH = os.path.join( - settings.BASE_DIR, 'contrib', 'sample_documents', 'mayan_11_1.pdf' + settings.BASE_DIR, 'contrib', 'sample_documents', TEST_DOCUMENT_FILENAME ) TEST_SMALL_DOCUMENT_PATH = os.path.join( settings.BASE_DIR, 'contrib', 'sample_documents', diff --git a/mayan/apps/documents/urls.py b/mayan/apps/documents/urls.py index 964df5f47d..92e64f06b1 100644 --- a/mayan/apps/documents/urls.py +++ b/mayan/apps/documents/urls.py @@ -3,10 +3,12 @@ from __future__ import unicode_literals from django.conf.urls import patterns, url from .api_views import ( - APIDocumentView, APIDocumentImageView, APIDocumentListView, - APIDocumentPageView, APIDocumentTypeDocumentListView, - APIDocumentTypeListView, APIDocumentTypeView, - APIDocumentVersionCreateView, APIDocumentVersionView, + APIDeletedDocumentListView, APIDeletedDocumentRestoreView, + APIDeletedDocumentView, APIDocumentView, APIDocumentListView, + APIDocumentPageImageView, APIDocumentPageView, + APIDocumentTypeDocumentListView, APIDocumentTypeListView, + APIDocumentTypeView, APIDocumentVersionsListView, + APIDocumentVersionRevertView, APIDocumentVersionView, APIRecentDocumentListView ) from .settings import setting_print_size, setting_display_size @@ -229,6 +231,18 @@ urlpatterns = patterns( api_urls = patterns( '', + url( + r'^deleted_documents/$', APIDeletedDocumentListView.as_view(), + name='deleteddocument-list' + ), + url( + r'^deleted_documents/(?P[0-9]+)/$', + APIDeletedDocumentView.as_view(), name='deleteddocument-detail' + ), + url( + r'^deleted_documents/(?P[0-9]+)/restore/$', + APIDeletedDocumentRestoreView.as_view(), name='deleteddocument-restore' + ), url(r'^documents/$', APIDocumentListView.as_view(), name='document-list'), url( r'^documents/recent/$', APIRecentDocumentListView.as_view(), @@ -238,33 +252,37 @@ api_urls = patterns( r'^documents/(?P[0-9]+)/$', APIDocumentView.as_view(), name='document-detail' ), + url( + r'^documents/(?P[0-9]+)/versions/$', + APIDocumentVersionsListView.as_view(), name='document-version-list' + ), url( r'^document_version/(?P[0-9]+)/$', APIDocumentVersionView.as_view(), name='documentversion-detail' ), + url( + r'^document_version/(?P[0-9]+)/revert/$', + APIDocumentVersionRevertView.as_view(), name='documentversion-revert' + ), url( r'^document_page/(?P[0-9]+)/$', APIDocumentPageView.as_view(), name='documentpage-detail' ), url( - r'^documents/(?P[0-9]+)/image/$', APIDocumentImageView.as_view(), - name='document-image' + r'^document_page/(?P[0-9]+)/image/$', + APIDocumentPageImageView.as_view(), name='documentpage-image' ), url( - r'^documents/(?P[0-9]+)/new_version/$', - APIDocumentVersionCreateView.as_view(), name='document-new-version' - ), - url( - r'^documenttypes/(?P[0-9]+)/documents/$', + r'^document_types/(?P[0-9]+)/documents/$', APIDocumentTypeDocumentListView.as_view(), name='documenttype-document-list' ), url( - r'^documenttypes/(?P[0-9]+)/$', APIDocumentTypeView.as_view(), + r'^document_types/(?P[0-9]+)/$', APIDocumentTypeView.as_view(), name='documenttype-detail' ), url( - r'^documenttypes/$', APIDocumentTypeListView.as_view(), + r'^document_types/$', APIDocumentTypeListView.as_view(), name='documenttype-list' ), ) diff --git a/mayan/apps/documents/widgets.py b/mayan/apps/documents/widgets.py index 962511a95b..5312d477b4 100644 --- a/mayan/apps/documents/widgets.py +++ b/mayan/apps/documents/widgets.py @@ -99,11 +99,12 @@ def document_html_widget(document_page, click_view=None, click_view_arguments=No alt_text = _('Document page image') + if not document_page: + return mark_safe('') + document = document_page.document - page = document_page.page_number query_dict = { - 'page': page, 'zoom': zoom, 'rotation': rotation, 'size': size, @@ -117,12 +118,12 @@ def document_html_widget(document_page, click_view=None, click_view_arguments=No query_string = urlencode(query_dict) preview_view = '%s?%s' % ( - reverse('document-image', args=[document.pk]), query_string + reverse('rest_api:documentpage-image', args=[document_page.pk]), query_string ) result.append( '
' % ( - document.pk, page if page else 1 + document.pk, document_page.page_number if document_page.page_number else 1 ) ) diff --git a/mayan/apps/dynamic_search/apps.py b/mayan/apps/dynamic_search/apps.py index 65187e203c..d4ade792f1 100644 --- a/mayan/apps/dynamic_search/apps.py +++ b/mayan/apps/dynamic_search/apps.py @@ -17,7 +17,7 @@ class DynamicSearchApp(MayanAppConfig): def ready(self): super(DynamicSearchApp, self).ready() - APIEndPoint('search', app_name='dynamic_search') + APIEndPoint(app=self, version_string='1') menu_facet.bind_links( links=(link_search, link_search_advanced), diff --git a/mayan/apps/folders/apps.py b/mayan/apps/folders/apps.py index 1c4e2925d6..6c74bd2824 100644 --- a/mayan/apps/folders/apps.py +++ b/mayan/apps/folders/apps.py @@ -35,7 +35,7 @@ class FoldersApp(MayanAppConfig): def ready(self): super(FoldersApp, self).ready() - APIEndPoint('folders') + APIEndPoint(app=self, version_string='1') ModelPermission.register( model=Document, permissions=( @@ -52,6 +52,11 @@ class FoldersApp(MayanAppConfig): ) ) + SourceColumn( + source=Folder, label=_('Created'), attribute='datetime_created' + ) + SourceColumn(source=Folder, label=_('User'), attribute='user') + menu_facet.bind_links( links=(link_document_folder_list,), sources=(Document,) ) @@ -79,8 +84,3 @@ class FoldersApp(MayanAppConfig): 'folders:document_folder_list', 'folders:folder_add_document' ) ) - - SourceColumn( - source=Folder, label=_('Created'), attribute='datetime_created' - ) - SourceColumn(source=Folder, label=_('User'), attribute='user') diff --git a/mayan/apps/metadata/apps.py b/mayan/apps/metadata/apps.py index 487e1cebe6..76e60071bd 100644 --- a/mayan/apps/metadata/apps.py +++ b/mayan/apps/metadata/apps.py @@ -54,7 +54,7 @@ class MetadataApp(MayanAppConfig): def ready(self): super(MetadataApp, self).ready() - APIEndPoint('metadata') + APIEndPoint(app=self, version_string='1') Document.add_to_class( 'metadata_value_of', DocumentMetadataHelper.constructor diff --git a/mayan/apps/ocr/apps.py b/mayan/apps/ocr/apps.py index bf264eb279..e7013314b8 100644 --- a/mayan/apps/ocr/apps.py +++ b/mayan/apps/ocr/apps.py @@ -55,7 +55,7 @@ class OCRApp(MayanAppConfig): def ready(self): super(OCRApp, self).ready() - APIEndPoint('ocr') + APIEndPoint(app=self, version_string='1') Document.add_to_class('submit_for_ocr', document_ocr_submit) DocumentVersion.add_to_class( diff --git a/mayan/apps/permissions/apps.py b/mayan/apps/permissions/apps.py index 2c0b74831d..943574cc77 100644 --- a/mayan/apps/permissions/apps.py +++ b/mayan/apps/permissions/apps.py @@ -24,7 +24,7 @@ class PermissionsApp(MayanAppConfig): def ready(self): super(PermissionsApp, self).ready() - APIEndPoint('permissions') + APIEndPoint(app=self, version_string='1') menu_object.bind_links( links=( diff --git a/mayan/apps/sources/apps.py b/mayan/apps/sources/apps.py index 5893ad393c..e218560db0 100644 --- a/mayan/apps/sources/apps.py +++ b/mayan/apps/sources/apps.py @@ -45,7 +45,7 @@ class SourcesApp(MayanAppConfig): def ready(self): super(SourcesApp, self).ready() - APIEndPoint('sources') + APIEndPoint(app=self, version_string='1') MissingItem( label=_('Create a document source'), diff --git a/mayan/apps/tags/apps.py b/mayan/apps/tags/apps.py index 64f452aae0..4563497502 100644 --- a/mayan/apps/tags/apps.py +++ b/mayan/apps/tags/apps.py @@ -36,7 +36,7 @@ class TagsApp(MayanAppConfig): def ready(self): super(TagsApp, self).ready() - APIEndPoint('tags') + APIEndPoint(app=self, version_string='1') ModelPermission.register( model=Document, permissions=( diff --git a/mayan/apps/user_management/apps.py b/mayan/apps/user_management/apps.py index 451be0a8c4..e730fb773c 100644 --- a/mayan/apps/user_management/apps.py +++ b/mayan/apps/user_management/apps.py @@ -28,7 +28,7 @@ class UserManagementApp(MayanAppConfig): def ready(self): super(UserManagementApp, self).ready() - APIEndPoint('users', app_name='user_management') + APIEndPoint(app=self, version_string='1') MetadataLookup(description=_('All the groups.'), name='group', value=Group.objects.all()) MetadataLookup(description=_('All the users.'), name='users', value=get_user_model().objects.all()) diff --git a/requirements/common.txt b/requirements/common.txt index 5530cb2ae8..da6ba4b270 100644 --- a/requirements/common.txt +++ b/requirements/common.txt @@ -16,10 +16,10 @@ django-filetransfers==0.1.0 django-pagination==1.0.7 django-model-utils==2.2 django-mptt==0.7.4 -django-rest-swagger==0.2.0 +django-rest-swagger==0.3.3 django-suit==0.2.13 django-widget-tweaks==1.3 -djangorestframework==2.4.4 +djangorestframework==3.1.3 fusepy==2.0.2