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:
Roberto Rosario
2015-08-06 02:51:23 -04:00
parent ea02172a82
commit 960d60c39d
23 changed files with 680 additions and 418 deletions

View File

@@ -319,13 +319,8 @@
function load_document_image(image) { function load_document_image(image) {
$.get( image.attr('data-src'), function(result) { $.get( image.attr('data-src'), function(result) {
if (result.status == 'success') {
image.attr('src', result.data); image.attr('src', result.data);
image.addClass(image.attr('data-post-load-class')); 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() { .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>'); 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>');

View File

@@ -35,7 +35,7 @@ class CheckoutsApp(MayanAppConfig):
def ready(self): def ready(self):
super(CheckoutsApp, self).ready() super(CheckoutsApp, self).ready()
APIEndPoint('checkouts') APIEndPoint(app=self, version_string='1')
Document.add_to_class( Document.add_to_class(
'check_in', 'check_in',

View File

@@ -96,12 +96,13 @@ class CommonApp(MayanAppConfig):
'common:tools_list' 'common:tools_list'
) )
) )
user_logged_in.connect(
user_locale_profile_session_config,
dispatch_uid='user_locale_profile_session_config'
)
post_save.connect( post_save.connect(
user_locale_profile_create, user_locale_profile_create,
dispatch_uid='user_locale_profile_create', dispatch_uid='user_locale_profile_create',
sender=settings.AUTH_USER_MODEL sender=settings.AUTH_USER_MODEL
) )
user_logged_in.connect(
user_locale_profile_session_config,
dispatch_uid='user_locale_profile_session_config'
)

View File

@@ -18,6 +18,10 @@ class ConverterApp(MayanAppConfig):
def ready(self): def ready(self):
super(ConverterApp, self).ready() super(ConverterApp, self).ready()
menu_object.bind_links(
links=(link_transformation_edit, link_transformation_delete),
sources=(Transformation,)
)
menu_sidebar.bind_links( menu_sidebar.bind_links(
links=(link_transformation_create,), sources=(Transformation,) links=(link_transformation_create,), sources=(Transformation,)
) )
@@ -28,7 +32,3 @@ class ConverterApp(MayanAppConfig):
'converter:transformation_list' 'converter:transformation_list'
) )
) )
menu_object.bind_links(
links=(link_transformation_edit, link_transformation_delete),
sources=(Transformation,)
)

View File

@@ -39,7 +39,7 @@ class DocumentIndexingApp(MayanAppConfig):
def ready(self): def ready(self):
super(DocumentIndexingApp, self).ready() super(DocumentIndexingApp, self).ready()
APIEndPoint('indexes', app_name='document_indexing') APIEndPoint(app=self, version_string='1')
app.conf.CELERY_QUEUES.append( app.conf.CELERY_QUEUES.append(
Queue('indexing', Exchange('indexing'), routing_key='indexing'), Queue('indexing', Exchange('indexing'), routing_key='indexing'),
@@ -85,15 +85,6 @@ class DocumentIndexingApp(MayanAppConfig):
menu_setup.bind_links(links=(link_index_setup,)) menu_setup.bind_links(links=(link_index_setup,))
menu_tools.bind_links(links=(link_rebuild_index_instances,)) 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( post_delete.connect(
document_index_delete, dispatch_uid='document_index_delete', document_index_delete, dispatch_uid='document_index_delete',
sender=Document sender=Document
@@ -103,3 +94,12 @@ class DocumentIndexingApp(MayanAppConfig):
dispatch_uid='document_metadata_index_post_delete', dispatch_uid='document_metadata_index_post_delete',
sender=DocumentMetadata 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

View File

@@ -80,7 +80,7 @@ class DocumentsApp(MayanAppConfig):
def ready(self): def ready(self):
super(DocumentsApp, self).ready() super(DocumentsApp, self).ready()
APIEndPoint('documents') APIEndPoint(app=self, version_string='1')
MissingItem( MissingItem(
label=_('Create a document type'), label=_('Create a document type'),

View File

@@ -20,7 +20,9 @@ from converter import (
converter_class, TransformationResize, TransformationRotate, converter_class, TransformationResize, TransformationRotate,
TransformationZoom 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.literals import DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION
from converter.models import Transformation from converter.models import Transformation
from mimetype.api import get_mimetype from mimetype.api import get_mimetype
@@ -150,6 +152,7 @@ class Document(models.Model):
in_trash = models.BooleanField( in_trash = models.BooleanField(
default=False, editable=False, verbose_name=_('In trash?') default=False, editable=False, verbose_name=_('In trash?')
) )
#TODO: set editable to False
deleted_date_time = models.DateTimeField( deleted_date_time = models.DateTimeField(
blank=True, editable=True, null=True, blank=True, editable=True, null=True,
verbose_name=_('Date and time trashed') verbose_name=_('Date and time trashed')
@@ -431,12 +434,11 @@ class DocumentVersion(models.Model):
file_object=file_object, mime_type=self.mimetype file_object=file_object, mime_type=self.mimetype
) )
detected_pages = converter.get_page_count() detected_pages = converter.get_page_count()
except UnknownFileFormat: except PageCountError:
# If converter backend doesn't understand the format, # If converter backend doesn't understand the format,
# use 1 as the total page count # use 1 as the total page count
detected_pages = 1 pass
# TODO: should be no pages instead? else:
with transaction.atomic(): with transaction.atomic():
self.pages.all().delete() self.pages.all().delete()
@@ -670,8 +672,8 @@ class DocumentPage(models.Model):
as_base64 = kwargs.pop('as_base64', False) as_base64 = kwargs.pop('as_base64', False)
transformations = kwargs.pop('transformations', []) transformations = kwargs.pop('transformations', [])
size = kwargs.pop('size', setting_display_size.value) size = kwargs.pop('size', setting_display_size.value)
rotation = kwargs.pop('rotation', DEFAULT_ROTATION) rotation = int(kwargs.pop('rotation', DEFAULT_ROTATION) or DEFAULT_ROTATION)
zoom_level = kwargs.pop('zoom', DEFAULT_ZOOM_LEVEL) zoom_level = int(kwargs.pop('zoom', DEFAULT_ZOOM_LEVEL) or DEFAULT_ZOOM_LEVEL)
if zoom_level < setting_zoom_min_level.value: if zoom_level < setting_zoom_min_level.value:
zoom_level = setting_zoom_min_level.value zoom_level = setting_zoom_min_level.value

View File

@@ -2,66 +2,181 @@ from __future__ import unicode_literals
from rest_framework import serializers from rest_framework import serializers
from .models import (Document, DocumentVersion, DocumentPage, DocumentType, from common.models import SharedUploadedFile
RecentDocument)
from .settings import setting_language, setting_language_choices 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): class DocumentPageSerializer(serializers.HyperlinkedModelSerializer):
image = serializers.HyperlinkedIdentityField(
view_name='rest_api:documentpage-image'
)
class Meta: class Meta:
extra_kwargs = {
'url': {'view_name': 'rest_api:documentpage-detail'},
'document_version': {'view_name': 'rest_api:documentversion-detail'}
}
model = DocumentPage model = DocumentPage
class DocumentVersionSerializer(serializers.HyperlinkedModelSerializer): class DocumentTypeSerializer(serializers.HyperlinkedModelSerializer):
pages = DocumentPageSerializer(many=True, required=False, read_only=True) documents = serializers.HyperlinkedIdentityField(
view_name='rest_api:documenttype-document-list',
class Meta: )
model = DocumentVersion documents_count = serializers.SerializerMethodField()
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')
def get_documents_count(self, obj): def get_documents_count(self, obj):
return obj.documents.count() return obj.documents.count()
class Meta:
class DocumentSerializer(serializers.ModelSerializer): extra_kwargs = {
versions = DocumentVersionSerializer(many=True, read_only=True) 'url': {'view_name': 'rest_api:documenttype-detail'},
# TODO: Deprecate, move this as an entry point of DocumentVersion's pages }
image = serializers.HyperlinkedIdentityField(view_name='document-image') fields = (
new_version = serializers.HyperlinkedIdentityField( 'delete_time_period', 'delete_time_unit', 'documents',
view_name='document-new-version' '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: 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 = ( fields = (
'id', 'label', 'image', 'new_version', 'uuid', 'document_type', 'date_added', 'deleted_date_time', 'description', 'document_type',
'description', 'date_added', 'versions' '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 model = Document
class NewDocumentSerializer(serializers.Serializer): class NewDocumentSerializer(serializers.ModelSerializer):
description = serializers.CharField(required=False) file = serializers.FileField(write_only=True)
document_type = serializers.IntegerField()
file = serializers.FileField() def save(self, _user):
label = serializers.CharField(required=False) document = Document.objects.create(
language = serializers.ChoiceField( description=self.validated_data.get('description', ''),
blank_display_value=None, choices=setting_language_choices.value, document_type=self.validated_data['document_type'],
default=setting_language.value, required=False 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): class RecentDocumentSerializer(serializers.ModelSerializer):

View File

@@ -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: with shared_file.open() as file_object:
document_version = DocumentVersion( document_version = DocumentVersion(
document=document, comment=comment, file=file_object document=document, comment=comment or '', file=file_object
) )
try: try:
document_version.save(_user=user) document_version.save(_user=user)

View File

@@ -5,25 +5,23 @@ from __future__ import unicode_literals
from json import loads from json import loads
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.files import File
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.test import TestCase
from rest_framework import status from rest_framework import status
from rest_framework.test import APIClient from rest_framework.test import APITestCase
from .models import Document, DocumentType from .models import Document, DocumentType
from .test_models import ( from .test_models import (
TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL, TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME,
TEST_SMALL_DOCUMENT_FILENAME, TEST_DOCUMENT_PATH, TEST_DOCUMENT_FILENAME, TEST_DOCUMENT_PATH, TEST_DOCUMENT_TYPE,
TEST_SMALL_DOCUMENT_PATH, TEST_SMALL_DOCUMENT_FILENAME, TEST_SMALL_DOCUMENT_PATH,
TEST_DOCUMENT_TYPE
) )
class DocumentAPICreateDocumentTestCase(TestCase): class DocumentTypeAPITestCase(APITestCase):
""" """
Functional test to make sure all the moving parts to create a document Test the document type API endpoints
from the API are working correctly
""" """
def setUp(self): def setUp(self):
@@ -31,6 +29,65 @@ class DocumentAPICreateDocumentTestCase(TestCase):
username=TEST_ADMIN_USERNAME, email=TEST_ADMIN_EMAIL, username=TEST_ADMIN_USERNAME, email=TEST_ADMIN_EMAIL,
password=TEST_ADMIN_PASSWORD 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( self.document_type = DocumentType.objects.create(
label=TEST_DOCUMENT_TYPE label=TEST_DOCUMENT_TYPE
) )
@@ -40,90 +97,133 @@ class DocumentAPICreateDocumentTestCase(TestCase):
ocr_settings.save() ocr_settings.save()
def tearDown(self): def tearDown(self):
self.document_type.delete()
self.admin_user.delete() self.admin_user.delete()
self.document_type.delete()
def test_uploading_a_document_using_token_auth(self): def test_document_upload(self):
# Get the an user token with open(TEST_DOCUMENT_PATH) as file_descriptor:
token_client = APIClient() document_response = self.client.post(
response = token_client.post( reverse('rest_api:document-list'), {
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'), {
'document_type': self.document_type.pk, 'document_type': self.document_type.pk,
'file': file_descriptor 'file': file_descriptor
} }
) )
document_data = loads(document_response.content)
self.assertEqual(document_response.status_code, status.HTTP_201_CREATED) self.assertEqual(document_response.status_code, status.HTTP_201_CREATED)
# The document was created in the DB?
self.assertEqual(Document.objects.count(), 1) 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() 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.exists(), True)
self.assertEqual(document.size, 272213) self.assertEqual(document.size, 272213)
self.assertEqual(document.file_mimetype, 'application/pdf') self.assertEqual(document.file_mimetype, 'application/pdf')
self.assertEqual(document.file_mime_encoding, 'binary') self.assertEqual(document.file_mime_encoding, 'binary')
self.assertEqual(document.label, TEST_SMALL_DOCUMENT_FILENAME) self.assertEqual(document.label, TEST_DOCUMENT_FILENAME)
self.assertEqual( self.assertEqual(
document.checksum, document.checksum,
'c637ffab6b8bb026ed3784afdb07663fddc60099853fae2be93890852a69ecf3' 'c637ffab6b8bb026ed3784afdb07663fddc60099853fae2be93890852a69ecf3'
) )
self.assertEqual(document.page_count, 47) self.assertEqual(document.page_count, 47)
# Make sure we can edit the document via the API def test_document_move_to_trash(self):
document_url = reverse( with open(TEST_SMALL_DOCUMENT_PATH) as file_object:
'document-detail', args=[Document.objects.first().pk] document = self.document_type.new_document(
file_object=File(file_object),
) )
response = document_client.post( self.client.delete(reverse('rest_api:document-detail', args=(document.pk,)))
document_url, {'description': 'edited test document'}
)
# 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.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

View File

@@ -18,8 +18,9 @@ TEST_SMALL_DOCUMENT_FILENAME = 'title_page.png'
TEST_MULTI_PAGE_TIFF = 'multi_page.tiff' TEST_MULTI_PAGE_TIFF = 'multi_page.tiff'
TEST_NON_ASCII_DOCUMENT_FILENAME = 'I18N_title_áéíóúüñÑ.png' TEST_NON_ASCII_DOCUMENT_FILENAME = 'I18N_title_áéíóúüñÑ.png'
TEST_NON_ASCII_COMPRESSED_DOCUMENT_FILENAME = 'I18N_title_áéíóúüñÑ.png.zip' TEST_NON_ASCII_COMPRESSED_DOCUMENT_FILENAME = 'I18N_title_áéíóúüñÑ.png.zip'
TEST_DOCUMENT_FILENAME = 'mayan_11_1.pdf'
TEST_DOCUMENT_PATH = os.path.join( 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( TEST_SMALL_DOCUMENT_PATH = os.path.join(
settings.BASE_DIR, 'contrib', 'sample_documents', settings.BASE_DIR, 'contrib', 'sample_documents',

View File

@@ -3,10 +3,12 @@ from __future__ import unicode_literals
from django.conf.urls import patterns, url from django.conf.urls import patterns, url
from .api_views import ( from .api_views import (
APIDocumentView, APIDocumentImageView, APIDocumentListView, APIDeletedDocumentListView, APIDeletedDocumentRestoreView,
APIDocumentPageView, APIDocumentTypeDocumentListView, APIDeletedDocumentView, APIDocumentView, APIDocumentListView,
APIDocumentTypeListView, APIDocumentTypeView, APIDocumentPageImageView, APIDocumentPageView,
APIDocumentVersionCreateView, APIDocumentVersionView, APIDocumentTypeDocumentListView, APIDocumentTypeListView,
APIDocumentTypeView, APIDocumentVersionsListView,
APIDocumentVersionRevertView, APIDocumentVersionView,
APIRecentDocumentListView APIRecentDocumentListView
) )
from .settings import setting_print_size, setting_display_size from .settings import setting_print_size, setting_display_size
@@ -229,6 +231,18 @@ urlpatterns = patterns(
api_urls = 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/$', APIDocumentListView.as_view(), name='document-list'),
url( url(
r'^documents/recent/$', APIRecentDocumentListView.as_view(), r'^documents/recent/$', APIRecentDocumentListView.as_view(),
@@ -238,33 +252,37 @@ api_urls = patterns(
r'^documents/(?P<pk>[0-9]+)/$', APIDocumentView.as_view(), r'^documents/(?P<pk>[0-9]+)/$', APIDocumentView.as_view(),
name='document-detail' name='document-detail'
), ),
url(
r'^documents/(?P<pk>[0-9]+)/versions/$',
APIDocumentVersionsListView.as_view(), name='document-version-list'
),
url( url(
r'^document_version/(?P<pk>[0-9]+)/$', r'^document_version/(?P<pk>[0-9]+)/$',
APIDocumentVersionView.as_view(), name='documentversion-detail' APIDocumentVersionView.as_view(), name='documentversion-detail'
), ),
url(
r'^document_version/(?P<pk>[0-9]+)/revert/$',
APIDocumentVersionRevertView.as_view(), name='documentversion-revert'
),
url( url(
r'^document_page/(?P<pk>[0-9]+)/$', APIDocumentPageView.as_view(), r'^document_page/(?P<pk>[0-9]+)/$', APIDocumentPageView.as_view(),
name='documentpage-detail' name='documentpage-detail'
), ),
url( url(
r'^documents/(?P<pk>[0-9]+)/image/$', APIDocumentImageView.as_view(), r'^document_page/(?P<pk>[0-9]+)/image/$',
name='document-image' APIDocumentPageImageView.as_view(), name='documentpage-image'
), ),
url( url(
r'^documents/(?P<pk>[0-9]+)/new_version/$', r'^document_types/(?P<pk>[0-9]+)/documents/$',
APIDocumentVersionCreateView.as_view(), name='document-new-version'
),
url(
r'^documenttypes/(?P<pk>[0-9]+)/documents/$',
APIDocumentTypeDocumentListView.as_view(), APIDocumentTypeDocumentListView.as_view(),
name='documenttype-document-list' name='documenttype-document-list'
), ),
url( url(
r'^documenttypes/(?P<pk>[0-9]+)/$', APIDocumentTypeView.as_view(), r'^document_types/(?P<pk>[0-9]+)/$', APIDocumentTypeView.as_view(),
name='documenttype-detail' name='documenttype-detail'
), ),
url( url(
r'^documenttypes/$', APIDocumentTypeListView.as_view(), r'^document_types/$', APIDocumentTypeListView.as_view(),
name='documenttype-list' name='documenttype-list'
), ),
) )

View File

@@ -99,11 +99,12 @@ def document_html_widget(document_page, click_view=None, click_view_arguments=No
alt_text = _('Document page image') 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 document = document_page.document
page = document_page.page_number
query_dict = { query_dict = {
'page': page,
'zoom': zoom, 'zoom': zoom,
'rotation': rotation, 'rotation': rotation,
'size': size, 'size': size,
@@ -117,12 +118,12 @@ def document_html_widget(document_page, click_view=None, click_view_arguments=No
query_string = urlencode(query_dict) query_string = urlencode(query_dict)
preview_view = '%s?%s' % ( 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( result.append(
'<div class="tc" id="document-%d-%d">' % ( '<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
) )
) )

View File

@@ -17,7 +17,7 @@ class DynamicSearchApp(MayanAppConfig):
def ready(self): def ready(self):
super(DynamicSearchApp, self).ready() super(DynamicSearchApp, self).ready()
APIEndPoint('search', app_name='dynamic_search') APIEndPoint(app=self, version_string='1')
menu_facet.bind_links( menu_facet.bind_links(
links=(link_search, link_search_advanced), links=(link_search, link_search_advanced),

View File

@@ -35,7 +35,7 @@ class FoldersApp(MayanAppConfig):
def ready(self): def ready(self):
super(FoldersApp, self).ready() super(FoldersApp, self).ready()
APIEndPoint('folders') APIEndPoint(app=self, version_string='1')
ModelPermission.register( ModelPermission.register(
model=Document, permissions=( 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( menu_facet.bind_links(
links=(link_document_folder_list,), sources=(Document,) links=(link_document_folder_list,), sources=(Document,)
) )
@@ -79,8 +84,3 @@ class FoldersApp(MayanAppConfig):
'folders:document_folder_list', 'folders:folder_add_document' 'folders:document_folder_list', 'folders:folder_add_document'
) )
) )
SourceColumn(
source=Folder, label=_('Created'), attribute='datetime_created'
)
SourceColumn(source=Folder, label=_('User'), attribute='user')

View File

@@ -54,7 +54,7 @@ class MetadataApp(MayanAppConfig):
def ready(self): def ready(self):
super(MetadataApp, self).ready() super(MetadataApp, self).ready()
APIEndPoint('metadata') APIEndPoint(app=self, version_string='1')
Document.add_to_class( Document.add_to_class(
'metadata_value_of', DocumentMetadataHelper.constructor 'metadata_value_of', DocumentMetadataHelper.constructor

View File

@@ -55,7 +55,7 @@ class OCRApp(MayanAppConfig):
def ready(self): def ready(self):
super(OCRApp, self).ready() super(OCRApp, self).ready()
APIEndPoint('ocr') APIEndPoint(app=self, version_string='1')
Document.add_to_class('submit_for_ocr', document_ocr_submit) Document.add_to_class('submit_for_ocr', document_ocr_submit)
DocumentVersion.add_to_class( DocumentVersion.add_to_class(

View File

@@ -24,7 +24,7 @@ class PermissionsApp(MayanAppConfig):
def ready(self): def ready(self):
super(PermissionsApp, self).ready() super(PermissionsApp, self).ready()
APIEndPoint('permissions') APIEndPoint(app=self, version_string='1')
menu_object.bind_links( menu_object.bind_links(
links=( links=(

View File

@@ -45,7 +45,7 @@ class SourcesApp(MayanAppConfig):
def ready(self): def ready(self):
super(SourcesApp, self).ready() super(SourcesApp, self).ready()
APIEndPoint('sources') APIEndPoint(app=self, version_string='1')
MissingItem( MissingItem(
label=_('Create a document source'), label=_('Create a document source'),

View File

@@ -36,7 +36,7 @@ class TagsApp(MayanAppConfig):
def ready(self): def ready(self):
super(TagsApp, self).ready() super(TagsApp, self).ready()
APIEndPoint('tags') APIEndPoint(app=self, version_string='1')
ModelPermission.register( ModelPermission.register(
model=Document, permissions=( model=Document, permissions=(

View File

@@ -28,7 +28,7 @@ class UserManagementApp(MayanAppConfig):
def ready(self): def ready(self):
super(UserManagementApp, self).ready() 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 groups.'), name='group', value=Group.objects.all())
MetadataLookup(description=_('All the users.'), name='users', value=get_user_model().objects.all()) MetadataLookup(description=_('All the users.'), name='users', value=get_user_model().objects.all())

View File

@@ -16,10 +16,10 @@ django-filetransfers==0.1.0
django-pagination==1.0.7 django-pagination==1.0.7
django-model-utils==2.2 django-model-utils==2.2
django-mptt==0.7.4 django-mptt==0.7.4
django-rest-swagger==0.2.0 django-rest-swagger==0.3.3
django-suit==0.2.13 django-suit==0.2.13
django-widget-tweaks==1.3 django-widget-tweaks==1.3
djangorestframework==2.4.4 djangorestframework==3.1.3
fusepy==2.0.2 fusepy==2.0.2