Refactor the parsing app API
Add additional API and view tests. Add success and multi document titles strings. Make use of external mixin in the document type submit view. Puntuate all view text strings. Signed-off-by: Roberto Rosario <Roberto.Rosario@mayan-edms.com>
This commit is contained in:
@@ -2,47 +2,104 @@ from __future__ import absolute_import, unicode_literals
|
|||||||
|
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
|
|
||||||
from rest_framework import generics
|
from rest_framework import status
|
||||||
|
from rest_framework.decorators import action
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from mayan.apps.documents.models import Document
|
from mayan.apps.documents.models import Document, DocumentVersion
|
||||||
from mayan.apps.rest_api.permissions import MayanPermission
|
from mayan.apps.rest_api.viewsets import MayanAPIViewSet, MayanAPIGenericViewSet
|
||||||
|
|
||||||
from .models import DocumentPageContent
|
from .permissions import permission_content_view, permission_parse_document
|
||||||
from .permissions import permission_content_view
|
from .serializers import (
|
||||||
from .serializers import DocumentPageContentSerializer
|
DocumentParsingSerializer, DocumentPageParsingSerializer,
|
||||||
|
DocumentVersionParsingSerializer
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class APIDocumentPageContentView(generics.RetrieveAPIView):
|
class DocumentParsingAPIViewSet(MayanAPIGenericViewSet):
|
||||||
"""
|
lookup_url_kwarg = 'document_id'
|
||||||
Returns the content of the selected document page.
|
object_permission_map = {
|
||||||
"""
|
'parsing_content': permission_content_view,
|
||||||
lookup_url_kwarg = 'document_page_id'
|
'parsing_submit': permission_parse_document,
|
||||||
mayan_object_permissions = {
|
|
||||||
'GET': (permission_content_view,),
|
|
||||||
}
|
}
|
||||||
permission_classes = (MayanPermission,)
|
queryset = Document.objects.all()
|
||||||
serializer_class = DocumentPageContentSerializer
|
serializer_class = DocumentParsingSerializer
|
||||||
|
|
||||||
def get_document(self):
|
@action(
|
||||||
return get_object_or_404(klass=Document, pk=self.kwargs['document_id'])
|
detail=True, url_name='content', url_path='parsing'
|
||||||
|
)
|
||||||
def get_document_version(self):
|
def parsing_content(self, request, *args, **kwargs):
|
||||||
return get_object_or_404(
|
instance = self.get_object()
|
||||||
klass=self.get_document().versions.all(),
|
serializer = self.get_serializer(instance)
|
||||||
pk=self.kwargs['document_version_id']
|
headers = self.get_success_headers(data=serializer.data)
|
||||||
|
return Response(
|
||||||
|
serializer.data, status=status.HTTP_200_OK, headers=headers
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_queryset(self):
|
@action(
|
||||||
return self.get_document_version().pages.all()
|
detail=True, methods=('post',), url_name='submit',
|
||||||
|
url_path='parsing/submit'
|
||||||
def retrieve(self, request, *args, **kwargs):
|
)
|
||||||
|
def parsing_submit(self, request, *args, **kwargs):
|
||||||
instance = self.get_object()
|
instance = self.get_object()
|
||||||
|
instance.submit_for_parsing(_user=request.user)
|
||||||
|
return Response(
|
||||||
|
data=None, status=status.HTTP_202_ACCEPTED
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
|
||||||
content = instance.content
|
|
||||||
except DocumentPageContent.DoesNotExist:
|
|
||||||
content = DocumentPageContent.objects.none()
|
|
||||||
|
|
||||||
serializer = self.get_serializer(content)
|
class DocumentVersionParsingAPIViewSet(MayanAPIViewSet):
|
||||||
return Response(serializer.data)
|
lookup_url_kwarg = 'document_version_id'
|
||||||
|
object_permission_map = {
|
||||||
|
'parsing_content': permission_content_view,
|
||||||
|
'parsing_submit': permission_parse_document,
|
||||||
|
}
|
||||||
|
queryset = DocumentVersion.objects.all()
|
||||||
|
serializer_class = DocumentVersionParsingSerializer
|
||||||
|
|
||||||
|
@action(
|
||||||
|
detail=True, url_name='content', url_path='parsing'
|
||||||
|
)
|
||||||
|
def parsing_content(self, request, *args, **kwargs):
|
||||||
|
instance = self.get_object()
|
||||||
|
serializer = self.get_serializer(instance)
|
||||||
|
headers = self.get_success_headers(data=serializer.data)
|
||||||
|
return Response(
|
||||||
|
serializer.data, status=status.HTTP_200_OK, headers=headers
|
||||||
|
)
|
||||||
|
|
||||||
|
@action(
|
||||||
|
detail=True, methods=('post',), url_name='submit',
|
||||||
|
url_path='parsing/submit'
|
||||||
|
)
|
||||||
|
def parsing_submit(self, request, *args, **kwargs):
|
||||||
|
instance = self.get_object()
|
||||||
|
instance.submit_for_parsing(_user=request.user)
|
||||||
|
return Response(
|
||||||
|
data=None, status=status.HTTP_202_ACCEPTED
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentPageParsingAPIViewSet(MayanAPIGenericViewSet):
|
||||||
|
lookup_url_kwarg = 'document_page_id'
|
||||||
|
object_permission_map = {
|
||||||
|
'parsing_content': permission_content_view,
|
||||||
|
}
|
||||||
|
serializer_class = DocumentPageParsingSerializer
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return get_object_or_404(
|
||||||
|
klass=DocumentVersion, document_id=self.kwargs['document_id'],
|
||||||
|
pk=self.kwargs['document_version_id']
|
||||||
|
).pages.all()
|
||||||
|
|
||||||
|
@action(
|
||||||
|
detail=True, url_name='content', url_path='parsing'
|
||||||
|
)
|
||||||
|
def parsing_content(self, request, *args, **kwargs):
|
||||||
|
instance = self.get_object()
|
||||||
|
serializer = self.get_serializer(instance)
|
||||||
|
headers = self.get_success_headers(data=serializer.data)
|
||||||
|
return Response(
|
||||||
|
serializer.data, status=status.HTTP_200_OK, headers=headers
|
||||||
|
)
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ from mayan.apps.common.classes import ModelAttribute, ModelField
|
|||||||
from mayan.apps.documents.search import document_page_search, document_search
|
from mayan.apps.documents.search import document_page_search, document_search
|
||||||
from mayan.apps.documents.signals import post_version_upload
|
from mayan.apps.documents.signals import post_version_upload
|
||||||
from mayan.apps.navigation import SourceColumn
|
from mayan.apps.navigation import SourceColumn
|
||||||
|
from mayan.apps.rest_api.fields import HyperlinkField
|
||||||
|
from mayan.apps.rest_api.serializers import LazyExtraFieldsSerializerMixin
|
||||||
from mayan.celery import app
|
from mayan.celery import app
|
||||||
|
|
||||||
from .handlers import (
|
from .handlers import (
|
||||||
@@ -31,9 +33,9 @@ from .links import (
|
|||||||
link_error_list
|
link_error_list
|
||||||
)
|
)
|
||||||
from .methods import (
|
from .methods import (
|
||||||
method_document_submit_for_parsing,
|
method_document_get_content, method_document_page_get_content,
|
||||||
method_document_version_submit_for_parsing,
|
method_document_submit_for_parsing, method_document_version_get_content,
|
||||||
method_get_document_content, method_get_document_version_content
|
method_document_version_submit_for_parsing
|
||||||
)
|
)
|
||||||
from .permissions import (
|
from .permissions import (
|
||||||
permission_content_view, permission_document_type_parsing_setup,
|
permission_content_view, permission_document_type_parsing_setup,
|
||||||
@@ -79,16 +81,95 @@ class DocumentParsingApp(MayanAppConfig):
|
|||||||
value=method_document_submit_for_parsing
|
value=method_document_submit_for_parsing
|
||||||
)
|
)
|
||||||
Document.add_to_class(
|
Document.add_to_class(
|
||||||
name='get_content', value=method_get_document_content
|
name='get_content', value=method_document_get_content
|
||||||
|
)
|
||||||
|
DocumentPage.add_to_class(
|
||||||
|
name='get_content', value=method_document_page_get_content
|
||||||
)
|
)
|
||||||
DocumentVersion.add_to_class(
|
DocumentVersion.add_to_class(
|
||||||
name='get_content', value=method_get_document_version_content
|
name='get_content', value=method_document_version_get_content
|
||||||
)
|
)
|
||||||
DocumentVersion.add_to_class(
|
DocumentVersion.add_to_class(
|
||||||
name='submit_for_parsing',
|
name='submit_for_parsing',
|
||||||
value=method_document_version_submit_for_parsing
|
value=method_document_version_submit_for_parsing
|
||||||
)
|
)
|
||||||
|
|
||||||
|
LazyExtraFieldsSerializerMixin.add_field(
|
||||||
|
dotted_path='mayan.apps.documents.serializers.DocumentPageSerializer',
|
||||||
|
field_name='parsing_content_url',
|
||||||
|
field=HyperlinkField(
|
||||||
|
view_kwargs=(
|
||||||
|
{
|
||||||
|
'lookup_field': 'document_version__document_id',
|
||||||
|
'lookup_url_kwarg': 'document_id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'lookup_field': 'document_version_id',
|
||||||
|
'lookup_url_kwarg': 'document_version_id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'lookup_field': 'pk',
|
||||||
|
'lookup_url_kwarg': 'document_page_id',
|
||||||
|
}
|
||||||
|
),
|
||||||
|
view_name='rest_api:document_page-parsing-content'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
LazyExtraFieldsSerializerMixin.add_field(
|
||||||
|
dotted_path='mayan.apps.documents.serializers.DocumentSerializer',
|
||||||
|
field_name='parsing_content_url',
|
||||||
|
field=HyperlinkField(
|
||||||
|
lookup_url_kwarg='document_id',
|
||||||
|
view_name='rest_api:document-parsing-content'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
LazyExtraFieldsSerializerMixin.add_field(
|
||||||
|
dotted_path='mayan.apps.documents.serializers.DocumentSerializer',
|
||||||
|
field_name='parsing_submit_url',
|
||||||
|
field=HyperlinkField(
|
||||||
|
lookup_url_kwarg='document_id',
|
||||||
|
view_name='rest_api:document-parsing-submit'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
LazyExtraFieldsSerializerMixin.add_field(
|
||||||
|
dotted_path='mayan.apps.documents.serializers.DocumentVersionSerializer',
|
||||||
|
field_name='parsing_submit_url',
|
||||||
|
field=HyperlinkField(
|
||||||
|
view_kwargs=(
|
||||||
|
{
|
||||||
|
'lookup_field': 'document_id',
|
||||||
|
'lookup_url_kwarg': 'document_id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'lookup_field': 'pk',
|
||||||
|
'lookup_url_kwarg': 'document_version_id',
|
||||||
|
}
|
||||||
|
),
|
||||||
|
view_name='rest_api:document_version-parsing-submit'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
LazyExtraFieldsSerializerMixin.add_field(
|
||||||
|
dotted_path='mayan.apps.documents.serializers.DocumentVersionSerializer',
|
||||||
|
field_name='parsing_content_url',
|
||||||
|
field=HyperlinkField(
|
||||||
|
view_kwargs=(
|
||||||
|
{
|
||||||
|
'lookup_field': 'document_id',
|
||||||
|
'lookup_url_kwarg': 'document_id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'lookup_field': 'pk',
|
||||||
|
'lookup_url_kwarg': 'document_version_id',
|
||||||
|
}
|
||||||
|
),
|
||||||
|
view_name='rest_api:document_version-parsing-content'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
ModelAttribute(model=Document, name='get_content')
|
ModelAttribute(model=Document, name='get_content')
|
||||||
|
|
||||||
ModelField(
|
ModelField(
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from django.apps import apps
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
@@ -9,48 +10,62 @@ from mayan.apps.common.settings import settings_db_sync_task_delay
|
|||||||
|
|
||||||
from .events import event_parsing_document_version_submit
|
from .events import event_parsing_document_version_submit
|
||||||
from .tasks import task_parse_document_version
|
from .tasks import task_parse_document_version
|
||||||
from .utils import get_document_version_content_iterator
|
|
||||||
|
|
||||||
|
|
||||||
def method_document_submit_for_parsing(self):
|
def method_document_get_content(self):
|
||||||
latest_version = self.latest_version
|
|
||||||
# Don't error out if document has no version
|
|
||||||
if latest_version:
|
|
||||||
latest_version.submit_for_parsing()
|
|
||||||
|
|
||||||
|
|
||||||
def method_document_version_submit_for_parsing(self):
|
|
||||||
event_parsing_document_version_submit.commit(
|
|
||||||
action_object=self.document, target=self
|
|
||||||
)
|
|
||||||
|
|
||||||
task_parse_document_version.apply_async(
|
|
||||||
eta=now() + timedelta(seconds=settings_db_sync_task_delay.value),
|
|
||||||
kwargs={'document_version_pk': self.pk},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def method_get_document_content(self):
|
|
||||||
latest_version = self.latest_version
|
latest_version = self.latest_version
|
||||||
|
|
||||||
if latest_version:
|
if latest_version:
|
||||||
return latest_version.get_content()
|
return latest_version.get_content()
|
||||||
|
|
||||||
|
|
||||||
method_get_document_content.help_text = _(
|
method_document_get_content.help_text = _(
|
||||||
'Return the parsed content of the document.'
|
'Return the parsed content of the document.'
|
||||||
)
|
)
|
||||||
method_get_document_content.short_description = _(
|
method_document_get_content.short_description = _(
|
||||||
'get_content()'
|
'get_content()'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def method_get_document_version_content(self):
|
def method_document_page_get_content(self):
|
||||||
return ' '.join(
|
DocumentPageContent = apps.get_model(
|
||||||
get_document_version_content_iterator(document_version=self)
|
app_label='document_parsing', model_name='DocumentPageContent'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
page_content = self.content.content
|
||||||
|
except DocumentPageContent.DoesNotExist:
|
||||||
|
return ''
|
||||||
|
else:
|
||||||
|
return page_content
|
||||||
|
|
||||||
method_get_document_version_content.help_text = _(
|
|
||||||
|
def method_document_submit_for_parsing(self, _user=None):
|
||||||
|
latest_version = self.latest_version
|
||||||
|
# Don't error out if document has no version
|
||||||
|
if latest_version:
|
||||||
|
latest_version.submit_for_parsing(_user=_user)
|
||||||
|
|
||||||
|
|
||||||
|
def method_document_version_get_content(self):
|
||||||
|
result = []
|
||||||
|
for page in self.pages.all():
|
||||||
|
result.append(page.get_content())
|
||||||
|
|
||||||
|
return ''.join(result)
|
||||||
|
|
||||||
|
|
||||||
|
method_document_version_get_content.help_text = _(
|
||||||
'Return the parsed content of the document version.'
|
'Return the parsed content of the document version.'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def method_document_version_submit_for_parsing(self, _user=None):
|
||||||
|
event_parsing_document_version_submit.commit(
|
||||||
|
action_object=self.document, actor=_user, target=self
|
||||||
|
)
|
||||||
|
|
||||||
|
task_parse_document_version.apply_async(
|
||||||
|
eta=now() + timedelta(seconds=settings_db_sync_task_delay.value),
|
||||||
|
kwargs={'document_version_pk': self.pk},
|
||||||
|
)
|
||||||
|
|||||||
@@ -2,10 +2,20 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from .models import DocumentPageContent
|
|
||||||
|
class DocumentPageParsingSerializer(serializers.Serializer):
|
||||||
|
text = serializers.CharField(
|
||||||
|
read_only=True, source='get_content'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DocumentPageContentSerializer(serializers.ModelSerializer):
|
class DocumentParsingSerializer(serializers.Serializer):
|
||||||
class Meta:
|
text = serializers.CharField(
|
||||||
fields = ('content',)
|
read_only=True, source='get_content'
|
||||||
model = DocumentPageContent
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentVersionParsingSerializer(serializers.Serializer):
|
||||||
|
text = serializers.CharField(
|
||||||
|
read_only=True, source='get_content'
|
||||||
|
)
|
||||||
|
|||||||
@@ -7,35 +7,134 @@ from rest_framework import status
|
|||||||
from mayan.apps.documents.tests import TEST_HYBRID_DOCUMENT, DocumentTestMixin
|
from mayan.apps.documents.tests import TEST_HYBRID_DOCUMENT, DocumentTestMixin
|
||||||
from mayan.apps.rest_api.tests import BaseAPITestCase
|
from mayan.apps.rest_api.tests import BaseAPITestCase
|
||||||
|
|
||||||
from ..permissions import permission_content_view
|
from ..permissions import permission_content_view, permission_parse_document
|
||||||
|
|
||||||
TEST_DOCUMENT_CONTENT = 'Sample text'
|
from .literals import TEST_DOCUMENT_CONTENT
|
||||||
|
|
||||||
|
|
||||||
@override_settings(DOCUMENT_PARSING_AUTO_PARSING=True)
|
class DocumentParsingSubmitAPITestCase(DocumentTestMixin, BaseAPITestCase):
|
||||||
class DocumentParsingAPITestCase(DocumentTestMixin, BaseAPITestCase):
|
def _request_document_parsing_submit_view(self):
|
||||||
test_document_filename = TEST_HYBRID_DOCUMENT
|
return self.post(
|
||||||
|
viewname='rest_api:document-parsing-submit',
|
||||||
|
kwargs={'document_id': self.document.pk}
|
||||||
|
)
|
||||||
|
|
||||||
def _request_document_page_content_view(self):
|
def test_submit_document_no_permission(self):
|
||||||
return self.get(
|
response = self._request_document_parsing_submit_view()
|
||||||
viewname='rest_api:document-page-content-view',
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||||
kargs={
|
|
||||||
|
self.assertFalse(hasattr(self.document.pages.first(), 'content'))
|
||||||
|
|
||||||
|
#TODO: mock OCR here
|
||||||
|
def test_submit_document_with_access(self):
|
||||||
|
self.grant_access(
|
||||||
|
obj=self.document, permission=permission_parse_document
|
||||||
|
)
|
||||||
|
response = self._request_document_parsing_submit_view()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
|
||||||
|
|
||||||
|
self.assertTrue(hasattr(self.document.pages.first(), 'content'))
|
||||||
|
|
||||||
|
def _request_document_version_parsing_submit_view(self):
|
||||||
|
return self.post(
|
||||||
|
viewname='rest_api:document_version-parsing-submit',
|
||||||
|
kwargs={
|
||||||
'document_id': self.document.pk,
|
'document_id': self.document.pk,
|
||||||
'version_id': self.document.latest_version.pk,
|
'document_version_id': self.document.latest_version.pk
|
||||||
'page_id': self.document.latest_version.pages.first().pk
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_get_document_version_page_content_no_access(self):
|
def test_submit_document_version_no_permission(self):
|
||||||
response = self._request_document_page_content_view()
|
response = self._request_document_version_parsing_submit_view()
|
||||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
def test_get_document_version_page_content_with_access(self):
|
self.assertFalse(hasattr(self.document.pages.first(), 'content'))
|
||||||
|
|
||||||
|
def test_submit_document_version_with_access(self):
|
||||||
self.grant_access(
|
self.grant_access(
|
||||||
permission=permission_content_view, obj=self.document
|
obj=self.document, permission=permission_parse_document
|
||||||
|
)
|
||||||
|
response = self._request_document_version_parsing_submit_view()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
|
||||||
|
|
||||||
|
self.assertTrue(hasattr(self.document.pages.first(), 'content'))
|
||||||
|
|
||||||
|
|
||||||
|
@override_settings(DOCUMENT_PARSING_AUTO_PARSING=True)
|
||||||
|
class DocumentParsingContentAPITestCase(DocumentTestMixin, BaseAPITestCase):
|
||||||
|
test_document_filename = TEST_HYBRID_DOCUMENT
|
||||||
|
|
||||||
|
def _request_document_content_view(self):
|
||||||
|
return self.get(
|
||||||
|
viewname='rest_api:document-parsing-content',
|
||||||
|
kwargs={
|
||||||
|
'document_id': self.test_document.pk,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_get_document_content_no_permission(self):
|
||||||
|
response = self._request_document_content_view()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
def test_get_document_content_with_access(self):
|
||||||
|
self.grant_access(
|
||||||
|
obj=self.document, permission=permission_content_view
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self._request_document_content_view()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertTrue(
|
||||||
|
TEST_DOCUMENT_CONTENT in response.data['text']
|
||||||
|
)
|
||||||
|
|
||||||
|
def _request_document_page_content_view(self):
|
||||||
|
latest_version = self.test_document.latest_version
|
||||||
|
|
||||||
|
return self.get(
|
||||||
|
viewname='rest_api:document_page-parsing-content',
|
||||||
|
kwargs={
|
||||||
|
'document_id': self.test_document.pk,
|
||||||
|
'document_version_id': latest_version.pk,
|
||||||
|
'document_page_id': latest_version.pages.first().pk
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_get_document_page_content_no_access(self):
|
||||||
|
response = self._request_document_page_content_view()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
def test_get_document_page_content_with_access(self):
|
||||||
|
self.grant_access(
|
||||||
|
obj=self.document, permission=permission_content_view
|
||||||
)
|
)
|
||||||
response = self._request_document_page_content_view()
|
response = self._request_document_page_content_view()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
TEST_DOCUMENT_CONTENT in response.data['content']
|
TEST_DOCUMENT_CONTENT in response.data['text']
|
||||||
|
)
|
||||||
|
|
||||||
|
def _request_document_version_content_view(self):
|
||||||
|
latest_version = self.test_document.latest_version
|
||||||
|
|
||||||
|
return self.get(
|
||||||
|
viewname='rest_api:document_version-parsing-content',
|
||||||
|
kwargs={
|
||||||
|
'document_id': self.test_document.pk,
|
||||||
|
'document_version_id': latest_version.pk,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_get_document_version_content_no_permission(self):
|
||||||
|
response = self._request_document_version_content_view()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
def test_get_document_version_content_with_access(self):
|
||||||
|
self.grant_access(
|
||||||
|
obj=self.document, permission=permission_content_view
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self._request_document_version_content_view()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertTrue(
|
||||||
|
TEST_DOCUMENT_CONTENT in response.data['text']
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -25,20 +25,19 @@ class DocumentContentViewsTestCase(GenericDocumentViewTestCase):
|
|||||||
def _request_document_content_view(self):
|
def _request_document_content_view(self):
|
||||||
return self.get(
|
return self.get(
|
||||||
viewname='document_parsing:document_content',
|
viewname='document_parsing:document_content',
|
||||||
kwargs={'document_id': self.document.pk}
|
kwargs={'document_id': self.test_document.pk}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_document_content_view_no_permissions(self):
|
def test_document_content_view_no_permissions(self):
|
||||||
response = self._request_document_content_view()
|
response = self._request_document_content_view()
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
def test_document_content_view_with_access(self):
|
def test_document_content_view_with_access(self):
|
||||||
self.grant_access(
|
self.grant_access(
|
||||||
permission=permission_content_view, obj=self.document
|
obj=self.test_document, permission=permission_content_view
|
||||||
)
|
)
|
||||||
response = self._request_document_content_view()
|
|
||||||
|
|
||||||
|
response = self._request_document_content_view()
|
||||||
self.assertContains(
|
self.assertContains(
|
||||||
response=response, text=TEST_DOCUMENT_CONTENT, status_code=200
|
response=response, text=TEST_DOCUMENT_CONTENT, status_code=200
|
||||||
)
|
)
|
||||||
@@ -46,21 +45,20 @@ class DocumentContentViewsTestCase(GenericDocumentViewTestCase):
|
|||||||
def _request_document_page_content_view(self):
|
def _request_document_page_content_view(self):
|
||||||
return self.get(
|
return self.get(
|
||||||
viewname='document_parsing:document_page_content', kwargs={
|
viewname='document_parsing:document_page_content', kwargs={
|
||||||
'document_page_id': self.document.pages.first().pk
|
'document_page_id': self.test_document.pages.first().pk
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_document_page_content_view_no_permissions(self):
|
def test_document_page_content_view_no_permissions(self):
|
||||||
response = self._request_document_page_content_view()
|
response = self._request_document_page_content_view()
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
def test_document_page_content_view_with_access(self):
|
def test_document_page_content_view_with_access(self):
|
||||||
self.grant_access(
|
self.grant_access(
|
||||||
permission=permission_content_view, obj=self.document
|
permission=permission_content_view, obj=self.test_document
|
||||||
)
|
)
|
||||||
response = self._request_document_page_content_view()
|
|
||||||
|
|
||||||
|
response = self._request_document_page_content_view()
|
||||||
self.assertContains(
|
self.assertContains(
|
||||||
response=response, text=TEST_DOCUMENT_CONTENT, status_code=200
|
response=response, text=TEST_DOCUMENT_CONTENT, status_code=200
|
||||||
)
|
)
|
||||||
@@ -68,7 +66,7 @@ class DocumentContentViewsTestCase(GenericDocumentViewTestCase):
|
|||||||
def _request_document_content_download_view(self):
|
def _request_document_content_download_view(self):
|
||||||
return self.get(
|
return self.get(
|
||||||
viewname='document_parsing:document_content_download',
|
viewname='document_parsing:document_content_download',
|
||||||
kwargs={'document_id': self.document.pk}
|
kwargs={'document_id': self.test_document.pk}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_document_parsing_download_view_no_permission(self):
|
def test_document_parsing_download_view_no_permission(self):
|
||||||
@@ -78,16 +76,72 @@ class DocumentContentViewsTestCase(GenericDocumentViewTestCase):
|
|||||||
def test_download_view_with_access(self):
|
def test_download_view_with_access(self):
|
||||||
self.expected_content_type = 'application/octet-stream; charset=utf-8'
|
self.expected_content_type = 'application/octet-stream; charset=utf-8'
|
||||||
self.grant_access(
|
self.grant_access(
|
||||||
permission=permission_content_view, obj=self.document
|
permission=permission_content_view, obj=self.test_document
|
||||||
)
|
)
|
||||||
|
|
||||||
response = self._request_document_content_download_view()
|
response = self._request_document_content_download_view()
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
self.assert_download_response(
|
self.assert_download_response(
|
||||||
response=response, content=(
|
content=(
|
||||||
''.join(get_document_content_iterator(document=self.document))
|
''.join(get_document_content_iterator(document=self.test_document))
|
||||||
),
|
), response=response
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentSubmitViewsTestCase(GenericDocumentViewTestCase):
|
||||||
|
_skip_file_descriptor_test = True
|
||||||
|
|
||||||
|
# Ensure we use a PDF file
|
||||||
|
test_document_filename = TEST_HYBRID_DOCUMENT
|
||||||
|
|
||||||
|
def _request_document_submit_view(self):
|
||||||
|
return self.post(
|
||||||
|
viewname='document_parsing:document_submit',
|
||||||
|
kwargs={'document_id': self.test_document.pk}
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_document_submit_view_no_permission(self):
|
||||||
|
response = self._request_document_submit_view()
|
||||||
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
|
self.assertEqual(self.test_document.get_content(), '')
|
||||||
|
|
||||||
|
def test_document_submit_view_with_access(self):
|
||||||
|
self.grant_access(
|
||||||
|
obj=self.test_document, permission=permission_parse_document
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self._request_document_submit_view()
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
|
||||||
|
self.assertTrue(
|
||||||
|
TEST_DOCUMENT_CONTENT in self.test_document.get_content()
|
||||||
|
)
|
||||||
|
|
||||||
|
def _request_multiple_document_submit_view(self):
|
||||||
|
return self.post(
|
||||||
|
viewname='document_parsing:document_multiple_submit',
|
||||||
|
data={
|
||||||
|
'id_list': self.test_document.pk,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_multiple_document_submit_view_no_permission(self):
|
||||||
|
response = self._request_multiple_document_submit_view()
|
||||||
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
|
self.assertEqual(self.test_document.get_content(), '')
|
||||||
|
|
||||||
|
def test_multiple_document_submit_view_with_access(self):
|
||||||
|
self.grant_access(
|
||||||
|
obj=self.test_document, permission=permission_parse_document
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self._request_multiple_document_submit_view()
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
|
||||||
|
self.assertTrue(
|
||||||
|
TEST_DOCUMENT_CONTENT in self.test_document.get_content()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -98,17 +152,17 @@ class DocumentTypeViewsTestCase(GenericDocumentViewTestCase):
|
|||||||
def _request_document_type_parsing_settings_view(self):
|
def _request_document_type_parsing_settings_view(self):
|
||||||
return self.get(
|
return self.get(
|
||||||
viewname='document_parsing:document_type_parsing_settings',
|
viewname='document_parsing:document_type_parsing_settings',
|
||||||
kwargs={'document_type_id': self.document.document_type.pk}
|
kwargs={'document_type_id': self.test_document.document_type.pk}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_document_type_parsing_settings_view_no_permission(self):
|
def test_document_type_parsing_settings_view_no_permission(self):
|
||||||
response = self._request_document_type_parsing_settings_view()
|
response = self._request_document_type_parsing_settings_view()
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
def test_document_type_parsing_settings_view_with_access(self):
|
def test_document_type_parsing_settings_view_with_access(self):
|
||||||
self.grant_access(
|
self.grant_access(
|
||||||
permission=permission_document_type_parsing_setup,
|
obj=self.test_document.document_type,
|
||||||
obj=self.document.document_type
|
permission=permission_document_type_parsing_setup
|
||||||
)
|
)
|
||||||
response = self._request_document_type_parsing_settings_view()
|
response = self._request_document_type_parsing_settings_view()
|
||||||
|
|
||||||
@@ -117,7 +171,7 @@ class DocumentTypeViewsTestCase(GenericDocumentViewTestCase):
|
|||||||
def _request_document_type_submit_view(self):
|
def _request_document_type_submit_view(self):
|
||||||
return self.post(
|
return self.post(
|
||||||
viewname='document_parsing:document_type_submit', data={
|
viewname='document_parsing:document_type_submit', data={
|
||||||
'document_type': self.document_type.pk,
|
'document_type': self.test_document_type.pk,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -125,15 +179,15 @@ class DocumentTypeViewsTestCase(GenericDocumentViewTestCase):
|
|||||||
response = self._request_document_type_submit_view()
|
response = self._request_document_type_submit_view()
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
TEST_DOCUMENT_CONTENT not in self.document.get_content()
|
TEST_DOCUMENT_CONTENT not in self.test_document.get_content()
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_document_type_submit_view_with_access(self):
|
def test_document_type_submit_view_with_access(self):
|
||||||
self.grant_access(
|
self.grant_access(
|
||||||
obj=self.document_type, permission=permission_parse_document,
|
obj=self.test_document_type, permission=permission_parse_document
|
||||||
)
|
)
|
||||||
response = self._request_document_type_submit_view()
|
response = self._request_document_type_submit_view()
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 302)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
TEST_DOCUMENT_CONTENT in self.document.get_content()
|
TEST_DOCUMENT_CONTENT in self.test_document.get_content()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
|
||||||
from .api_views import APIDocumentPageContentView
|
from .api_views import (
|
||||||
|
DocumentParsingAPIViewSet, DocumentPageParsingAPIViewSet,
|
||||||
|
DocumentVersionParsingAPIViewSet
|
||||||
|
)
|
||||||
from .views import (
|
from .views import (
|
||||||
DocumentContentDownloadView, DocumentContentView, DocumentPageContentView,
|
DocumentContentDownloadView, DocumentContentView, DocumentPageContentView,
|
||||||
DocumentParsingErrorsListView, DocumentSubmitView,
|
DocumentParsingErrorsListView, DocumentSubmitView,
|
||||||
@@ -51,10 +54,20 @@ urlpatterns = [
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
api_urls = [
|
|
||||||
url(
|
api_router_entries = (
|
||||||
regex=r'^documents/(?P<document_id>\d+)/versions/(?P<document_version_id>\d+)/pages/(?P<document_page_id>\d+)/content/$',
|
{
|
||||||
view=APIDocumentPageContentView.as_view(),
|
'prefix': r'documents',
|
||||||
name='document-page-content-view'
|
'viewset': DocumentParsingAPIViewSet, 'basename': 'document-parsing'
|
||||||
)
|
},
|
||||||
]
|
{
|
||||||
|
'prefix': r'documents/(?P<document_id>\d+)/document_versions',
|
||||||
|
'viewset': DocumentVersionParsingAPIViewSet,
|
||||||
|
'basename': 'document_version-parsing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'prefix': r'documents/(?P<document_id>\d+)/document_versions/(?P<document_version_id>\d+)/document_pages',
|
||||||
|
'viewset': DocumentPageParsingAPIViewSet,
|
||||||
|
'basename': 'document_page-parsing'
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ from django.http import HttpResponseRedirect
|
|||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.translation import ungettext
|
|
||||||
|
|
||||||
from mayan.apps.common.generics import (
|
from mayan.apps.common.generics import (
|
||||||
FormView, MultipleObjectConfirmActionView, SingleObjectDetailView,
|
FormView, MultipleObjectConfirmActionView, SingleObjectDetailView,
|
||||||
SingleObjectDownloadView, SingleObjectEditView, SingleObjectListView
|
SingleObjectDownloadView, SingleObjectEditView, SingleObjectListView
|
||||||
)
|
)
|
||||||
|
from mayan.apps.common.mixins import ExternalObjectMixin
|
||||||
from mayan.apps.documents.forms import DocumentTypeFilteredSelectForm
|
from mayan.apps.documents.forms import DocumentTypeFilteredSelectForm
|
||||||
from mayan.apps.documents.models import Document, DocumentPage, DocumentType
|
from mayan.apps.documents.models import Document, DocumentPage, DocumentType
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ class DocumentContentView(SingleObjectDetailView):
|
|||||||
'document': self.get_object(),
|
'document': self.get_object(),
|
||||||
'hide_labels': True,
|
'hide_labels': True,
|
||||||
'object': self.get_object(),
|
'object': self.get_object(),
|
||||||
'title': _('Content for document: %s') % self.get_object(),
|
'title': _('Content for document: %s.') % self.get_object(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ class DocumentPageContentView(SingleObjectDetailView):
|
|||||||
return {
|
return {
|
||||||
'hide_labels': True,
|
'hide_labels': True,
|
||||||
'object': self.get_object(),
|
'object': self.get_object(),
|
||||||
'title': _('Content for document page: %s') % self.get_object(),
|
'title': _('Content for document page: %s.') % self.get_object(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ class DocumentParsingErrorsListView(SingleObjectListView):
|
|||||||
'hide_object': True,
|
'hide_object': True,
|
||||||
'object': self.get_document(),
|
'object': self.get_document(),
|
||||||
'title': _(
|
'title': _(
|
||||||
'Parsing errors for document: %s'
|
'Parsing errors for document: %s.'
|
||||||
) % self.get_document(),
|
) % self.get_document(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,57 +105,39 @@ class DocumentParsingErrorsListView(SingleObjectListView):
|
|||||||
class DocumentSubmitView(MultipleObjectConfirmActionView):
|
class DocumentSubmitView(MultipleObjectConfirmActionView):
|
||||||
model = Document
|
model = Document
|
||||||
object_permission = permission_parse_document
|
object_permission = permission_parse_document
|
||||||
|
pk_url_kwarg = 'document_id'
|
||||||
|
success_message_single = _(
|
||||||
|
'Document "%(object)s" added to the parsing queue.'
|
||||||
|
)
|
||||||
success_message_singular = _(
|
success_message_singular = _(
|
||||||
'%(count)d document added to the parsing queue'
|
'%(count)d document added to the parsing queue.'
|
||||||
)
|
)
|
||||||
success_message_plural = _(
|
success_message_plural = _(
|
||||||
'%(count)d documents added to the parsing queue'
|
'%(count)d documents added to the parsing queue.'
|
||||||
)
|
)
|
||||||
|
title_single = _('Submit the document "%(object)s" to the parsing queue.')
|
||||||
def get_extra_context(self):
|
title_singular = _('Submit %(count)d document to the parsing queue.')
|
||||||
queryset = self.get_queryset()
|
title_plural = _('Submit %(count)d documents to the parsing queue.')
|
||||||
|
|
||||||
result = {
|
|
||||||
'title': ungettext(
|
|
||||||
singular='Submit %(count)d document to the parsing queue?',
|
|
||||||
plural='Submit %(count)d documents to the parsing queue',
|
|
||||||
number=queryset.count()
|
|
||||||
) % {
|
|
||||||
'count': queryset.count(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if queryset.count() == 1:
|
|
||||||
result.update(
|
|
||||||
{
|
|
||||||
'object': queryset.first(),
|
|
||||||
'title': _(
|
|
||||||
'Submit document "%s" to the parsing queue'
|
|
||||||
) % queryset.first()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def object_action(self, instance, form=None):
|
def object_action(self, instance, form=None):
|
||||||
instance.submit_for_parsing()
|
instance.submit_for_parsing()
|
||||||
|
|
||||||
|
|
||||||
class DocumentTypeSettingsEditView(SingleObjectEditView):
|
class DocumentTypeSettingsEditView(ExternalObjectMixin, SingleObjectEditView):
|
||||||
|
external_object_class = DocumentType
|
||||||
|
external_object_permission = permission_document_type_parsing_setup
|
||||||
|
external_object_pk_url_kwarg = 'document_type_id'
|
||||||
fields = ('auto_parsing',)
|
fields = ('auto_parsing',)
|
||||||
object_permission = permission_document_type_parsing_setup
|
|
||||||
post_action_redirect = reverse_lazy(viewname='documents:document_type_list')
|
post_action_redirect = reverse_lazy(viewname='documents:document_type_list')
|
||||||
|
|
||||||
def get_document_type(self):
|
def get_document_type(self):
|
||||||
return get_object_or_404(
|
return self.external_object
|
||||||
klass=DocumentType, pk=self.kwargs['document_type_id']
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_extra_context(self):
|
def get_extra_context(self):
|
||||||
return {
|
return {
|
||||||
'object': self.get_document_type(),
|
'object': self.get_document_type(),
|
||||||
'title': _(
|
'title': _(
|
||||||
'Edit parsing settings for document type: %s'
|
'Edit parsing settings for document type: %s.'
|
||||||
) % self.get_document_type()
|
) % self.get_document_type()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +147,7 @@ class DocumentTypeSettingsEditView(SingleObjectEditView):
|
|||||||
|
|
||||||
class DocumentTypeSubmitView(FormView):
|
class DocumentTypeSubmitView(FormView):
|
||||||
extra_context = {
|
extra_context = {
|
||||||
'title': _('Submit all documents of a type for parsing')
|
'title': _('Submit all documents of a type for parsing.')
|
||||||
}
|
}
|
||||||
form_class = DocumentTypeFilteredSelectForm
|
form_class = DocumentTypeFilteredSelectForm
|
||||||
post_action_redirect = reverse_lazy(viewname='common:tools_list')
|
post_action_redirect = reverse_lazy(viewname='common:tools_list')
|
||||||
@@ -198,7 +180,7 @@ class DocumentTypeSubmitView(FormView):
|
|||||||
class ParseErrorListView(SingleObjectListView):
|
class ParseErrorListView(SingleObjectListView):
|
||||||
extra_context = {
|
extra_context = {
|
||||||
'hide_object': True,
|
'hide_object': True,
|
||||||
'title': _('Parsing errors'),
|
'title': _('Parsing errors.'),
|
||||||
}
|
}
|
||||||
view_permission = permission_document_type_parsing_setup
|
view_permission = permission_document_type_parsing_setup
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user