Merge branch '2_1_10-hotfix' into feature/hotfix

This commit is contained in:
Roberto Rosario
2017-02-20 02:44:00 -04:00
30 changed files with 1266 additions and 105 deletions
+2 -2
View File
@@ -1,8 +1,8 @@
from __future__ import unicode_literals
__title__ = 'Mayan EDMS'
__version__ = '2.1.7'
__build__ = 0x020107
__version__ = '2.1.10'
__build__ = 0x020110
__author__ = 'Roberto Rosario'
__author_email__ = 'roberto.rosario@mayan-edms.com'
__description__ = 'Free Open Source Electronic Document Management System'
+27 -4
View File
@@ -31,7 +31,9 @@ from .serializers import (
DocumentPageSerializer, DocumentSerializer,
DocumentTypeSerializer, DocumentVersionSerializer,
DocumentVersionRevertSerializer, NewDocumentSerializer,
NewDocumentVersionSerializer, RecentDocumentSerializer
NewDocumentVersionSerializer, RecentDocumentSerializer,
WritableDocumentSerializer, WritableDocumentTypeSerializer,
WritableDocumentVersionSerializer
)
logger = logging.getLogger(__name__)
@@ -190,7 +192,6 @@ class APIDocumentView(generics.RetrieveUpdateDestroyAPIView):
}
permission_classes = (MayanPermission,)
queryset = Document.objects.all()
serializer_class = DocumentSerializer
def delete(self, *args, **kwargs):
"""
@@ -206,6 +207,12 @@ class APIDocumentView(generics.RetrieveUpdateDestroyAPIView):
return super(APIDocumentView, self).get(*args, **kwargs)
def get_serializer_class(self):
if self.request.method == 'GET':
return DocumentSerializer
else:
return WritableDocumentSerializer
def patch(self, *args, **kwargs):
"""
Edit the properties of the selected document.
@@ -289,6 +296,12 @@ class APIDocumentTypeListView(generics.ListCreateAPIView):
return super(APIDocumentTypeListView, self).get(*args, **kwargs)
def get_serializer_class(self):
if self.request.method == 'GET':
return DocumentTypeSerializer
else:
return WritableDocumentTypeSerializer
def post(self, *args, **kwargs):
"""
Create a new document type.
@@ -310,7 +323,6 @@ class APIDocumentTypeView(generics.RetrieveUpdateDestroyAPIView):
}
permission_classes = (MayanPermission,)
queryset = DocumentType.objects.all()
serializer_class = DocumentTypeSerializer
def delete(self, *args, **kwargs):
"""
@@ -326,6 +338,12 @@ class APIDocumentTypeView(generics.RetrieveUpdateDestroyAPIView):
return super(APIDocumentTypeView, self).get(*args, **kwargs)
def get_serializer_class(self):
if self.request.method == 'GET':
return DocumentTypeSerializer
else:
return WritableDocumentTypeSerializer
def patch(self, *args, **kwargs):
"""
Edit the properties of the selected document type.
@@ -436,7 +454,12 @@ class APIDocumentVersionView(generics.RetrieveUpdateAPIView):
mayan_permission_attribute_check = 'document'
permission_classes = (MayanPermission,)
queryset = DocumentVersion.objects.all()
serializer_class = DocumentVersionSerializer
def get_serializer_class(self):
if self.request.method == 'GET':
return DocumentVersionSerializer
else:
return WritableDocumentVersionSerializer
def patch(self, *args, **kwargs):
"""
+76 -4
View File
@@ -6,7 +6,8 @@ from common.models import SharedUploadedFile
from .literals import DOCUMENT_IMAGE_TASK_TIMEOUT
from .models import (
Document, DocumentVersion, DocumentPage, DocumentType, RecentDocument
Document, DocumentVersion, DocumentPage, DocumentType,
DocumentTypeFilename, RecentDocument
)
from .settings import setting_language
from .tasks import task_get_document_page_image, task_upload_new_version
@@ -45,15 +46,40 @@ class DocumentPageSerializer(serializers.HyperlinkedModelSerializer):
model = DocumentPage
class DocumentTypeFilenameSerializer(serializers.ModelSerializer):
class Meta:
model = DocumentTypeFilename
fields = ('filename',)
class DocumentTypeSerializer(serializers.HyperlinkedModelSerializer):
documents_url = serializers.HyperlinkedIdentityField(
view_name='rest_api:documenttype-document-list',
)
documents_count = serializers.SerializerMethodField()
filenames = DocumentTypeFilenameSerializer(many=True, read_only=True)
class Meta:
extra_kwargs = {
'url': {'view_name': 'rest_api:documenttype-detail'},
}
fields = (
'delete_time_period', 'delete_time_unit', 'documents_url',
'documents_count', 'id', 'label', 'filenames', 'trash_time_period',
'trash_time_unit', 'url'
)
model = DocumentType
def get_documents_count(self, obj):
return obj.documents.count()
class WritableDocumentTypeSerializer(serializers.ModelSerializer):
documents_url = serializers.HyperlinkedIdentityField(
view_name='rest_api:documenttype-document-list',
)
documents_count = serializers.SerializerMethodField()
class Meta:
extra_kwargs = {
'url': {'view_name': 'rest_api:documenttype-detail'},
@@ -65,6 +91,9 @@ class DocumentTypeSerializer(serializers.HyperlinkedModelSerializer):
)
model = DocumentType
def get_documents_count(self, obj):
return obj.documents.count()
class DocumentVersionSerializer(serializers.HyperlinkedModelSerializer):
pages = DocumentPageSerializer(many=True, required=False, read_only=True)
@@ -82,6 +111,26 @@ class DocumentVersionSerializer(serializers.HyperlinkedModelSerializer):
read_only_fields = ('document', 'file')
class WritableDocumentVersionSerializer(serializers.ModelSerializer):
document = serializers.HyperlinkedIdentityField(
view_name='rest_api:document-detail'
)
pages = DocumentPageSerializer(many=True, required=False, read_only=True)
revert = serializers.HyperlinkedIdentityField(
view_name='rest_api:documentversion-revert'
)
url = serializers.HyperlinkedIdentityField(
view_name='rest_api:documentversion-detail'
)
class Meta:
extra_kwargs = {
'file': {'use_url': False},
}
model = DocumentVersion
read_only_fields = ('document', 'file')
class DocumentVersionRevertSerializer(DocumentVersionSerializer):
class Meta(DocumentVersionSerializer.Meta):
read_only_fields = ('comment', 'document',)
@@ -136,9 +185,6 @@ class DocumentSerializer(serializers.HyperlinkedModelSerializer):
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'},
@@ -152,6 +198,32 @@ class DocumentSerializer(serializers.HyperlinkedModelSerializer):
model = Document
read_only_fields = ('document_type',)
def get_document_type_label(self, instance):
return instance.document_type.label
class WritableDocumentSerializer(serializers.ModelSerializer):
document_type_label = serializers.SerializerMethodField()
latest_version = DocumentVersionSerializer(many=False, read_only=True)
versions = serializers.HyperlinkedIdentityField(
view_name='rest_api:document-version-list',
)
url = serializers.HyperlinkedIdentityField(
view_name='rest_api:document-detail',
)
class Meta:
fields = (
'date_added', 'description', 'document_type',
'document_type_label', 'id', 'label', 'language',
'latest_version', 'url', 'uuid', 'versions',
)
model = Document
read_only_fields = ('document_type',)
def get_document_type_label(self, instance):
return instance.document_type.label
class NewDocumentSerializer(serializers.ModelSerializer):
file = serializers.FileField(write_only=True)
+2 -1
View File
@@ -49,12 +49,13 @@ class DocumentTypeAPITestCase(APITestCase):
def test_document_type_create(self):
self.assertEqual(DocumentType.objects.all().count(), 0)
self.client.post(
response = self.client.post(
reverse('rest_api:documenttype-list'), data={
'label': TEST_DOCUMENT_TYPE
}
)
self.assertEqual(response.status_code, 201)
self.assertEqual(DocumentType.objects.all().count(), 1)
self.assertEqual(
DocumentType.objects.all().first().label, TEST_DOCUMENT_TYPE
+360
View File
@@ -0,0 +1,360 @@
from __future__ import absolute_import, unicode_literals
from django.core.exceptions import PermissionDenied
from django.shortcuts import get_object_or_404
from rest_framework import generics
from acls.models import AccessControlList
from documents.models import Document
from documents.permissions import permission_document_view
from permissions import Permission
from rest_api.filters import MayanObjectPermissionsFilter
from rest_api.permissions import MayanPermission
from .models import SmartLink
from .permissions import (
permission_smart_link_create, permission_smart_link_delete,
permission_smart_link_edit, permission_smart_link_view
)
from .serializers import (
ResolvedSmartLinkDocumentSerializer, ResolvedSmartLinkSerializer,
SmartLinkConditionSerializer, SmartLinkSerializer,
WritableSmartLinkSerializer
)
class APIResolvedSmartLinkDocumentListView(generics.ListAPIView):
filter_backends = (MayanObjectPermissionsFilter,)
mayan_object_permissions = {'GET': (permission_document_view,)}
permission_classes = (MayanPermission,)
serializer_class = ResolvedSmartLinkDocumentSerializer
def get(self, *args, **kwargs):
"""
Returns a list of the smart link documents that apply to the document.
"""
return super(APIResolvedSmartLinkDocumentListView, self).get(
*args, **kwargs
)
def get_document(self):
document = get_object_or_404(Document, pk=self.kwargs['pk'])
try:
Permission.check_permissions(
self.request.user, (permission_document_view,)
)
except PermissionDenied:
AccessControlList.objects.check_access(
permission_document_view, self.request.user, document
)
return document
def get_smart_link(self):
smart_link = get_object_or_404(
SmartLink.objects.get_for(document=self.get_document()),
pk=self.kwargs['smart_link_pk']
)
try:
Permission.check_permissions(
self.request.user, (permission_smart_link_view,)
)
except PermissionDenied:
AccessControlList.objects.check_access(
permission_smart_link_view, self.request.user, smart_link
)
return smart_link
def get_serializer_context(self):
"""
Extra context provided to the serializer class.
"""
return {
'document': self.get_document(),
'format': self.format_kwarg,
'request': self.request,
'smart_link': self.get_smart_link(),
'view': self
}
def get_queryset(self):
return self.get_smart_link().get_linked_document_for(
document=self.get_document()
)
class APIResolvedSmartLinkView(generics.RetrieveAPIView):
filter_backends = (MayanObjectPermissionsFilter,)
lookup_url_kwarg = 'smart_link_pk'
mayan_object_permissions = {'GET': (permission_smart_link_view,)}
permission_classes = (MayanPermission,)
serializer_class = ResolvedSmartLinkSerializer
def get(self, *args, **kwargs):
"""
Return the details of the selected resolved smart link.
"""
return super(APIResolvedSmartLinkView, self).get(*args, **kwargs)
def get_document(self):
document = get_object_or_404(Document, pk=self.kwargs['pk'])
try:
Permission.check_permissions(
self.request.user, (permission_document_view,)
)
except PermissionDenied:
AccessControlList.objects.check_access(
permission_document_view, self.request.user, document
)
return document
def get_serializer_context(self):
"""
Extra context provided to the serializer class.
"""
return {
'document': self.get_document(),
'format': self.format_kwarg,
'request': self.request,
'view': self
}
def get_queryset(self):
return SmartLink.objects.get_for(document=self.get_document())
class APIResolvedSmartLinkListView(generics.ListAPIView):
filter_backends = (MayanObjectPermissionsFilter,)
mayan_object_permissions = {'GET': (permission_smart_link_view,)}
permission_classes = (MayanPermission,)
serializer_class = ResolvedSmartLinkSerializer
def get(self, *args, **kwargs):
"""
Returns a list of the smart links that apply to the document.
"""
return super(APIResolvedSmartLinkListView, self).get(*args, **kwargs)
def get_document(self):
document = get_object_or_404(Document, pk=self.kwargs['pk'])
try:
Permission.check_permissions(
self.request.user, (permission_document_view,)
)
except PermissionDenied:
AccessControlList.objects.check_access(
permission_document_view, self.request.user, document
)
return document
def get_serializer_context(self):
"""
Extra context provided to the serializer class.
"""
return {
'document': self.get_document(),
'format': self.format_kwarg,
'request': self.request,
'view': self
}
def get_queryset(self):
return SmartLink.objects.filter(
document_types=self.get_document().document_type
)
class APISmartLinkConditionListView(generics.ListCreateAPIView):
serializer_class = SmartLinkConditionSerializer
def get(self, *args, **kwargs):
"""
Returns a list of all the smart link conditions.
"""
return super(APISmartLinkConditionListView, self).get(*args, **kwargs)
def get_queryset(self):
return self.get_smart_link().conditions.all()
def get_serializer_context(self):
"""
Extra context provided to the serializer class.
"""
return {
'format': self.format_kwarg,
'request': self.request,
'smart_link': self.get_smart_link(),
'view': self
}
def get_smart_link(self):
if self.request.method == 'GET':
permission_required = permission_smart_link_view
else:
permission_required = permission_smart_link_edit
smart_link = get_object_or_404(SmartLink, pk=self.kwargs['pk'])
try:
Permission.check_permissions(
self.request.user, (permission_required,)
)
except PermissionDenied:
AccessControlList.objects.check_access(
permission_required, self.request.user, smart_link
)
return smart_link
def post(self, *args, **kwargs):
"""
Create a new smart link condition.
"""
return super(APISmartLinkConditionListView, self).post(*args, **kwargs)
class APISmartLinkConditionView(generics.RetrieveUpdateDestroyAPIView):
lookup_url_kwarg = 'condition_pk'
serializer_class = SmartLinkConditionSerializer
def delete(self, *args, **kwargs):
"""
Delete the selected smart link condition.
"""
return super(APISmartLinkConditionView, self).delete(*args, **kwargs)
def get(self, *args, **kwargs):
"""
Return the details of the selected smart link condition.
"""
return super(APISmartLinkConditionView, self).get(*args, **kwargs)
def get_queryset(self):
return self.get_smart_link().conditions.all()
def get_serializer_context(self):
"""
Extra context provided to the serializer class.
"""
return {
'format': self.format_kwarg,
'request': self.request,
'smart_link': self.get_smart_link(),
'view': self
}
def get_smart_link(self):
if self.request.method == 'GET':
permission_required = permission_smart_link_view
else:
permission_required = permission_smart_link_edit
smart_link = get_object_or_404(SmartLink, pk=self.kwargs['pk'])
try:
Permission.check_permissions(
self.request.user, (permission_required,)
)
except PermissionDenied:
AccessControlList.objects.check_access(
permission_required, self.request.user, smart_link
)
return smart_link
def patch(self, *args, **kwargs):
"""
Edit the selected smart link condition.
"""
return super(APISmartLinkConditionView, self).patch(*args, **kwargs)
def put(self, *args, **kwargs):
"""
Edit the selected smart link condition.
"""
return super(APISmartLinkConditionView, self).put(*args, **kwargs)
class APISmartLinkListView(generics.ListCreateAPIView):
filter_backends = (MayanObjectPermissionsFilter,)
mayan_object_permissions = {'GET': (permission_smart_link_view,)}
mayan_view_permissions = {'POST': (permission_smart_link_create,)}
permission_classes = (MayanPermission,)
queryset = SmartLink.objects.all()
def get(self, *args, **kwargs):
"""
Returns a list of all the smart links.
"""
return super(APISmartLinkListView, self).get(*args, **kwargs)
def get_serializer_class(self):
if self.request.method == 'GET':
return SmartLinkSerializer
else:
return WritableSmartLinkSerializer
def post(self, *args, **kwargs):
"""
Create a new smart link.
"""
return super(APISmartLinkListView, self).post(*args, **kwargs)
class APISmartLinkView(generics.RetrieveUpdateDestroyAPIView):
filter_backends = (MayanObjectPermissionsFilter,)
mayan_object_permissions = {
'DELETE': (permission_smart_link_delete,),
'GET': (permission_smart_link_view,),
'PATCH': (permission_smart_link_edit,),
'PUT': (permission_smart_link_edit,)
}
queryset = SmartLink.objects.all()
def delete(self, *args, **kwargs):
"""
Delete the selected smart link.
"""
return super(APISmartLinkView, self).delete(*args, **kwargs)
def get(self, *args, **kwargs):
"""
Return the details of the selected smart ink.
"""
return super(APISmartLinkView, self).get(*args, **kwargs)
def get_serializer_class(self):
if self.request.method == 'GET':
return SmartLinkSerializer
else:
return WritableSmartLinkSerializer
def patch(self, *args, **kwargs):
"""
Edit the selected smart link.
"""
return super(APISmartLinkView, self).patch(*args, **kwargs)
def put(self, *args, **kwargs):
"""
Edit the selected smart link.
"""
return super(APISmartLinkView, self).put(*args, **kwargs)
+3
View File
@@ -12,6 +12,7 @@ from common import (
)
from common.widgets import two_state_template
from navigation import SourceColumn
from rest_api.classes import APIEndPoint
from .links import (
link_smart_link_create, link_smart_link_condition_create,
@@ -35,6 +36,8 @@ class LinkingApp(MayanAppConfig):
def ready(self):
super(LinkingApp, self).ready()
APIEndPoint(app=self, version_string='1')
Document = apps.get_model(
app_label='documents', model_name='Document'
)
+8
View File
@@ -0,0 +1,8 @@
from django.db import models
class SmartLinkManager(models.Manager):
def get_for(self, document):
return self.filter(
document_types=document.document_type, enabled=True
)
+3
View File
@@ -11,6 +11,7 @@ from documents.models import Document, DocumentType
from .literals import (
INCLUSION_AND, INCLUSION_CHOICES, INCLUSION_OR, OPERATOR_CHOICES
)
from .managers import SmartLinkManager
@python_2_unicode_compatible
@@ -29,6 +30,8 @@ class SmartLink(models.Model):
DocumentType, verbose_name=_('Document types')
)
objects = SmartLinkManager()
def __str__(self):
return self.label
+115
View File
@@ -0,0 +1,115 @@
from __future__ import absolute_import, unicode_literals
from rest_framework import serializers
from rest_framework.reverse import reverse
from documents.serializers import DocumentSerializer
from .models import SmartLink, SmartLinkCondition
class SmartLinkConditionSerializer(serializers.HyperlinkedModelSerializer):
smart_link_url = serializers.SerializerMethodField()
url = serializers.SerializerMethodField()
class Meta:
fields = (
'enabled', 'expression', 'foreign_document_data', 'inclusion',
'id', 'negated', 'operator', 'smart_link_url', 'url'
)
model = SmartLinkCondition
def create(self, validated_data):
validated_data['smart_link'] = self.context['smart_link']
return super(SmartLinkConditionSerializer, self).create(validated_data)
def get_smart_link_url(self, instance):
return reverse(
'rest_api:smartlink-detail', args=(instance.smart_link.pk,),
request=self.context['request'], format=self.context['format']
)
def get_url(self, instance):
return reverse(
'rest_api:smartlinkcondition-detail', args=(
instance.smart_link.pk, instance.pk,
), request=self.context['request'], format=self.context['format']
)
class SmartLinkSerializer(serializers.HyperlinkedModelSerializer):
conditions_url = serializers.HyperlinkedIdentityField(
view_name='rest_api:smartlinkcondition-list'
)
class Meta:
extra_kwargs = {
'url': {'view_name': 'rest_api:smartlink-detail'},
}
fields = (
'conditions_url', 'dynamic_label', 'enabled', 'label', 'id', 'url'
)
model = SmartLink
class ResolvedSmartLinkDocumentSerializer(DocumentSerializer):
resolved_smart_link_url = serializers.SerializerMethodField()
class Meta(DocumentSerializer.Meta):
fields = DocumentSerializer.Meta.fields + (
'resolved_smart_link_url',
)
read_only_fields = DocumentSerializer.Meta.fields
def get_resolved_smart_link_url(self, instance):
return reverse(
'rest_api:resolvedsmartlink-detail', args=(
self.context['document'].pk, self.context['smart_link'].pk
), request=self.context['request'],
format=self.context['format']
)
class ResolvedSmartLinkSerializer(SmartLinkSerializer):
resolved_dynamic_label = serializers.SerializerMethodField()
resolved_smart_link_url = serializers.SerializerMethodField()
resolved_documents_url = serializers.SerializerMethodField()
class Meta(SmartLinkSerializer.Meta):
fields = SmartLinkSerializer.Meta.fields + (
'resolved_dynamic_label', 'resolved_smart_link_url',
'resolved_documents_url'
)
read_only_fields = SmartLinkSerializer.Meta.fields
def get_resolved_documents_url(self, instance):
return reverse(
'rest_api:resolvedsmartlinkdocument-list',
args=(self.context['document'].pk, instance.pk,),
request=self.context['request'], format=self.context['format']
)
def get_resolved_dynamic_label(self, instance):
return instance.get_dynamic_label(document=self.context['document'])
def get_resolved_smart_link_url(self, instance):
return reverse(
'rest_api:resolvedsmartlink-detail',
args=(self.context['document'].pk, instance.pk,),
request=self.context['request'], format=self.context['format']
)
class WritableSmartLinkSerializer(serializers.ModelSerializer):
conditions_url = serializers.HyperlinkedIdentityField(
view_name='rest_api:smartlinkcondition-list'
)
class Meta:
extra_kwargs = {
'url': {'view_name': 'rest_api:smartlink-detail'},
}
fields = (
'conditions_url', 'dynamic_label', 'enabled', 'label', 'id', 'url'
)
model = SmartLink
+5 -1
View File
@@ -1,5 +1,9 @@
from __future__ import unicode_literals
TEST_SMART_LINK_CONDITION_FOREIGN_DOCUMENT_DATA = 'label'
TEST_SMART_LINK_CONDITION_EXPRESSION = 'sample'
TEST_SMART_LINK_CONDITION_EXPRESSION_EDITED = '\'test edited\''
TEST_SMART_LINK_CONDITION_OPERATOR = 'icontains'
TEST_SMART_LINK_DYNAMIC_LABEL = '{{ document.label }}'
TEST_SMART_LINK_EDITED_LABEL = 'test edited label'
TEST_SMART_LINK_LABEL_EDITED = 'test edited label'
TEST_SMART_LINK_LABEL = 'test label'
+315
View File
@@ -0,0 +1,315 @@
from __future__ import unicode_literals
from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse
from django.test import override_settings
from rest_framework.test import APITestCase
from documents.models import DocumentType
from documents.tests.literals import (
TEST_DOCUMENT_TYPE, TEST_SMALL_DOCUMENT_PATH
)
from user_management.tests.literals import (
TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME
)
from ..models import SmartLink, SmartLinkCondition
from .literals import (
TEST_SMART_LINK_CONDITION_FOREIGN_DOCUMENT_DATA,
TEST_SMART_LINK_CONDITION_EXPRESSION,
TEST_SMART_LINK_CONDITION_EXPRESSION_EDITED,
TEST_SMART_LINK_CONDITION_OPERATOR, TEST_SMART_LINK_DYNAMIC_LABEL,
TEST_SMART_LINK_LABEL_EDITED, TEST_SMART_LINK_LABEL
)
@override_settings(OCR_AUTO_OCR=False)
class SmartLinkAPITestCase(APITestCase):
def setUp(self):
self.admin_user = get_user_model().objects.create_superuser(
username=TEST_ADMIN_USERNAME, email=TEST_ADMIN_EMAIL,
password=TEST_ADMIN_PASSWORD
)
self.client.login(
username=TEST_ADMIN_USERNAME, password=TEST_ADMIN_PASSWORD
)
def tearDown(self):
if hasattr(self, 'document_type'):
self.document_type.delete()
def _create_document_type(self):
self.document_type = DocumentType.objects.create(
label=TEST_DOCUMENT_TYPE
)
def _create_document(self):
with open(TEST_SMALL_DOCUMENT_PATH) as file_object:
self.document = self.document_type.new_document(
file_object=file_object
)
def _create_smart_link(self):
return SmartLink.objects.create(
label=TEST_SMART_LINK_LABEL,
dynamic_label=TEST_SMART_LINK_DYNAMIC_LABEL
)
def test_smart_link_create_view(self):
response = self.client.post(
reverse('rest_api:smartlink-list'), {
'label': TEST_SMART_LINK_LABEL
}
)
smart_link = SmartLink.objects.first()
self.assertEqual(response.data['id'], smart_link.pk)
self.assertEqual(response.data['label'], TEST_SMART_LINK_LABEL)
self.assertEqual(SmartLink.objects.count(), 1)
self.assertEqual(smart_link.label, TEST_SMART_LINK_LABEL)
def test_smart_link_delete_view(self):
smart_link = self._create_smart_link()
self.client.delete(
reverse('rest_api:smartlink-detail', args=(smart_link.pk,))
)
self.assertEqual(SmartLink.objects.count(), 0)
def test_smart_link_detail_view(self):
smart_link = self._create_smart_link()
response = self.client.get(
reverse('rest_api:smartlink-detail', args=(smart_link.pk,))
)
self.assertEqual(
response.data['label'], TEST_SMART_LINK_LABEL
)
def test_smart_link_patch_view(self):
smart_link = self._create_smart_link()
self.client.patch(
reverse('rest_api:smartlink-detail', args=(smart_link.pk,)),
data={
'label': TEST_SMART_LINK_LABEL_EDITED,
}
)
smart_link.refresh_from_db()
self.assertEqual(smart_link.label, TEST_SMART_LINK_LABEL_EDITED)
def test_smart_link_put_view(self):
smart_link = self._create_smart_link()
self.client.put(
reverse('rest_api:smartlink-detail', args=(smart_link.pk,)),
data={
'label': TEST_SMART_LINK_LABEL_EDITED,
}
)
smart_link.refresh_from_db()
self.assertEqual(smart_link.label, TEST_SMART_LINK_LABEL_EDITED)
@override_settings(OCR_AUTO_OCR=False)
class SmartLinkConditionAPITestCase(APITestCase):
def setUp(self):
self.admin_user = get_user_model().objects.create_superuser(
username=TEST_ADMIN_USERNAME, email=TEST_ADMIN_EMAIL,
password=TEST_ADMIN_PASSWORD
)
self.client.login(
username=TEST_ADMIN_USERNAME, password=TEST_ADMIN_PASSWORD
)
def tearDown(self):
if hasattr(self, 'document_type'):
self.document_type.delete()
def _create_document_type(self):
self.document_type = DocumentType.objects.create(
label=TEST_DOCUMENT_TYPE
)
def _create_document(self):
with open(TEST_SMALL_DOCUMENT_PATH) as file_object:
self.document = self.document_type.new_document(
file_object=file_object
)
def _create_smart_link(self):
self.smart_link = SmartLink.objects.create(
label=TEST_SMART_LINK_LABEL,
dynamic_label=TEST_SMART_LINK_DYNAMIC_LABEL
)
self.smart_link.document_types.add(self.document_type)
def _create_smart_link_condition(self):
self.smart_link_condition = SmartLinkCondition.objects.create(
smart_link=self.smart_link,
foreign_document_data=TEST_SMART_LINK_CONDITION_FOREIGN_DOCUMENT_DATA,
expression=TEST_SMART_LINK_CONDITION_EXPRESSION,
operator=TEST_SMART_LINK_CONDITION_OPERATOR
)
def test_resolved_smart_link_detail_view(self):
self._create_document_type()
self._create_smart_link()
self._create_smart_link_condition()
self._create_document()
response = self.client.get(
reverse(
'rest_api:resolvedsmartlink-detail',
args=(self.document.pk, self.smart_link.pk)
)
)
self.assertEqual(
response.data['label'], TEST_SMART_LINK_LABEL
)
def test_resolved_smart_link_list_view(self):
self._create_document_type()
self._create_smart_link()
self._create_smart_link_condition()
self._create_document()
response = self.client.get(
reverse(
'rest_api:resolvedsmartlink-list', args=(self.document.pk,)
)
)
self.assertEqual(
response.data['results'][0]['label'], TEST_SMART_LINK_LABEL
)
def test_resolved_smart_link_document_list_view(self):
self._create_document_type()
self._create_smart_link()
self._create_smart_link_condition()
self._create_document()
response = self.client.get(
reverse(
'rest_api:resolvedsmartlinkdocument-list',
args=(self.document.pk, self.smart_link.pk)
)
)
self.assertEqual(
response.data['results'][0]['label'], self.document.label
)
def test_smart_link_condition_create_view(self):
self._create_document_type()
self._create_smart_link()
response = self.client.post(
reverse(
'rest_api:smartlinkcondition-list', args=(self.smart_link.pk,)
), {
'foreign_document_data': TEST_SMART_LINK_CONDITION_FOREIGN_DOCUMENT_DATA,
'expression': TEST_SMART_LINK_CONDITION_EXPRESSION,
'operator': TEST_SMART_LINK_CONDITION_OPERATOR
}
)
smart_link_condition = SmartLinkCondition.objects.first()
self.assertEqual(response.data['id'], smart_link_condition.pk)
self.assertEqual(
response.data['operator'], TEST_SMART_LINK_CONDITION_OPERATOR
)
self.assertEqual(SmartLinkCondition.objects.count(), 1)
self.assertEqual(
smart_link_condition.operator, TEST_SMART_LINK_CONDITION_OPERATOR
)
def test_smart_link_condition_delete_view(self):
self._create_document_type()
self._create_smart_link()
self._create_smart_link_condition()
self.client.delete(
reverse(
'rest_api:smartlinkcondition-detail',
args=(self.smart_link.pk, self.smart_link_condition.pk)
)
)
self.assertEqual(SmartLinkCondition.objects.count(), 0)
def test_smart_link_condition_detail_view(self):
self._create_document_type()
self._create_smart_link()
self._create_smart_link_condition()
response = self.client.get(
reverse(
'rest_api:smartlinkcondition-detail',
args=(self.smart_link.pk, self.smart_link_condition.pk)
)
)
self.assertEqual(
response.data['operator'], TEST_SMART_LINK_CONDITION_OPERATOR
)
def test_smart_link_condition_patch_view(self):
self._create_document_type()
self._create_smart_link()
self._create_smart_link_condition()
self.client.patch(
reverse(
'rest_api:smartlinkcondition-detail',
args=(self.smart_link.pk, self.smart_link_condition.pk)
),
data={
'expression': TEST_SMART_LINK_CONDITION_EXPRESSION_EDITED,
}
)
self.smart_link_condition.refresh_from_db()
self.assertEqual(
self.smart_link_condition.expression,
TEST_SMART_LINK_CONDITION_EXPRESSION_EDITED
)
def test_smart_link_condition_put_view(self):
self._create_document_type()
self._create_smart_link()
self._create_smart_link_condition()
self.client.put(
reverse(
'rest_api:smartlinkcondition-detail',
args=(self.smart_link.pk, self.smart_link_condition.pk)
),
data={
'expression': TEST_SMART_LINK_CONDITION_EXPRESSION_EDITED,
'foreign_document_data': TEST_SMART_LINK_CONDITION_FOREIGN_DOCUMENT_DATA,
'operator': TEST_SMART_LINK_CONDITION_OPERATOR,
}
)
self.smart_link_condition.refresh_from_db()
self.assertEqual(
self.smart_link_condition.expression,
TEST_SMART_LINK_CONDITION_EXPRESSION_EDITED
)
+4 -4
View File
@@ -13,7 +13,7 @@ from ..permissions import (
)
from .literals import (
TEST_SMART_LINK_DYNAMIC_LABEL, TEST_SMART_LINK_EDITED_LABEL,
TEST_SMART_LINK_DYNAMIC_LABEL, TEST_SMART_LINK_LABEL_EDITED,
TEST_SMART_LINK_LABEL
)
@@ -83,7 +83,7 @@ class SmartLinkViewTestCase(GenericDocumentViewTestCase):
response = self.post(
'linking:smart_link_edit', args=(smart_link.pk,), data={
'label': TEST_SMART_LINK_EDITED_LABEL
'label': TEST_SMART_LINK_LABEL_EDITED
}
)
self.assertEqual(response.status_code, 403)
@@ -101,13 +101,13 @@ class SmartLinkViewTestCase(GenericDocumentViewTestCase):
response = self.post(
'linking:smart_link_edit', args=(smart_link.pk,), data={
'label': TEST_SMART_LINK_EDITED_LABEL
'label': TEST_SMART_LINK_LABEL_EDITED
}, follow=True
)
smart_link = SmartLink.objects.get(pk=smart_link.pk)
self.assertContains(response, text='update', status_code=200)
self.assertEqual(smart_link.label, TEST_SMART_LINK_EDITED_LABEL)
self.assertEqual(smart_link.label, TEST_SMART_LINK_LABEL_EDITED)
def setup_smart_links(self):
smart_link = SmartLink.objects.create(
+40
View File
@@ -2,6 +2,11 @@ from __future__ import unicode_literals
from django.conf.urls import patterns, url
from .api_views import (
APIResolvedSmartLinkView, APIResolvedSmartLinkDocumentListView,
APIResolvedSmartLinkListView, APISmartLinkListView, APISmartLinkView,
APISmartLinkConditionListView, APISmartLinkConditionView
)
from .views import (
DocumentSmartLinkListView, ResolvedSmartLinkView,
SetupSmartLinkDocumentTypesView, SmartLinkConditionListView,
@@ -61,3 +66,38 @@ urlpatterns = patterns(
name='smart_link_condition_delete'
),
)
api_urls = [
url(
r'^smart_links/$', APISmartLinkListView.as_view(),
name='smartlink-list'
),
url(
r'^smart_links/(?P<pk>[0-9]+)/$', APISmartLinkView.as_view(),
name='smartlink-detail'
),
url(
r'^smart_links/(?P<pk>[0-9]+)/conditions/$',
APISmartLinkConditionListView.as_view(), name='smartlinkcondition-list'
),
url(
r'^smart_links/(?P<pk>[0-9]+)/conditions/(?P<condition_pk>[0-9]+)/$',
APISmartLinkConditionView.as_view(),
name='smartlinkcondition-detail'
),
url(
r'^documents/(?P<pk>[0-9]+)/resolved_smart_links/$',
APIResolvedSmartLinkListView.as_view(),
name='resolvedsmartlink-list'
),
url(
r'^documents/(?P<pk>[0-9]+)/resolved_smart_links/(?P<smart_link_pk>[0-9]+)/$',
APIResolvedSmartLinkView.as_view(),
name='resolvedsmartlink-detail'
),
url(
r'^documents/(?P<pk>[0-9]+)/resolved_smart_links/(?P<smart_link_pk>[0-9]+)/documents/$',
APIResolvedSmartLinkDocumentListView.as_view(),
name='resolvedsmartlinkdocument-list'
),
]
+1 -3
View File
@@ -174,9 +174,7 @@ class DocumentSmartLinkListView(SmartLinkListView):
}
def get_smart_link_queryset(self):
return ResolvedSmartLink.objects.filter(
document_types=self.document.document_type, enabled=True
)
return ResolvedSmartLink.objects.get_for(document=self.document)
class SmartLinkCreateView(SingleObjectCreateView):
+1 -1
View File
@@ -266,7 +266,7 @@ class APIDocumentTypeMetadataTypeOptionalListView(generics.ListCreateAPIView):
document_type
)
serializer = self.get_serializer(data=self.request.POST)
serializer = self.get_serializer(data=self.request.data)
if serializer.is_valid():
metadata_type = get_object_or_404(
+3 -2
View File
@@ -5,7 +5,7 @@ import shlex
from django.core.exceptions import ValidationError
from django.db import models
from django.template import Context, Template
from django.utils.encoding import python_2_unicode_compatible
from django.utils.encoding import force_text, python_2_unicode_compatible
from django.utils.module_loading import import_string
from django.utils.translation import ugettext_lazy as _
@@ -97,7 +97,7 @@ class MetadataType(models.Model):
splitter.whitespace = ','.encode('utf-8')
splitter.whitespace_split = True
splitter.commenters = ''.encode('utf-8')
return list(splitter)
return [force_text(e) for e in splitter]
def get_default_value(self):
template = Template(self.default)
@@ -126,6 +126,7 @@ class MetadataType(models.Model):
if self.lookup:
lookup_options = self.get_lookup_values()
if value and value not in lookup_options:
raise ValidationError(
_('Value is not one of the provided options.')
+12 -5
View File
@@ -1,8 +1,10 @@
from __future__ import unicode_literals
from django.db import IntegrityError
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from .models import DocumentMetadata, MetadataType, DocumentTypeMetadataType
@@ -26,7 +28,7 @@ class DocumentMetadataSerializer(serializers.ModelSerializer):
class DocumentTypeMetadataTypeSerializer(serializers.ModelSerializer):
class Meta:
fields = ('metadata_type', )
fields = ('metadata_type',)
model = DocumentTypeMetadataType
@@ -52,10 +54,15 @@ class DocumentNewMetadataSerializer(serializers.Serializer):
metadata_type = MetadataType.objects.get(
pk=validated_data['metadata_type_pk']
)
instance = self.document.metadata.create(
metadata_type=metadata_type, value=validated_data['value']
)
return instance
try:
instance = self.document.metadata.create(
metadata_type=metadata_type, value=validated_data['value']
)
return instance
except IntegrityError:
detail = 'Metadata type with pk {} is already defined for Document with pk {}'.format(metadata_type.pk,
self.document.pk)
raise ValidationError(detail)
class DocumentTypeNewMetadataTypeSerializer(serializers.Serializer):
+13
View File
@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.core.files.base import File
@@ -175,3 +176,15 @@ class MetadataTestCase(TestCase):
self.assertTrue(
self.metadata_type.get_required_for(self.document_type)
)
def test_unicode_lookup(self):
# Should NOT return a ValidationError, otherwise test fails
self.metadata_type.lookup = '测试1,测试2,test1,test2'
self.metadata_type.save()
self.metadata_type.validate_value(document_type=None, value='测试1')
def test_non_unicode_lookup(self):
# Should NOT return a ValidationError, otherwise test fails
self.metadata_type.lookup = 'test1,test2'
self.metadata_type.save()
self.metadata_type.validate_value(document_type=None, value='test1')
+1 -1
View File
@@ -70,7 +70,7 @@ class MOTDAPITestCase(APITestCase):
response.data['label'], TEST_LABEL
)
def test_message_path_view(self):
def test_message_patch_view(self):
message = self._create_message()
self.client.patch(