diff --git a/mayan/apps/documents/api_views.py b/mayan/apps/documents/api_views.py index ef9923374c..5a67fdae30 100644 --- a/mayan/apps/documents/api_views.py +++ b/mayan/apps/documents/api_views.py @@ -1,10 +1,13 @@ from __future__ import absolute_import +import tempfile + from django.core.exceptions import PermissionDenied from django.shortcuts import get_object_or_404 from rest_framework import generics, status from rest_framework.response import Response +from rest_framework.settings import api_settings from acls.models import AccessEntry from converter.exceptions import UnkownConvertError, UnknownFileFormat @@ -26,14 +29,15 @@ from .permissions import (PERMISSION_DOCUMENT_CREATE, PERMISSION_DOCUMENT_TYPE_VIEW) from .serializers import (DocumentImageSerializer, DocumentPageSerializer, DocumentSerializer, DocumentTypeSerializer, - DocumentVersionSerializer) + DocumentVersionSerializer, NewDocumentSerializer) from .settings import DISPLAY_SIZE, ZOOM_MAX_LEVEL, ZOOM_MIN_LEVEL -from .tasks import task_get_document_image +from .tasks import task_get_document_image, task_new_document + DOCUMENT_IMAGE_TASK_TIMEOUT = 10 -class APIDocumentListView(generics.ListCreateAPIView): +class APIDocumentListView(generics.ListAPIView): """ Returns a list of all the documents. """ @@ -44,8 +48,51 @@ class APIDocumentListView(generics.ListCreateAPIView): permission_classes = (MayanPermission,) filter_backends = (MayanObjectPermissionsFilter,) mayan_object_permissions = {'GET': [PERMISSION_DOCUMENT_VIEW]} + + +class APINewDocumentView(generics.GenericAPIView): + serializer_class = NewDocumentSerializer + + permission_classes = (MayanPermission,) mayan_view_permissions = {'POST': [PERMISSION_DOCUMENT_CREATE]} + def post(self, request, *args, **kwargs): + """Create a new document.""" + + serializer = self.get_serializer(data=request.DATA, files=request.FILES) + + if serializer.is_valid(): + print serializer.data + temporary_file = tempfile.NamedTemporaryFile(delete=False) + source_file = request.FILES['file'] + for chunk in source_file.chunks(): + temporary_file.write(chunk) + temporary_file.close() + source_file.close() + + task_new_document.apply_async(kwargs=dict( + file_path=temporary_file.name, + document_type_id=serializer.data['document_type'], + description=serializer.data['description'], + expand=serializer.data['expand'], + label=serializer.data['label'], + language=serializer.data['language'], + user_id=serializer.data['user'] + ), queue='uploads') + + + headers = self.get_success_headers(serializer.data) + return Response(serializer.data, status=status.HTTP_202_ACCEPTED, + headers=headers) + + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + def get_success_headers(self, data): + try: + return {'Location': data[api_settings.URL_FIELD_NAME]} + except (TypeError, KeyError): + return {} + class APIDocumentView(generics.RetrieveUpdateDestroyAPIView): """ diff --git a/mayan/apps/documents/managers.py b/mayan/apps/documents/managers.py index d8db4cb645..768fd7abe4 100644 --- a/mayan/apps/documents/managers.py +++ b/mayan/apps/documents/managers.py @@ -1,11 +1,16 @@ from __future__ import absolute_import from ast import literal_eval +import logging from django.db import models, transaction +from common.compressed_files import CompressedFile, NotACompressedFile + from .settings import RECENT_COUNT +logger = logging.getLogger(__name__) + class DocumentPageTransformationManager(models.Manager): def get_for_document_page(self, document_page): @@ -54,9 +59,38 @@ class DocumentTypeManager(models.Manager): class DocumentManager(models.Manager): + def new_document(self, document_type, file_object, label, command_line=False, description=None, expand=False, language=None, user=None): + documents_created = [] + is_compressed = None + + if expand: + try: + compressed_file = CompressedFile(file_object) + count = 1 + for compressed_file_child in compressed_file.children(): + if command_line: + print 'Uploading file #%d: %s' % (count, fp) + documents_created.append(self.upload_single_document(document_type=document_type, file_object=compressed_file_child, description=description, label=unicode(fp), language=language, user=user)) + compressed_file_child.close() + count += 1 + + except NotACompressedFile: + is_compressed = False + logging.debug('Exception: NotACompressedFile') + if command_line: + raise + documents_created.append(self.upload_single_document(document_type=document_type, file_object=file_object, description=description, label=label, language=language, user=user)) + else: + is_compressed = True + else: + documents_created.append(self.upload_single_document(document_type=document_type, file_object=file_object, description=description, label=label, language=language, user=user)) + + file_object.close() + return documents_created + @transaction.atomic - def new_document(self, file_object, document_type, label, user=None, description=None, language=None): - document = self.model(document_type=document_type, label=label, - description=description, language=language) + def upload_single_document(self, document_type, file_object, label, description=None, language=None, user=None): + document = self.model(description=description, document_type=document_type, language=language, label=label) document.save(user=user) - return document.new_version(file=file_object, user=user) + document.new_version(file=file_object, user=user) + return document diff --git a/mayan/apps/documents/serializers.py b/mayan/apps/documents/serializers.py index 44302240db..728b2753cc 100644 --- a/mayan/apps/documents/serializers.py +++ b/mayan/apps/documents/serializers.py @@ -1,7 +1,10 @@ from __future__ import absolute_import +from django.contrib.auth.models import User + from rest_framework import serializers +from .literals import LANGUAGE_CHOICES from .models import Document, DocumentVersion, DocumentPage, DocumentType @@ -25,6 +28,7 @@ class DocumentImageSerializer(serializers.Serializer): class DocumentSerializer(serializers.HyperlinkedModelSerializer): 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') @@ -33,9 +37,20 @@ class DocumentSerializer(serializers.HyperlinkedModelSerializer): model = Document -class DocumentTypeSerializer(serializers.HyperlinkedModelSerializer): +class DocumentTypeSerializer(serializers.ModelSerializer): documents = serializers.HyperlinkedIdentityField(view_name='documenttype-document-list') class Meta: model = DocumentType - fields = ('id', 'url', 'name', 'documents') + fields = ('id', 'name', 'documents') + + +class NewDocumentSerializer(serializers.Serializer): + description = serializers.CharField(required=False) + document_type = DocumentTypeSerializer() + document_type = serializers.ChoiceField(choices=[(document_type.pk, document_type) for document_type in DocumentType.objects.all()]) + expand = serializers.BooleanField(default=False) + file = serializers.FileField() + label = serializers.CharField() + language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, blank_display_value=None, required=False) + user = serializers.ChoiceField(required=False, choices=[(user.pk, user) for user in User.objects.all()]) diff --git a/mayan/apps/documents/tasks.py b/mayan/apps/documents/tasks.py index afbd24214b..19783679f0 100644 --- a/mayan/apps/documents/tasks.py +++ b/mayan/apps/documents/tasks.py @@ -1,8 +1,11 @@ import logging +from django.contrib.auth.models import User +from django.core.files import File + from mayan.celery import app -from .models import Document, DocumentVersion +from .models import Document, DocumentType, DocumentVersion logger = logging.getLogger(__name__) @@ -26,3 +29,26 @@ def task_clear_image_cache(): def task_update_page_count(version_id): document_version = DocumentVersion.objects.get(pk=version_id) document_version.update_page_count() + + +@app.task(ignore_result=True) +def task_new_document(document_type_id, file_path, label, description=None, expand=False, language=None, user_id=None): + document_type = DocumentType.objects.get(pk=document_type_id) + + if user_id: + user = User.objects.get(pk=user_id) + else: + user = None + + with File(file=open(file_path, mode='rb')) as file_object: + new_version = Document.objects.new_document(document_type=document_type, expand=expand, file_object=file_object, label=label, description=description, language=language, user=user) + + # TODO: Report/record how was file uploaded + # if result['is_compressed'] is None: + # messages.success(request, _(u'File uploaded successfully.')) + + # if result['is_compressed'] is True: + # messages.success(request, _(u'File uncompressed successfully and uploaded as individual files.')) + + # if result['is_compressed'] is False: + # messages.warning(request, _(u'File was not a compressed file, uploaded as it was.')) diff --git a/mayan/apps/documents/urls.py b/mayan/apps/documents/urls.py index 9e52d79906..f474aab46c 100644 --- a/mayan/apps/documents/urls.py +++ b/mayan/apps/documents/urls.py @@ -5,7 +5,8 @@ from django.conf.urls import patterns, url from .api_views import (APIDocumentView, APIDocumentImageView, APIDocumentListView, APIDocumentPageView, APIDocumentTypeDocumentListView, APIDocumentTypeListView, APIDocumentTypeView, - APIDocumentVersionCreateView, APIDocumentVersionView) + APIDocumentVersionCreateView, APIDocumentVersionView, + APINewDocumentView) from .settings import PRINT_SIZE, DISPLAY_SIZE from .views import DocumentListView @@ -72,6 +73,7 @@ urlpatterns = patterns('documents.views', api_urls = patterns('', url(r'^documents/$', APIDocumentListView.as_view(), name='document-list'), + url(r'^documents/new/$', APINewDocumentView.as_view(), name='newdocument-view'), url(r'^documents/(?P[0-9]+)/$', APIDocumentView.as_view(), name='document-detail'), url(r'^document_version/(?P[0-9]+)/$', APIDocumentVersionView.as_view(), name='documentversion-detail'), url(r'^document_page/(?P[0-9]+)/$', APIDocumentPageView.as_view(), name='documentpage-detail'),