Refactor metadata app API
Signed-off-by: Roberto Rosario <Roberto.Rosario@mayan-edms.com>
This commit is contained in:
@@ -8,13 +8,14 @@ from mayan.apps.common.mixins import ContentTypeViewMixin, ExternalObjectMixin
|
||||
from mayan.apps.permissions.serializers import (
|
||||
PermissionSerializer, RolePermissionAddRemoveSerializer
|
||||
)
|
||||
from mayan.apps.rest_api.mixins import ExternalObjectAPIViewSetMixin
|
||||
from mayan.apps.rest_api.viewsets import MayanAPIModelViewSet
|
||||
|
||||
from .permissions import permission_acl_edit, permission_acl_view
|
||||
from .serializers import AccessControlListSerializer
|
||||
|
||||
|
||||
class ObjectACLAPIViewSet(ContentTypeViewMixin, ExternalObjectMixin, MayanAPIModelViewSet):
|
||||
class ObjectACLAPIViewSet(ContentTypeViewMixin, ExternalObjectAPIViewSetMixin, MayanAPIModelViewSet):
|
||||
content_type_url_kw_args = {
|
||||
'app_label': 'app_label',
|
||||
'model': 'model_name'
|
||||
|
||||
@@ -5,7 +5,8 @@ from rest_framework import viewsets
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
|
||||
from mayan.apps.common.mixins import ContentTypeViewMixin, ExternalObjectMixin
|
||||
from mayan.apps.common.mixins import ContentTypeViewMixin
|
||||
from mayan.apps.rest_api.mixins import ExternalObjectAPIViewSetMixin
|
||||
from mayan.apps.rest_api.viewsets import MayanAPIReadOnlyModelViewSet
|
||||
|
||||
from .classes import EventTypeNamespace
|
||||
@@ -80,7 +81,7 @@ class NotificationAPIViewSet(MayanAPIReadOnlyModelViewSet):
|
||||
return queryset
|
||||
|
||||
|
||||
class ObjectEventAPIViewSet(ContentTypeViewMixin, ExternalObjectMixin, MayanAPIReadOnlyModelViewSet):
|
||||
class ObjectEventAPIViewSet(ContentTypeViewMixin, ExternalObjectAPIViewSetMixin, MayanAPIReadOnlyModelViewSet):
|
||||
content_type_url_kw_args = {
|
||||
'app_label': 'app_label',
|
||||
'model': 'model_name'
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from django.shortcuts import get_object_or_404
|
||||
from rest_framework import status
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
|
||||
from rest_framework import generics
|
||||
|
||||
from mayan.apps.acls.models import AccessControlList
|
||||
from mayan.apps.documents.models import Document, DocumentType
|
||||
from mayan.apps.documents.models import Document
|
||||
from mayan.apps.documents.permissions import (
|
||||
permission_document_type_view, permission_document_type_edit
|
||||
permission_document_type_view, permission_document_type_edit,
|
||||
)
|
||||
from mayan.apps.rest_api.mixins import ExternalObjectAPIViewSetMixin
|
||||
from mayan.apps.rest_api.viewsets import (
|
||||
MayanAPIModelViewSet, MayanRetrieveUpdateAPIViewSet,
|
||||
)
|
||||
from mayan.apps.rest_api.filters import MayanObjectPermissionsFilter
|
||||
from mayan.apps.rest_api.permissions import MayanPermission
|
||||
|
||||
from .models import MetadataType
|
||||
from .permissions import (
|
||||
@@ -20,235 +21,140 @@ from .permissions import (
|
||||
permission_metadata_type_edit, permission_metadata_type_view
|
||||
)
|
||||
from .serializers import (
|
||||
DocumentMetadataSerializer, DocumentTypeMetadataTypeSerializer,
|
||||
MetadataTypeSerializer, NewDocumentMetadataSerializer,
|
||||
NewDocumentTypeMetadataTypeSerializer,
|
||||
WritableDocumentTypeMetadataTypeSerializer
|
||||
DocumentMetadataAddSerializer,
|
||||
DocumentMetadataSerializer,
|
||||
MetadataTypeSerializer,
|
||||
MetadataTypeDocumentTypeRelationSerializer,
|
||||
MetadataTypeDocumentTypeRelationAddRemoveSerializer,
|
||||
)
|
||||
|
||||
|
||||
class APIDocumentMetadataListView(generics.ListCreateAPIView):
|
||||
"""
|
||||
get: Returns a list of selected document's metadata types and values.
|
||||
post: Add an existing metadata type and value to the selected document.
|
||||
"""
|
||||
def get_document(self):
|
||||
if self.request.method == 'GET':
|
||||
permission_required = permission_metadata_view
|
||||
else:
|
||||
permission_required = permission_metadata_add
|
||||
|
||||
document = get_object_or_404(
|
||||
klass=Document, pk=self.kwargs['document_pk']
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_required, user=self.request.user,
|
||||
obj=document
|
||||
)
|
||||
|
||||
return document
|
||||
|
||||
def get_queryset(self):
|
||||
return self.get_document().metadata.all()
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
if not self.request:
|
||||
return None
|
||||
|
||||
return super(APIDocumentMetadataListView, self).get_serializer(*args, **kwargs)
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.request.method == 'GET':
|
||||
return DocumentMetadataSerializer
|
||||
else:
|
||||
return NewDocumentMetadataSerializer
|
||||
|
||||
def get_serializer_context(self):
|
||||
"""
|
||||
Extra context provided to the serializer class.
|
||||
"""
|
||||
context = super(APIDocumentMetadataListView, self).get_serializer_context()
|
||||
if self.kwargs:
|
||||
context.update(
|
||||
{
|
||||
'document': self.get_document(),
|
||||
}
|
||||
)
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class APIDocumentMetadataView(generics.RetrieveUpdateDestroyAPIView):
|
||||
"""
|
||||
delete: Remove this metadata entry from the selected document.
|
||||
get: Return the details of the selected document metadata type and value.
|
||||
patch: Edit the selected document metadata type and value.
|
||||
put: Edit the selected document metadata type and value.
|
||||
"""
|
||||
lookup_url_kwarg = 'metadata_pk'
|
||||
|
||||
def get_document(self):
|
||||
if self.request.method == 'GET':
|
||||
permission_required = permission_metadata_view
|
||||
elif self.request.method == 'PUT':
|
||||
permission_required = permission_metadata_edit
|
||||
elif self.request.method == 'PATCH':
|
||||
permission_required = permission_metadata_edit
|
||||
elif self.request.method == 'DELETE':
|
||||
permission_required = permission_metadata_remove
|
||||
|
||||
document = get_object_or_404(
|
||||
klass=Document, pk=self.kwargs['document_pk']
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_required, user=self.request.user,
|
||||
obj=document
|
||||
)
|
||||
|
||||
return document
|
||||
|
||||
def get_queryset(self):
|
||||
return self.get_document().metadata.all()
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
if not self.request:
|
||||
return None
|
||||
|
||||
return super(APIDocumentMetadataView, self).get_serializer(*args, **kwargs)
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.request.method == 'GET':
|
||||
return DocumentMetadataSerializer
|
||||
else:
|
||||
return DocumentMetadataSerializer
|
||||
|
||||
|
||||
class APIMetadataTypeListView(generics.ListCreateAPIView):
|
||||
"""
|
||||
get: Returns a list of all the metadata types.
|
||||
post: Create a new metadata type.
|
||||
"""
|
||||
filter_backends = (MayanObjectPermissionsFilter,)
|
||||
mayan_object_permissions = {'GET': (permission_metadata_type_view,)}
|
||||
mayan_view_permissions = {'POST': (permission_metadata_type_create,)}
|
||||
permission_classes = (MayanPermission,)
|
||||
queryset = MetadataType.objects.all()
|
||||
serializer_class = MetadataTypeSerializer
|
||||
|
||||
|
||||
class APIMetadataTypeView(generics.RetrieveUpdateDestroyAPIView):
|
||||
"""
|
||||
delete: Delete the selected metadata type.
|
||||
get: Return the details of the selected metadata type.
|
||||
patch: Edit the selected metadata type.
|
||||
put: Edit the selected metadata type.
|
||||
"""
|
||||
lookup_url_kwarg = 'metadata_type_pk'
|
||||
mayan_object_permissions = {
|
||||
'GET': (permission_metadata_type_view,),
|
||||
'PUT': (permission_metadata_type_edit,),
|
||||
'PATCH': (permission_metadata_type_edit,),
|
||||
'DELETE': (permission_metadata_type_delete,)
|
||||
class MetadataTypeDocumentTypeRelationAPIViewSet(ExternalObjectAPIViewSetMixin, MayanRetrieveUpdateAPIViewSet):
|
||||
external_object_class = MetadataType
|
||||
external_object_pk_url_kwarg = 'metadata_type_id'
|
||||
lookup_url_kwarg = 'metadata_type_document_type_relation_id'
|
||||
object_permission_map = {
|
||||
'add': permission_metadata_type_edit,
|
||||
'list': permission_document_type_view,
|
||||
'partial_update': permission_document_type_edit,
|
||||
'remove': permission_metadata_type_edit,
|
||||
'retrieve': permission_document_type_view,
|
||||
'update': permission_document_type_edit,
|
||||
}
|
||||
permission_classes = (MayanPermission,)
|
||||
queryset = MetadataType.objects.all()
|
||||
serializer_class = MetadataTypeSerializer
|
||||
serializer_class = MetadataTypeDocumentTypeRelationSerializer
|
||||
|
||||
|
||||
class APIDocumentTypeMetadataTypeListView(generics.ListCreateAPIView):
|
||||
"""
|
||||
get: Returns a list of selected document type's metadata types.
|
||||
post: Add a metadata type to the selected document type.
|
||||
"""
|
||||
lookup_url_kwarg = 'metadata_type_pk'
|
||||
|
||||
def get_document_type(self):
|
||||
if self.request.method == 'GET':
|
||||
permission_required = permission_document_type_view
|
||||
def get_external_object_permission(self):
|
||||
action = getattr(self, 'action', None)
|
||||
if action is None:
|
||||
return None
|
||||
elif action in ['list', 'retrieve']:
|
||||
return permission_metadata_type_view
|
||||
else:
|
||||
permission_required = permission_document_type_edit
|
||||
|
||||
document_type = get_object_or_404(
|
||||
klass=DocumentType, pk=self.kwargs['document_type_pk']
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_required, user=self.request.user,
|
||||
obj=document_type
|
||||
)
|
||||
|
||||
return document_type
|
||||
return permission_metadata_type_edit
|
||||
|
||||
def get_queryset(self):
|
||||
return self.get_document_type().metadata.all()
|
||||
action = getattr(self, 'action', None)
|
||||
if action in ['add', 'remove']:
|
||||
# Return metadata types
|
||||
return self.get_external_object_queryset()
|
||||
else:
|
||||
# Return relations
|
||||
return self.get_external_object().document_type_relations.all()
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
if not self.request:
|
||||
@action(
|
||||
detail=False, lookup_url_kwarg='metadata_type_id', methods=('post',),
|
||||
serializer_class=MetadataTypeDocumentTypeRelationAddRemoveSerializer,
|
||||
url_name='add', url_path='add'
|
||||
)
|
||||
def add(self, request, *args, **kwargs):
|
||||
instance = self.get_object()
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.document_type_relations_add(instance=instance)
|
||||
headers = self.get_success_headers(data=serializer.data)
|
||||
return Response(
|
||||
serializer.data, status=status.HTTP_200_OK, headers=headers
|
||||
)
|
||||
|
||||
@action(
|
||||
detail=False, lookup_url_kwarg='metadata_type_id', methods=('post',),
|
||||
serializer_class=MetadataTypeDocumentTypeRelationAddRemoveSerializer,
|
||||
url_name='remove', url_path='remove'
|
||||
)
|
||||
def remove(self, request, *args, **kwargs):
|
||||
instance = self.get_object()
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.document_type_relations_remove(instance=instance)
|
||||
headers = self.get_success_headers(data=serializer.data)
|
||||
return Response(
|
||||
serializer.data, status=status.HTTP_200_OK, headers=headers
|
||||
)
|
||||
|
||||
|
||||
class MetadataTypeAPIViewSet(MayanAPIModelViewSet):
|
||||
lookup_url_kwarg = 'metadata_type_id'
|
||||
object_permission_map = {
|
||||
'destroy': permission_metadata_type_delete,
|
||||
'list': permission_metadata_type_view,
|
||||
'partial_update': permission_metadata_type_edit,
|
||||
'retrieve': permission_metadata_type_view,
|
||||
'update': permission_metadata_type_edit,
|
||||
}
|
||||
queryset = MetadataType.objects.all()
|
||||
serializer_class = MetadataTypeSerializer
|
||||
view_permission_map = {
|
||||
'create': permission_metadata_type_create
|
||||
}
|
||||
|
||||
|
||||
class DocumentMetadataAPIViewSet(ExternalObjectAPIViewSetMixin, MayanAPIModelViewSet):
|
||||
external_object_class = Document
|
||||
external_object_pk_url_kwarg = 'document_id'
|
||||
lookup_url_kwarg = 'document_metadata_id'
|
||||
object_permission_map = {
|
||||
'list': permission_metadata_view,
|
||||
'partial_update': permission_metadata_edit,
|
||||
'destroy': permission_metadata_remove,
|
||||
'retrieve': permission_metadata_view,
|
||||
'update': permission_metadata_edit,
|
||||
}
|
||||
|
||||
def get_external_object_permission(self):
|
||||
action = getattr(self, 'action', None)
|
||||
if action is None:
|
||||
return None
|
||||
elif action == 'create':
|
||||
return permission_metadata_add
|
||||
elif action == 'destroy':
|
||||
return permission_metadata_remove
|
||||
elif action in ['partial_update', 'update']:
|
||||
return permission_metadata_edit
|
||||
else:
|
||||
return permission_metadata_view
|
||||
|
||||
return super(APIDocumentTypeMetadataTypeListView, self).get_serializer(*args, **kwargs)
|
||||
def get_queryset(self):
|
||||
return self.get_external_object().metadata.all()
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.request.method == 'GET':
|
||||
return DocumentTypeMetadataTypeSerializer
|
||||
action = getattr(self, 'action', None)
|
||||
if action is None:
|
||||
return None
|
||||
if action == 'create':
|
||||
return DocumentMetadataAddSerializer
|
||||
else:
|
||||
return NewDocumentTypeMetadataTypeSerializer
|
||||
return DocumentMetadataSerializer
|
||||
|
||||
def get_serializer_context(self):
|
||||
"""
|
||||
Extra context provided to the serializer class.
|
||||
"""
|
||||
context = super(APIDocumentTypeMetadataTypeListView, self).get_serializer_context()
|
||||
context = super(DocumentMetadataAPIViewSet, self).get_serializer_context()
|
||||
if self.kwargs:
|
||||
context.update(
|
||||
{
|
||||
'document_type': self.get_document_type(),
|
||||
'document': self.get_external_object(),
|
||||
}
|
||||
)
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class APIDocumentTypeMetadataTypeView(generics.RetrieveUpdateDestroyAPIView):
|
||||
"""
|
||||
delete: Remove a metadata type from a document type.
|
||||
get: Retrieve the details of a document type metadata type.
|
||||
patch: Edit the selected document type metadata type.
|
||||
put: Edit the selected document type metadata type.
|
||||
"""
|
||||
lookup_url_kwarg = 'metadata_type_pk'
|
||||
serializer_class = DocumentTypeMetadataTypeSerializer
|
||||
|
||||
def get_document_type(self):
|
||||
if self.request.method == 'GET':
|
||||
permission_required = permission_document_type_view
|
||||
else:
|
||||
permission_required = permission_document_type_edit
|
||||
|
||||
document_type = get_object_or_404(
|
||||
klass=DocumentType, pk=self.kwargs['document_type_pk']
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_required, user=self.request.user,
|
||||
obj=document_type
|
||||
)
|
||||
|
||||
return document_type
|
||||
|
||||
def get_queryset(self):
|
||||
return self.get_document_type().metadata.all()
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
if not self.request:
|
||||
return None
|
||||
|
||||
return super(APIDocumentTypeMetadataTypeView, self).get_serializer(*args, **kwargs)
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.request.method == 'GET':
|
||||
return DocumentTypeMetadataTypeSerializer
|
||||
else:
|
||||
return WritableDocumentTypeMetadataTypeSerializer
|
||||
|
||||
@@ -13,7 +13,7 @@ from mayan.apps.acls.links import link_acl_list
|
||||
from mayan.apps.acls.permissions import permission_acl_edit, permission_acl_view
|
||||
from mayan.apps.common import (
|
||||
MayanAppConfig, menu_facet, menu_list_facet, menu_multi_item, menu_object,
|
||||
menu_secondary, menu_setup, menu_secondary
|
||||
menu_secondary, menu_setup
|
||||
)
|
||||
from mayan.apps.common.classes import ModelAttribute, ModelField
|
||||
from mayan.apps.common.widgets import TwoStateWidget
|
||||
@@ -26,6 +26,8 @@ from mayan.apps.events.links import (
|
||||
from mayan.apps.events.permissions import permission_events_view
|
||||
from mayan.celery import app
|
||||
from mayan.apps.navigation import SourceColumn
|
||||
from mayan.apps.rest_api.fields import HyperlinkField
|
||||
from mayan.apps.rest_api.serializers import LazyExtraFieldsSerializerMixin
|
||||
|
||||
from .events import (
|
||||
event_document_metadata_added, event_document_metadata_edited,
|
||||
@@ -80,11 +82,9 @@ class MetadataApp(MayanAppConfig):
|
||||
DocumentPageSearchResult = apps.get_model(
|
||||
app_label='documents', model_name='DocumentPageSearchResult'
|
||||
)
|
||||
|
||||
DocumentType = apps.get_model(
|
||||
app_label='documents', model_name='DocumentType'
|
||||
)
|
||||
|
||||
DocumentMetadata = self.get_model('DocumentMetadata')
|
||||
DocumentTypeMetadataType = self.get_model('DocumentTypeMetadataType')
|
||||
MetadataType = self.get_model('MetadataType')
|
||||
@@ -93,6 +93,15 @@ class MetadataApp(MayanAppConfig):
|
||||
name='get_metadata', value=method_get_metadata
|
||||
)
|
||||
|
||||
LazyExtraFieldsSerializerMixin.add_field(
|
||||
dotted_path='mayan.apps.documents.serializers.DocumentSerializer',
|
||||
field_name='metadata_list_url',
|
||||
field=HyperlinkField(
|
||||
lookup_url_kwarg='document_id',
|
||||
view_name='rest_api:document-metadata-list'
|
||||
)
|
||||
)
|
||||
|
||||
ModelAttribute(model=Document, name='get_metadata')
|
||||
|
||||
ModelField(
|
||||
@@ -140,10 +149,25 @@ class MetadataApp(MayanAppConfig):
|
||||
model=MetadataType, permissions=(
|
||||
permission_acl_edit, permission_acl_view,
|
||||
permission_events_view, permission_metadata_type_delete,
|
||||
permission_metadata_add, permission_metadata_edit,
|
||||
permission_metadata_remove, permission_metadata_view,
|
||||
permission_metadata_type_edit, permission_metadata_type_view
|
||||
)
|
||||
)
|
||||
|
||||
ModelPermission.register_inheritance(
|
||||
model=DocumentMetadata, related='document',
|
||||
)
|
||||
ModelPermission.register_inheritance(
|
||||
model=DocumentMetadata, related='metadata_type',
|
||||
)
|
||||
ModelPermission.register_inheritance(
|
||||
model=DocumentTypeMetadataType, related='document_type',
|
||||
)
|
||||
ModelPermission.register_inheritance(
|
||||
model=DocumentTypeMetadataType, related='metadata_type',
|
||||
)
|
||||
|
||||
SourceColumn(
|
||||
func=widget_get_metadata_string, source=Document
|
||||
)
|
||||
|
||||
@@ -198,12 +198,12 @@ class DocumentTypeMetadataTypeRelationshipForm(forms.Form):
|
||||
self.fields['relationship_type'].initial = self.initial_relationship_type
|
||||
|
||||
def get_relationship(self):
|
||||
return self.initial['document_type'].metadata.filter(
|
||||
return self.initial['document_type'].metadata_type_relations.filter(
|
||||
metadata_type=self.initial['metadata_type']
|
||||
)
|
||||
|
||||
def get_relationship_choices(self):
|
||||
return self.initial['document_type'].metadata.filter(
|
||||
return self.initial['document_type'].metadata_type_relations.filter(
|
||||
metadata_type=self.initial['metadata_type']
|
||||
)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ def handler_post_document_type_change(sender, instance, **kwargs):
|
||||
# First get the existing metadata types not found in the new document
|
||||
# type
|
||||
unneeded_metadata = instance.metadata.exclude(
|
||||
metadata_type__in=instance.document_type.metadata.values(
|
||||
metadata_type__in=instance.document_type.metadata_type_relations.values(
|
||||
'metadata_type'
|
||||
)
|
||||
)
|
||||
@@ -39,7 +39,7 @@ def handler_post_document_type_change(sender, instance, **kwargs):
|
||||
# excluding existing document metadata
|
||||
# get_or_create is not used to avoid a possible triggering of indexes
|
||||
# or workflow on document change by metadata save signal
|
||||
new_document_type_metadata_types = instance.document_type.metadata.filter(
|
||||
new_document_type_metadata_types = instance.document_type.metadata_type_relations.filter(
|
||||
required=True
|
||||
).exclude(metadata_type__in=instance.metadata.values('metadata_type'))
|
||||
|
||||
|
||||
@@ -9,18 +9,10 @@ class MetadataTypeManager(models.Manager):
|
||||
return self.get(name=name)
|
||||
|
||||
def get_for_document(self, document):
|
||||
return self.filter(
|
||||
pk__in=document.metadata.values_list(
|
||||
'metadata_type', flat=True
|
||||
)
|
||||
)
|
||||
return self.filter(document_metadata__document=document)
|
||||
|
||||
def get_for_document_type(self, document_type):
|
||||
return self.filter(
|
||||
pk__in=document_type.metadata.values_list(
|
||||
'metadata_type', flat=True
|
||||
)
|
||||
)
|
||||
return self.filter(document_type_relations__document_type=document_type)
|
||||
|
||||
|
||||
class DocumentTypeMetadataTypeManager(models.Manager):
|
||||
|
||||
@@ -5,13 +5,15 @@ import shlex
|
||||
from jinja2 import Template
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.db import models, transaction
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_text, python_2_unicode_compatible
|
||||
from django.utils.module_loading import import_string
|
||||
from django.utils.six import PY2
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from mayan.apps.acls.models import AccessControlList
|
||||
from mayan.apps.documents.events import event_document_type_edited
|
||||
from mayan.apps.documents.models import Document, DocumentType
|
||||
|
||||
from .classes import MetadataLookup
|
||||
@@ -126,6 +128,38 @@ class MetadataType(models.Model):
|
||||
template = Template(self.default)
|
||||
return template.render()
|
||||
|
||||
def get_document_type_relations(self, permission, user):
|
||||
return AccessControlList.objects.restrict_queryset(
|
||||
permission=permission, queryset=self.document_type_relations.all(),
|
||||
user=user
|
||||
)
|
||||
|
||||
def document_types_add(self, queryset, required=False, _user=None):
|
||||
with transaction.atomic():
|
||||
event_metadata_type_edited.commit(
|
||||
actor=_user, target=self
|
||||
)
|
||||
for obj in queryset:
|
||||
self.document_type_relations.create(
|
||||
document_type=obj, required=required
|
||||
)
|
||||
event_document_type_edited.commit(
|
||||
actor=_user, action_object=self, target=obj
|
||||
)
|
||||
|
||||
def document_types_remove(self, queryset, _user=None):
|
||||
with transaction.atomic():
|
||||
event_metadata_type_edited.commit(
|
||||
actor=_user, target=self
|
||||
)
|
||||
for obj in queryset:
|
||||
self.document_type_relations.filter(
|
||||
document_type=obj
|
||||
).delete()
|
||||
event_document_type_edited.commit(
|
||||
actor=_user, action_object=self, target=obj
|
||||
)
|
||||
|
||||
def get_lookup_choices(self, first_choice=None):
|
||||
template = Template(self.lookup)
|
||||
context = MetadataLookup.get_as_context()
|
||||
@@ -146,7 +180,7 @@ class MetadataType(models.Model):
|
||||
Return a queryset of metadata types that are required for the
|
||||
specified document type.
|
||||
"""
|
||||
return document_type.metadata.filter(
|
||||
return document_type.metadata_type_relations.filter(
|
||||
required=True, metadata_type=self
|
||||
).exists()
|
||||
|
||||
@@ -157,16 +191,17 @@ class MetadataType(models.Model):
|
||||
user = kwargs.pop('_user', None)
|
||||
created = not self.pk
|
||||
|
||||
result = super(MetadataType, self).save(*args, **kwargs)
|
||||
with transaction.atomic():
|
||||
result = super(MetadataType, self).save(*args, **kwargs)
|
||||
|
||||
if created:
|
||||
event_metadata_type_created.commit(
|
||||
actor=user, target=self
|
||||
)
|
||||
else:
|
||||
event_metadata_type_edited.commit(
|
||||
actor=user, target=self
|
||||
)
|
||||
if created:
|
||||
event_metadata_type_created.commit(
|
||||
actor=user, target=self
|
||||
)
|
||||
else:
|
||||
event_metadata_type_edited.commit(
|
||||
actor=user, target=self
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@@ -210,7 +245,8 @@ class DocumentMetadata(models.Model):
|
||||
verbose_name=_('Document')
|
||||
)
|
||||
metadata_type = models.ForeignKey(
|
||||
on_delete=models.CASCADE, to=MetadataType, verbose_name=_('Type')
|
||||
on_delete=models.CASCADE, related_name='document_metadata', to=MetadataType,
|
||||
verbose_name=_('Type')
|
||||
)
|
||||
value = models.CharField(
|
||||
blank=True, db_index=True, help_text=_(
|
||||
@@ -242,17 +278,19 @@ class DocumentMetadata(models.Model):
|
||||
It used set to False when deleting document metadata on document
|
||||
type change.
|
||||
"""
|
||||
if enforce_required and self.metadata_type.pk in self.document.document_type.metadata.filter(required=True).values_list('metadata_type', flat=True):
|
||||
if enforce_required and self.metadata_type.pk in self.document.document_type.metadata_type_relations.filter(required=True).values_list('metadata_type', flat=True):
|
||||
raise ValidationError(
|
||||
_('Metadata type is required for this document type.')
|
||||
)
|
||||
|
||||
user = kwargs.pop('_user', None)
|
||||
result = super(DocumentMetadata, self).delete(*args, **kwargs)
|
||||
with transaction.atomic():
|
||||
result = super(DocumentMetadata, self).delete(*args, **kwargs)
|
||||
|
||||
event_document_metadata_removed.commit(
|
||||
action_object=self.metadata_type, actor=user, target=self.document,
|
||||
)
|
||||
|
||||
event_document_metadata_removed.commit(
|
||||
action_object=self.metadata_type, actor=user, target=self.document,
|
||||
)
|
||||
return result
|
||||
|
||||
def natural_key(self):
|
||||
@@ -271,7 +309,7 @@ class DocumentMetadata(models.Model):
|
||||
is_required.fget.short_description = _('Required')
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.metadata_type.pk not in self.document.document_type.metadata.values_list('metadata_type', flat=True):
|
||||
if self.metadata_type.pk not in self.document.document_type.metadata_type_relations.values_list('metadata_type', flat=True):
|
||||
raise ValidationError(
|
||||
_('Metadata type is not valid for this document type.')
|
||||
)
|
||||
@@ -279,18 +317,19 @@ class DocumentMetadata(models.Model):
|
||||
user = kwargs.pop('_user', None)
|
||||
created = not self.pk
|
||||
|
||||
result = super(DocumentMetadata, self).save(*args, **kwargs)
|
||||
with transaction.atomic():
|
||||
result = super(DocumentMetadata, self).save(*args, **kwargs)
|
||||
|
||||
if created:
|
||||
event_document_metadata_added.commit(
|
||||
action_object=self.metadata_type, actor=user,
|
||||
target=self.document,
|
||||
)
|
||||
else:
|
||||
event_document_metadata_edited.commit(
|
||||
action_object=self.metadata_type, actor=user,
|
||||
target=self.document,
|
||||
)
|
||||
if created:
|
||||
event_document_metadata_added.commit(
|
||||
action_object=self.metadata_type, actor=user,
|
||||
target=self.document,
|
||||
)
|
||||
else:
|
||||
event_document_metadata_edited.commit(
|
||||
action_object=self.metadata_type, actor=user,
|
||||
target=self.document,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@@ -302,12 +341,12 @@ class DocumentTypeMetadataType(models.Model):
|
||||
document type.
|
||||
"""
|
||||
document_type = models.ForeignKey(
|
||||
on_delete=models.CASCADE, related_name='metadata', to=DocumentType,
|
||||
verbose_name=_('Document type')
|
||||
on_delete=models.CASCADE, related_name='metadata_type_relations',
|
||||
to=DocumentType, verbose_name=_('Document type')
|
||||
)
|
||||
metadata_type = models.ForeignKey(
|
||||
on_delete=models.CASCADE, to=MetadataType,
|
||||
verbose_name=_('Metadata type')
|
||||
on_delete=models.CASCADE, related_name='document_type_relations',
|
||||
to=MetadataType, verbose_name=_('Metadata type')
|
||||
)
|
||||
required = models.BooleanField(default=False, verbose_name=_('Required'))
|
||||
|
||||
@@ -325,21 +364,23 @@ class DocumentTypeMetadataType(models.Model):
|
||||
def delete(self, *args, **kwargs):
|
||||
user = kwargs.pop('_user', None)
|
||||
|
||||
result = super(DocumentTypeMetadataType, self).delete(*args, **kwargs)
|
||||
with transaction.atomic():
|
||||
result = super(DocumentTypeMetadataType, self).delete(*args, **kwargs)
|
||||
|
||||
event_metadata_type_relationship.commit(
|
||||
action_object=self.document_type, actor=user, target=self.metadata_type,
|
||||
)
|
||||
event_metadata_type_relationship.commit(
|
||||
action_object=self.document_type, actor=user, target=self.metadata_type,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
user = kwargs.pop('_user', None)
|
||||
|
||||
result = super(DocumentTypeMetadataType, self).save(*args, **kwargs)
|
||||
with transaction.atomic():
|
||||
result = super(DocumentTypeMetadataType, self).save(*args, **kwargs)
|
||||
|
||||
event_metadata_type_relationship.commit(
|
||||
action_object=self.document_type, actor=user, target=self.metadata_type,
|
||||
)
|
||||
event_metadata_type_relationship.commit(
|
||||
action_object=self.document_type, actor=user, target=self.metadata_type,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@@ -5,158 +5,149 @@ from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.reverse import reverse
|
||||
from rest_framework.settings import api_settings
|
||||
|
||||
from mayan.apps.documents.models import DocumentType
|
||||
from mayan.apps.documents.permissions import permission_document_type_edit
|
||||
from mayan.apps.documents.serializers import (
|
||||
DocumentSerializer, DocumentTypeSerializer
|
||||
)
|
||||
from mayan.apps.rest_api.mixins import ExternalObjectListSerializerMixin
|
||||
from mayan.apps.rest_api.relations import (
|
||||
FilteredPrimaryKeyRelatedField, MultiKwargHyperlinkedIdentityField
|
||||
)
|
||||
|
||||
from .models import DocumentMetadata, DocumentTypeMetadataType, MetadataType
|
||||
from .permissions import permission_metadata_add
|
||||
|
||||
|
||||
class MetadataTypeSerializer(serializers.HyperlinkedModelSerializer):
|
||||
document_type_relation_add_url = serializers.HyperlinkedIdentityField(
|
||||
lookup_url_kwarg='metadata_type_id', view_name='rest_api:metadata_type-document_type_relation-add'
|
||||
)
|
||||
document_type_relation_list_url = serializers.HyperlinkedIdentityField(
|
||||
lookup_url_kwarg='metadata_type_id', view_name='rest_api:metadata_type-document_type_relation-list'
|
||||
)
|
||||
document_type_relation_remove_url = serializers.HyperlinkedIdentityField(
|
||||
lookup_url_kwarg='metadata_type_id', view_name='rest_api:metadata_type-document_type_relation-remove'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
extra_kwargs = {
|
||||
'url': {
|
||||
'lookup_field': 'pk', 'lookup_url_kwarg': 'metadata_type_pk',
|
||||
'view_name': 'rest_api:metadatatype-detail'
|
||||
'lookup_url_kwarg': 'metadata_type_id',
|
||||
'view_name': 'rest_api:metadata_type-detail'
|
||||
},
|
||||
}
|
||||
fields = (
|
||||
'default', 'id', 'label', 'lookup', 'name', 'parser', 'url',
|
||||
'validation'
|
||||
'default', 'document_type_relation_add_url', 'document_type_relation_list_url',
|
||||
'document_type_relation_remove_url', 'id', 'label', 'lookup', 'name',
|
||||
'parser', 'url', 'validation'
|
||||
)
|
||||
model = MetadataType
|
||||
|
||||
|
||||
class DocumentTypeMetadataTypeSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class MetadataTypeDocumentTypeRelationSerializer(serializers.HyperlinkedModelSerializer):
|
||||
document_type = DocumentTypeSerializer(read_only=True)
|
||||
metadata_type = MetadataTypeSerializer(read_only=True)
|
||||
url = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
fields = ('document_type', 'id', 'metadata_type', 'required', 'url')
|
||||
model = DocumentTypeMetadataType
|
||||
|
||||
def get_url(self, instance):
|
||||
return reverse(
|
||||
viewname='rest_api:documenttypemetadatatype-detail', kwargs={
|
||||
'document_type_pk': instance.document_type.pk, 'metadata_type': instance.pk
|
||||
}, request=self.context['request'], format=self.context['format']
|
||||
)
|
||||
|
||||
|
||||
class NewDocumentTypeMetadataTypeSerializer(serializers.ModelSerializer):
|
||||
metadata_type_pk = serializers.IntegerField(
|
||||
help_text=_('Primary key of the metadata type to be added.'),
|
||||
write_only=True
|
||||
url = MultiKwargHyperlinkedIdentityField(
|
||||
view_kwargs=(
|
||||
{
|
||||
'lookup_field': 'metadata_type_id',
|
||||
'lookup_url_kwarg': 'metadata_type_id',
|
||||
},
|
||||
{
|
||||
'lookup_field': 'pk',
|
||||
'lookup_url_kwarg': 'metadata_type_document_type_relation_id',
|
||||
}
|
||||
),
|
||||
view_name='rest_api:metadata_type-document_type_relation-detail'
|
||||
)
|
||||
url = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
fields = (
|
||||
'id', 'metadata_type_pk', 'required', 'url'
|
||||
)
|
||||
fields = ('document_type', 'id', 'required', 'url')
|
||||
model = DocumentTypeMetadataType
|
||||
|
||||
def get_url(self, instance):
|
||||
return reverse(
|
||||
viewname='rest_api:documenttypemetadatatype-detail', kwargs={
|
||||
'document_type': instance.document_type.pk, 'metadata_type': instance.pk
|
||||
}, request=self.context['request'], format=self.context['format']
|
||||
)
|
||||
|
||||
def validate(self, attrs):
|
||||
attrs['document_type'] = self.context['document_type']
|
||||
attrs['metadata_type'] = MetadataType.objects.get(
|
||||
pk=attrs.pop('metadata_type_pk')
|
||||
)
|
||||
|
||||
instance = DocumentTypeMetadataType(**attrs)
|
||||
try:
|
||||
instance.full_clean()
|
||||
except DjangoValidationError as exception:
|
||||
raise ValidationError(exception)
|
||||
|
||||
return attrs
|
||||
|
||||
|
||||
class WritableDocumentTypeMetadataTypeSerializer(serializers.ModelSerializer):
|
||||
url = serializers.SerializerMethodField()
|
||||
class MetadataTypeDocumentTypeRelationAddRemoveSerializer(ExternalObjectListSerializerMixin, serializers.Serializer):
|
||||
document_type_id_list = serializers.CharField(
|
||||
help_text=_(
|
||||
'Comma separated list of document type primary keys that will be '
|
||||
'added or removed.'
|
||||
), label=_('Document Type ID list'), required=False, write_only=True
|
||||
)
|
||||
required = serializers.BooleanField(
|
||||
label=_('Required'), required=False, write_only=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
fields = (
|
||||
'id', 'required', 'url'
|
||||
)
|
||||
model = DocumentTypeMetadataType
|
||||
external_object_list_model = DocumentType
|
||||
external_object_list_permission = permission_document_type_edit
|
||||
external_object_list_pk_list_field = 'document_type_id_list'
|
||||
|
||||
def get_url(self, instance):
|
||||
return reverse(
|
||||
viewname='rest_api:documenttypemetadatatype-detail', kwargs={
|
||||
'document_type_pk': instance.document_type.pk,
|
||||
'metadata_type': instance.pk
|
||||
}, request=self.context['request'], format=self.context['format']
|
||||
def document_type_relations_add(self, instance):
|
||||
instance.document_types_add(
|
||||
queryset=self.get_external_object_list(),
|
||||
required=self.validated_data['required'],
|
||||
_user=self.context['request'].user
|
||||
)
|
||||
|
||||
def document_type_relations_remove(self, instance):
|
||||
instance.document_types_remove(
|
||||
queryset=self.get_external_object_list(),
|
||||
_user=self.context['request'].user
|
||||
)
|
||||
|
||||
|
||||
class DocumentMetadataSerializer(serializers.HyperlinkedModelSerializer):
|
||||
document = DocumentSerializer(read_only=True)
|
||||
metadata_type = MetadataTypeSerializer(read_only=True)
|
||||
url = serializers.SerializerMethodField()
|
||||
url = MultiKwargHyperlinkedIdentityField(
|
||||
view_kwargs=(
|
||||
{
|
||||
'lookup_field': 'document_id',
|
||||
'lookup_url_kwarg': 'document_id',
|
||||
},
|
||||
{
|
||||
'lookup_field': 'pk',
|
||||
'lookup_url_kwarg': 'document_metadata_id',
|
||||
}
|
||||
),
|
||||
view_name='rest_api:document-metadata-detail'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
fields = ('document', 'id', 'metadata_type', 'url', 'value')
|
||||
model = DocumentMetadata
|
||||
read_only_fields = ('document', 'metadata_type',)
|
||||
|
||||
def get_url(self, instance):
|
||||
return reverse(
|
||||
viewname='rest_api:documentmetadata-detail', kwargs={
|
||||
'document_pk': instance.document.pk, 'metadata_pk': instance.pk
|
||||
}, request=self.context['request'], format=self.context['format']
|
||||
)
|
||||
|
||||
def validate(self, attrs):
|
||||
self.instance.value = attrs['value']
|
||||
|
||||
try:
|
||||
self.instance.full_clean()
|
||||
except DjangoValidationError as exception:
|
||||
raise ValidationError(exception)
|
||||
|
||||
return attrs
|
||||
|
||||
|
||||
class NewDocumentMetadataSerializer(serializers.ModelSerializer):
|
||||
metadata_type_pk = serializers.IntegerField(
|
||||
help_text=_(
|
||||
'Primary key of the metadata type to be added to the document.'
|
||||
),
|
||||
class DocumentMetadataAddSerializer(DocumentMetadataSerializer):
|
||||
metadata_type = FilteredPrimaryKeyRelatedField(
|
||||
source_model=MetadataType, source_permission=permission_metadata_add,
|
||||
write_only=True
|
||||
)
|
||||
url = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
fields = ('id', 'metadata_type_pk', 'url', 'value')
|
||||
model = DocumentMetadata
|
||||
class Meta(DocumentMetadataSerializer.Meta):
|
||||
read_only_fields = ('document',)
|
||||
|
||||
def get_url(self, instance):
|
||||
return reverse(
|
||||
viewname='rest_api:documentmetadata-detail', kwargs={
|
||||
'document_pk': instance.document.pk, 'metadata_pk': instance.pk
|
||||
}, request=self.context['request'], format=self.context['format']
|
||||
def create(self, validated_data):
|
||||
validated_data['document'] = self.context['document']
|
||||
|
||||
return super(DocumentMetadataAddSerializer, self).create(
|
||||
validated_data=validated_data
|
||||
)
|
||||
|
||||
def validate(self, attrs):
|
||||
attrs['document'] = self.context['document']
|
||||
attrs['metadata_type'] = MetadataType.objects.get(
|
||||
pk=attrs.pop('metadata_type_pk')
|
||||
)
|
||||
|
||||
instance = DocumentMetadata(**attrs)
|
||||
|
||||
try:
|
||||
instance.full_clean()
|
||||
except DjangoValidationError as exception:
|
||||
raise ValidationError(exception)
|
||||
raise ValidationError(
|
||||
{
|
||||
api_settings.NON_FIELD_ERRORS_KEY: exception.messages
|
||||
}, code='invalid'
|
||||
)
|
||||
|
||||
return attrs
|
||||
|
||||
@@ -9,6 +9,7 @@ TEST_DEFAULT_VALUE = 'test'
|
||||
TEST_INCORRECT_LOOKUP_VALUE = '0'
|
||||
TEST_INVALID_DATE = '___________'
|
||||
TEST_LOOKUP_TEMPLATE = '1,2,3'
|
||||
TEST_METADATA_TYPE_INVALID_LOOKUP = 'invalid,lookup,values,on,purpose'
|
||||
TEST_METADATA_TYPE_LABEL = 'test metadata type'
|
||||
TEST_METADATA_TYPE_LABEL_2 = 'test metadata type label 2'
|
||||
TEST_METADATA_TYPE_LABEL_EDITED = 'test metadata type label edited'
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,9 @@ from .mixins import MetadataTypeTestMixin
|
||||
class MetadataTestCase(DocumentTestMixin, MetadataTypeTestMixin, BaseTestCase):
|
||||
def setUp(self):
|
||||
super(MetadataTestCase, self).setUp()
|
||||
self.document_type.metadata.create(metadata_type=self.metadata_type)
|
||||
self.document_type.metadata_type_relations.create(
|
||||
metadata_type=self.metadata_type
|
||||
)
|
||||
|
||||
def test_no_default(self):
|
||||
document_metadata = DocumentMetadata(
|
||||
@@ -146,13 +148,13 @@ class MetadataTestCase(DocumentTestMixin, MetadataTypeTestMixin, BaseTestCase):
|
||||
)
|
||||
|
||||
def test_required_metadata(self):
|
||||
self.document_type.metadata.all().delete()
|
||||
self.document_type.metadata_type_relations.all().delete()
|
||||
|
||||
self.assertFalse(
|
||||
self.metadata_type.get_required_for(self.document_type)
|
||||
)
|
||||
|
||||
self.document_type.metadata.create(
|
||||
self.document_type.metadata_type_relations.create(
|
||||
metadata_type=self.metadata_type, required=False
|
||||
)
|
||||
|
||||
@@ -160,9 +162,9 @@ class MetadataTestCase(DocumentTestMixin, MetadataTypeTestMixin, BaseTestCase):
|
||||
self.metadata_type.get_required_for(self.document_type)
|
||||
)
|
||||
|
||||
self.document_type.metadata.all().delete()
|
||||
self.document_type.metadata_type_relations.all().delete()
|
||||
|
||||
self.document_type.metadata.create(
|
||||
self.document_type.metadata_type_relations.create(
|
||||
metadata_type=self.metadata_type, required=True
|
||||
)
|
||||
|
||||
@@ -198,7 +200,7 @@ class MetadataTestCase(DocumentTestMixin, MetadataTypeTestMixin, BaseTestCase):
|
||||
label=TEST_DOCUMENT_TYPE_2_LABEL
|
||||
)
|
||||
|
||||
self.document_type_2.metadata.create(
|
||||
self.document_type_2.metadata_type_relations.create(
|
||||
metadata_type=self.metadata_type, required=True
|
||||
)
|
||||
|
||||
@@ -226,7 +228,9 @@ class MetadataTestCase(DocumentTestMixin, MetadataTypeTestMixin, BaseTestCase):
|
||||
label=TEST_DOCUMENT_TYPE_2_LABEL
|
||||
)
|
||||
|
||||
self.document_type_2.metadata.create(metadata_type=self.metadata_type)
|
||||
self.document_type_2.metadata_type_relations.create(
|
||||
metadata_type=self.metadata_type
|
||||
)
|
||||
|
||||
self.document.set_document_type(document_type=self.document_type_2)
|
||||
|
||||
@@ -276,7 +280,7 @@ class MetadataTestCase(DocumentTestMixin, MetadataTypeTestMixin, BaseTestCase):
|
||||
label=TEST_DOCUMENT_TYPE_2_LABEL
|
||||
)
|
||||
|
||||
self.document_type_2.metadata.create(
|
||||
self.document_type_2.metadata_type_relations.create(
|
||||
metadata_type=self.metadata_type, required=True
|
||||
)
|
||||
|
||||
|
||||
@@ -34,7 +34,9 @@ class DocumentMetadataViewTestCase(MetadataTestsMixin, GenericDocumentViewTestCa
|
||||
def setUp(self):
|
||||
super(DocumentMetadataViewTestCase, self).setUp()
|
||||
self._create_metadata_type()
|
||||
self.document_type.metadata.create(metadata_type=self.metadata_type)
|
||||
self.document_type.metadata_type_relations.create(
|
||||
metadata_type=self.metadata_type
|
||||
)
|
||||
|
||||
def _request_document_metadata_add_get_view(self):
|
||||
return self.get(
|
||||
@@ -76,7 +78,9 @@ class DocumentMetadataViewTestCase(MetadataTestsMixin, GenericDocumentViewTestCa
|
||||
)
|
||||
|
||||
self._create_document_type_random()
|
||||
self.test_document_type.metadata.create(metadata_type=self.metadata_type)
|
||||
self.test_document_type.metadata_type_relations.create(
|
||||
metadata_type=self.metadata_type
|
||||
)
|
||||
self._create_document()
|
||||
self.grant_access(
|
||||
obj=self.test_document, permission=permission_metadata_add
|
||||
@@ -94,7 +98,9 @@ class DocumentMetadataViewTestCase(MetadataTestsMixin, GenericDocumentViewTestCa
|
||||
)
|
||||
|
||||
self._create_document_type_random()
|
||||
self.test_document_type.metadata.create(metadata_type=self.metadata_type)
|
||||
self.test_document_type.metadata_type_relations.create(
|
||||
metadata_type=self.metadata_type
|
||||
)
|
||||
self._create_document()
|
||||
self.grant_access(
|
||||
obj=self.test_document, permission=permission_metadata_add
|
||||
@@ -112,7 +118,9 @@ class DocumentMetadataViewTestCase(MetadataTestsMixin, GenericDocumentViewTestCa
|
||||
)
|
||||
|
||||
self._create_document_type_random()
|
||||
self.test_document_type.metadata.create(metadata_type=self.metadata_type)
|
||||
self.test_document_type.metadata_type_relations.create(
|
||||
metadata_type=self.metadata_type
|
||||
)
|
||||
self._create_document()
|
||||
self.id_list.append(self.test_document.pk)
|
||||
self.grant_access(
|
||||
@@ -159,7 +167,7 @@ class DocumentMetadataViewTestCase(MetadataTestsMixin, GenericDocumentViewTestCa
|
||||
name=TEST_METADATA_TYPE_NAME_2, label=TEST_METADATA_TYPE_LABEL_2
|
||||
)
|
||||
|
||||
document_metadata_2 = document_type_2.metadata.create(
|
||||
document_metadata_2 = document_type_2.metadata_type_relations.create(
|
||||
metadata_type=metadata_type_2, required=True
|
||||
)
|
||||
|
||||
@@ -400,7 +408,7 @@ class DocumentMetadataViewTestCase(MetadataTestsMixin, GenericDocumentViewTestCa
|
||||
name=TEST_METADATA_TYPE_NAME_2, label=TEST_METADATA_TYPE_LABEL_2
|
||||
)
|
||||
|
||||
self.document_type.metadata.create(
|
||||
self.document_type.metadata_type_relations.create(
|
||||
metadata_type=metadata_type_2
|
||||
)
|
||||
|
||||
@@ -540,7 +548,7 @@ class MetadataTypeViewViewTestCase(DocumentTestMixin, MetadataTestsMixin, Generi
|
||||
|
||||
self.document_type.refresh_from_db()
|
||||
|
||||
self.assertEqual(self.document_type.metadata.count(), 0)
|
||||
self.assertEqual(self.document_type.metadata_type_relations.count(), 0)
|
||||
|
||||
def test_metadata_type_relationship_view_with_document_type_access(self):
|
||||
self._create_metadata_type()
|
||||
@@ -556,7 +564,7 @@ class MetadataTypeViewViewTestCase(DocumentTestMixin, MetadataTestsMixin, Generi
|
||||
|
||||
self.document_type.refresh_from_db()
|
||||
|
||||
self.assertEqual(self.document_type.metadata.count(), 0)
|
||||
self.assertEqual(self.document_type.metadata_type_relations.count(), 0)
|
||||
|
||||
def test_metadata_type_relationship_view_with_metadata_type_access(self):
|
||||
self._create_metadata_type()
|
||||
@@ -573,7 +581,7 @@ class MetadataTypeViewViewTestCase(DocumentTestMixin, MetadataTestsMixin, Generi
|
||||
|
||||
self.document_type.refresh_from_db()
|
||||
|
||||
self.assertEqual(self.document_type.metadata.count(), 0)
|
||||
self.assertEqual(self.document_type.metadata_type_relations.count(), 0)
|
||||
|
||||
def test_metadata_type_relationship_view_with_metadata_type_and_document_type_access(self):
|
||||
self._create_metadata_type()
|
||||
@@ -594,8 +602,9 @@ class MetadataTypeViewViewTestCase(DocumentTestMixin, MetadataTestsMixin, Generi
|
||||
self.document_type.refresh_from_db()
|
||||
|
||||
self.assertQuerysetEqual(
|
||||
qs=self.document_type.metadata.values('metadata_type', 'required'),
|
||||
values=[
|
||||
qs=self.document_type.metadata_type_relations.values(
|
||||
'metadata_type', 'required'
|
||||
), values=[
|
||||
{
|
||||
'metadata_type': self.metadata_type.pk,
|
||||
'required': True,
|
||||
|
||||
@@ -31,7 +31,7 @@ class DocumentUploadMetadataTestCase(MetadataTypeTestMixin, GenericDocumentViewT
|
||||
|
||||
self.document.delete()
|
||||
|
||||
self.document_type.metadata.create(
|
||||
self.document_type.metadata_type_relations.create(
|
||||
metadata_type=self.metadata_type, required=True
|
||||
)
|
||||
|
||||
|
||||
@@ -3,16 +3,14 @@ from __future__ import unicode_literals
|
||||
from django.conf.urls import url
|
||||
|
||||
from .api_views import (
|
||||
APIDocumentMetadataListView, APIDocumentMetadataView,
|
||||
APIDocumentTypeMetadataTypeListView, APIDocumentTypeMetadataTypeView,
|
||||
APIMetadataTypeListView, APIMetadataTypeView
|
||||
DocumentMetadataAPIViewSet, MetadataTypeAPIViewSet,
|
||||
MetadataTypeDocumentTypeRelationAPIViewSet
|
||||
)
|
||||
from .views import (
|
||||
DocumentMetadataAddView, DocumentMetadataEditView,
|
||||
DocumentMetadataListView, DocumentMetadataRemoveView,
|
||||
MetadataTypeCreateView, MetadataTypeDeleteView, MetadataTypeEditView,
|
||||
MetadataTypeListView, SetupDocumentTypeMetadataTypes,
|
||||
SetupMetadataTypesDocumentTypes
|
||||
DocumentTypeMetadataTypes, MetadataTypeCreateView, MetadataTypeDeleteView,
|
||||
MetadataTypesDocumentTypes, MetadataTypeEditView, MetadataTypeListView
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
@@ -35,12 +33,12 @@ urlpatterns = [
|
||||
url(
|
||||
regex=r'^metadata_types/(?P<metadata_type_id>\d+)/document_types/$',
|
||||
name='metadata_type_document_types',
|
||||
view=SetupMetadataTypesDocumentTypes.as_view()
|
||||
view=MetadataTypesDocumentTypes.as_view()
|
||||
),
|
||||
url(
|
||||
regex=r'^document_types/(?P<document_type_id>\d+)/metadata_types/$',
|
||||
name='document_type_metadata_types',
|
||||
view=SetupDocumentTypeMetadataTypes.as_view()
|
||||
view=DocumentTypeMetadataTypes.as_view()
|
||||
),
|
||||
url(
|
||||
regex=r'^documents/(?P<document_id>\d+)/edit/$',
|
||||
@@ -77,34 +75,18 @@ urlpatterns = [
|
||||
)
|
||||
]
|
||||
|
||||
api_urls = [
|
||||
url(
|
||||
regex=r'^metadata_types/$', name='metadatatype-list',
|
||||
view=APIMetadataTypeListView.as_view()
|
||||
),
|
||||
url(
|
||||
regex=r'^metadata_types/(?P<metadata_type_id>\d+)/$',
|
||||
name='metadatatype-detail',
|
||||
view=APIMetadataTypeView.as_view()
|
||||
),
|
||||
url(
|
||||
regex=r'^document_types/(?P<document_type_id>\d+)/metadata_types/$',
|
||||
name='documenttypemetadatatype-list',
|
||||
view=APIDocumentTypeMetadataTypeListView.as_view()
|
||||
),
|
||||
url(
|
||||
regex=r'^document_types/(?P<document_type_id>\d+)/metadata_types/(?P<metadata_type_id>\d+)/$',
|
||||
name='documenttypemetadatatype-detail',
|
||||
view=APIDocumentTypeMetadataTypeView.as_view()
|
||||
),
|
||||
url(
|
||||
regex=r'^documents/(?P<document_id>\d+)/metadata/$',
|
||||
name='documentmetadata-list',
|
||||
view=APIDocumentMetadataListView.as_view()
|
||||
),
|
||||
url(
|
||||
regex=r'^documents/(?P<document_id>\d+)/metadata/(?P<metadata_id>\d+)/$',
|
||||
name='documentmetadata-detail',
|
||||
view=APIDocumentMetadataView.as_view()
|
||||
)
|
||||
]
|
||||
api_router_entries = (
|
||||
{
|
||||
'prefix': r'metadata_types', 'viewset': MetadataTypeAPIViewSet,
|
||||
'basename': 'metadata_type'
|
||||
},
|
||||
{
|
||||
'prefix': r'metadata_types/(?P<metadata_type_id>[^/.]+)/document_type_relations',
|
||||
'viewset': MetadataTypeDocumentTypeRelationAPIViewSet,
|
||||
'basename': 'metadata_type-document_type_relation'
|
||||
},
|
||||
{
|
||||
'prefix': r'documents/(?P<document_id>[^/.]+)/metadata',
|
||||
'viewset': DocumentMetadataAPIViewSet, 'basename': 'document-metadata'
|
||||
}
|
||||
)
|
||||
|
||||
@@ -564,7 +564,7 @@ class MetadataTypeListView(SingleObjectListView):
|
||||
return MetadataType.objects.all()
|
||||
|
||||
|
||||
class SetupDocumentTypeMetadataTypes(ExternalObjectMixin, FormView):
|
||||
class DocumentTypeMetadataTypes(ExternalObjectMixin, FormView):
|
||||
external_object_class = DocumentType
|
||||
external_object_permission = permission_metadata_type_edit
|
||||
external_object_pk_url_kwarg = 'document_type_id'
|
||||
@@ -590,7 +590,7 @@ class SetupDocumentTypeMetadataTypes(ExternalObjectMixin, FormView):
|
||||
)
|
||||
|
||||
return super(
|
||||
SetupDocumentTypeMetadataTypes, self
|
||||
DocumentTypeMetadataTypes, self
|
||||
).form_valid(form=form)
|
||||
|
||||
def get_extra_context(self):
|
||||
@@ -640,7 +640,7 @@ class SetupDocumentTypeMetadataTypes(ExternalObjectMixin, FormView):
|
||||
return reverse(viewname='documents:document_type_list')
|
||||
|
||||
|
||||
class SetupMetadataTypesDocumentTypes(SetupDocumentTypeMetadataTypes):
|
||||
class MetadataTypesDocumentTypes(DocumentTypeMetadataTypes):
|
||||
external_object_class = MetadataType
|
||||
external_object_permission = permission_metadata_type_edit
|
||||
external_object_pk_url_kwarg = 'metadata_type_id'
|
||||
@@ -651,10 +651,10 @@ class SetupMetadataTypesDocumentTypes(SetupDocumentTypeMetadataTypes):
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
'form_display_mode_table': True,
|
||||
'object': self.get_object(),
|
||||
'object': self.external_object,
|
||||
'title': _(
|
||||
'Document types for metadata type: %s'
|
||||
) % self.get_object()
|
||||
) % self.external_object,
|
||||
}
|
||||
|
||||
def get_initial(self):
|
||||
|
||||
@@ -3,9 +3,23 @@ from __future__ import absolute_import, unicode_literals
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.generics import get_object_or_404
|
||||
from rest_framework.settings import api_settings
|
||||
|
||||
from mayan.apps.acls.models import AccessControlList
|
||||
from mayan.apps.common.mixins import ExternalObjectMixin
|
||||
|
||||
|
||||
class ExternalObjectAPIViewSetMixin(ExternalObjectMixin):
|
||||
"""Override get_external_object to use REST API get_object_or_404"""
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(ExternalObjectMixin, self).dispatch(*args, **kwargs)
|
||||
|
||||
def get_external_object(self):
|
||||
return get_object_or_404(
|
||||
queryset=self.get_external_object_queryset_filtered(),
|
||||
**self.get_pk_url_kwargs()
|
||||
)
|
||||
|
||||
|
||||
class ExternalObjectListSerializerMixin(object):
|
||||
@@ -127,6 +141,7 @@ class ExternalObjectSerializerMixin(object):
|
||||
external_object_permission
|
||||
external_object_queryset
|
||||
external_object_pk_field
|
||||
external_object_pk_type
|
||||
The source queryset can also be provided overriding the
|
||||
.get_external_object_queryset() method.
|
||||
"""
|
||||
@@ -157,7 +172,19 @@ class ExternalObjectSerializerMixin(object):
|
||||
else:
|
||||
pk_field_value = None
|
||||
|
||||
pk_type = self.get_external_object_option('pk_type')
|
||||
|
||||
if pk_field_value:
|
||||
if pk_type:
|
||||
try:
|
||||
pk_field_value = pk_type(pk_field_value)
|
||||
except Exception as exception:
|
||||
raise ValidationError(
|
||||
{
|
||||
pk_field: [exception]
|
||||
}, code='invalid'
|
||||
)
|
||||
|
||||
try:
|
||||
return queryset.get(pk=pk_field_value)
|
||||
except Exception as exception:
|
||||
|
||||
@@ -2,7 +2,7 @@ from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from django.core.exceptions import PermissionDenied
|
||||
|
||||
from rest_framework.permissions import BasePermission, IsAuthenticated
|
||||
from rest_framework.permissions import BasePermission
|
||||
|
||||
from mayan.apps.permissions import Permission
|
||||
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from rest_framework import serializers
|
||||
from rest_framework.generics import get_object_or_404
|
||||
from rest_framework.reverse import reverse
|
||||
|
||||
|
||||
class LazyExtraFieldsSerializerMixin(object):
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from rest_framework import viewsets
|
||||
from rest_framework.settings import api_settings
|
||||
from rest_framework import mixins, viewsets
|
||||
|
||||
from .filters import MayanViewSetObjectPermissionsFilter
|
||||
from .mixins import SuccessHeadersMixin
|
||||
@@ -26,3 +25,13 @@ class MayanAPIReadOnlyModelViewSet(SuccessHeadersMixin, viewsets.ReadOnlyModelVi
|
||||
class MayanAPIViewSet(SuccessHeadersMixin, viewsets.GenericViewSet):
|
||||
filter_backends = (MayanViewSetObjectPermissionsFilter,)
|
||||
permission_classes = (MayanViewSetPermission,)
|
||||
|
||||
|
||||
class MayanRetrieveUpdateAPIViewSet(SuccessHeadersMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, viewsets.GenericViewSet):
|
||||
filter_backends = (MayanViewSetObjectPermissionsFilter,)
|
||||
permission_classes = (MayanViewSetPermission,)
|
||||
|
||||
|
||||
class MayanRetrieveUpdateDestroyAPIViewSet(mixins.DestroyModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, viewsets.GenericViewSet):
|
||||
filter_backends = (MayanViewSetObjectPermissionsFilter,)
|
||||
permission_classes = (MayanViewSetPermission,)
|
||||
|
||||
Reference in New Issue
Block a user