Refactor rest_api app and the method end points are registered. All apps API URL endpoints are now registered under the 'rest_api' namespace.
Update DRF and DRF swagger versions. Update all apps API registration method.
This commit is contained in:
@@ -319,13 +319,8 @@
|
||||
|
||||
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('<span class="fa-stack fa-lg"><i class="fa fa-file-o fa-stack-2x"></i><i class="fa fa-times fa-stack-1x text-danger"></i></span>');
|
||||
set_image_noninteractive(image);
|
||||
}
|
||||
})
|
||||
.fail(function() {
|
||||
image.parent().parent().html('<span class="fa-stack fa-lg"><i class="fa fa-file-o fa-stack-2x"></i><i class="fa fa-times fa-stack-1x text-danger"></i></span>');
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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'
|
||||
)
|
||||
|
||||
@@ -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,)
|
||||
)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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'),
|
||||
|
||||
@@ -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,12 +434,11 @@ 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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 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'
|
||||
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'
|
||||
)
|
||||
document_type = DocumentTypeSerializer()
|
||||
model = DocumentType
|
||||
|
||||
|
||||
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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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<pk>[0-9]+)/$',
|
||||
APIDeletedDocumentView.as_view(), name='deleteddocument-detail'
|
||||
),
|
||||
url(
|
||||
r'^deleted_documents/(?P<pk>[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<pk>[0-9]+)/$', APIDocumentView.as_view(),
|
||||
name='document-detail'
|
||||
),
|
||||
url(
|
||||
r'^documents/(?P<pk>[0-9]+)/versions/$',
|
||||
APIDocumentVersionsListView.as_view(), name='document-version-list'
|
||||
),
|
||||
url(
|
||||
r'^document_version/(?P<pk>[0-9]+)/$',
|
||||
APIDocumentVersionView.as_view(), name='documentversion-detail'
|
||||
),
|
||||
url(
|
||||
r'^document_version/(?P<pk>[0-9]+)/revert/$',
|
||||
APIDocumentVersionRevertView.as_view(), name='documentversion-revert'
|
||||
),
|
||||
url(
|
||||
r'^document_page/(?P<pk>[0-9]+)/$', APIDocumentPageView.as_view(),
|
||||
name='documentpage-detail'
|
||||
),
|
||||
url(
|
||||
r'^documents/(?P<pk>[0-9]+)/image/$', APIDocumentImageView.as_view(),
|
||||
name='document-image'
|
||||
r'^document_page/(?P<pk>[0-9]+)/image/$',
|
||||
APIDocumentPageImageView.as_view(), name='documentpage-image'
|
||||
),
|
||||
url(
|
||||
r'^documents/(?P<pk>[0-9]+)/new_version/$',
|
||||
APIDocumentVersionCreateView.as_view(), name='document-new-version'
|
||||
),
|
||||
url(
|
||||
r'^documenttypes/(?P<pk>[0-9]+)/documents/$',
|
||||
r'^document_types/(?P<pk>[0-9]+)/documents/$',
|
||||
APIDocumentTypeDocumentListView.as_view(),
|
||||
name='documenttype-document-list'
|
||||
),
|
||||
url(
|
||||
r'^documenttypes/(?P<pk>[0-9]+)/$', APIDocumentTypeView.as_view(),
|
||||
r'^document_types/(?P<pk>[0-9]+)/$', APIDocumentTypeView.as_view(),
|
||||
name='documenttype-detail'
|
||||
),
|
||||
url(
|
||||
r'^documenttypes/$', APIDocumentTypeListView.as_view(),
|
||||
r'^document_types/$', APIDocumentTypeListView.as_view(),
|
||||
name='documenttype-list'
|
||||
),
|
||||
)
|
||||
|
||||
@@ -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('<span class="fa-stack fa-lg"><i class="fa fa-file-o fa-stack-2x"></i><i class="fa fa-question fa-stack-1x text-danger"></i></span>')
|
||||
|
||||
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(
|
||||
'<div class="tc" id="document-%d-%d">' % (
|
||||
document.pk, page if page else 1
|
||||
document.pk, document_page.page_number if document_page.page_number else 1
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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=(
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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=(
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user