Instead of inserting the path of the apps into the Python app, the apps are now referenced by their full import path. This solves name clashes with external or native Python libraries. Example: Mayan statistics app vs. Python new statistics library. Every app reference is now prepended with 'mayan.apps'. Existing config.yml files need to be updated manually. Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
199 lines
6.6 KiB
Python
199 lines
6.6 KiB
Python
from __future__ import unicode_literals
|
|
|
|
from django.db import connection, transaction
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
from rest_framework import serializers
|
|
from rest_framework.reverse import reverse
|
|
from rest_framework.settings import api_settings
|
|
from rest_framework_recursive.fields import RecursiveField
|
|
|
|
from mayan.apps.documents.models import Document
|
|
from mayan.apps.documents.serializers import DocumentSerializer
|
|
|
|
from .models import Cabinet
|
|
|
|
|
|
class CabinetSerializer(serializers.ModelSerializer):
|
|
children = RecursiveField(
|
|
help_text=_('List of children cabinets.'), many=True, read_only=True
|
|
)
|
|
documents_count = serializers.SerializerMethodField(
|
|
help_text=_('Number of documents on this cabinet level.')
|
|
)
|
|
full_path = serializers.SerializerMethodField(
|
|
help_text=_(
|
|
'The name of this cabinet level appended to the names of its '
|
|
'ancestors.'
|
|
)
|
|
)
|
|
documents_url = serializers.HyperlinkedIdentityField(
|
|
help_text=_(
|
|
'URL of the API endpoint showing the list documents inside this '
|
|
'cabinet.'
|
|
), view_name='rest_api:cabinet-document-list'
|
|
)
|
|
parent_url = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
extra_kwargs = {
|
|
'url': {'view_name': 'rest_api:cabinet-detail'},
|
|
}
|
|
fields = (
|
|
'children', 'documents_count', 'documents_url', 'full_path', 'id',
|
|
'label', 'parent', 'parent_url', 'url'
|
|
)
|
|
model = Cabinet
|
|
|
|
def get_documents_count(self, obj):
|
|
return obj.get_document_count(user=self.context['request'].user)
|
|
|
|
def get_full_path(self, obj):
|
|
return obj.get_full_path()
|
|
|
|
def get_parent_url(self, obj):
|
|
if obj.parent:
|
|
return reverse(
|
|
'rest_api:cabinet-detail', args=(obj.parent.pk,),
|
|
format=self.context['format'],
|
|
request=self.context.get('request')
|
|
)
|
|
else:
|
|
return ''
|
|
|
|
|
|
class WritableCabinetSerializer(serializers.ModelSerializer):
|
|
documents_pk_list = serializers.CharField(
|
|
help_text=_(
|
|
'Comma separated list of document primary keys to add to this '
|
|
'cabinet.'
|
|
), required=False
|
|
)
|
|
|
|
# This is here because parent is optional in the model but the serializer
|
|
# sets it as required.
|
|
parent = serializers.PrimaryKeyRelatedField(
|
|
allow_null=True, queryset=Cabinet.objects.all(), required=False
|
|
)
|
|
|
|
class Meta:
|
|
fields = ('documents_pk_list', 'label', 'id', 'parent')
|
|
model = Cabinet
|
|
|
|
def _add_documents(self, documents_pk_list, instance):
|
|
instance.documents.add(
|
|
*Document.objects.filter(pk__in=documents_pk_list.split(','))
|
|
)
|
|
|
|
def create(self, validated_data):
|
|
documents_pk_list = validated_data.pop('documents_pk_list', '')
|
|
|
|
instance = super(WritableCabinetSerializer, self).create(validated_data)
|
|
|
|
if documents_pk_list:
|
|
self._add_documents(
|
|
documents_pk_list=documents_pk_list, instance=instance
|
|
)
|
|
|
|
return instance
|
|
|
|
def update(self, instance, validated_data):
|
|
documents_pk_list = validated_data.pop('documents_pk_list', '')
|
|
|
|
instance = super(WritableCabinetSerializer, self).update(
|
|
instance, validated_data
|
|
)
|
|
|
|
if documents_pk_list:
|
|
instance.documents.clear()
|
|
self._add_documents(
|
|
documents_pk_list=documents_pk_list, instance=instance
|
|
)
|
|
|
|
return instance
|
|
|
|
def run_validation(self, data=None):
|
|
# Copy data into a new dictionary since data is an immutable type
|
|
result = data.copy()
|
|
|
|
# Add None parent to keep validation from failing.
|
|
# This is here because parent is optional in the model but the serializer
|
|
# sets it as required.
|
|
result.setdefault('parent')
|
|
|
|
data = super(WritableCabinetSerializer, self).run_validation(result)
|
|
|
|
# Explicit validation of uniqueness of parent+label as the provided
|
|
# unique_together check in Meta is not working for all 100% cases
|
|
# when there is a FK in the unique_together tuple
|
|
# https://code.djangoproject.com/ticket/1751
|
|
with transaction.atomic():
|
|
if connection.vendor == 'oracle':
|
|
queryset = Cabinet.objects.filter(parent=data['parent'], label=data['label'])
|
|
else:
|
|
queryset = Cabinet.objects.select_for_update().filter(parent=data['parent'], label=data['label'])
|
|
|
|
if queryset.exists():
|
|
params = {
|
|
'model_name': _('Cabinet'),
|
|
'field_labels': _('Parent and Label')
|
|
}
|
|
raise serializers.ValidationError(
|
|
{
|
|
api_settings.NON_FIELD_ERRORS_KEY: [
|
|
_(
|
|
'%(model_name)s with this %(field_labels)s '
|
|
'already exists.'
|
|
) % params
|
|
],
|
|
},
|
|
)
|
|
|
|
return data
|
|
|
|
|
|
class CabinetDocumentSerializer(DocumentSerializer):
|
|
cabinet_document_url = serializers.SerializerMethodField(
|
|
help_text=_(
|
|
'API URL pointing to a document in relation to the cabinet '
|
|
'storing it. This URL is different than the canonical document '
|
|
'URL.'
|
|
)
|
|
)
|
|
|
|
class Meta(DocumentSerializer.Meta):
|
|
fields = DocumentSerializer.Meta.fields + ('cabinet_document_url',)
|
|
read_only_fields = DocumentSerializer.Meta.fields
|
|
|
|
def get_cabinet_document_url(self, instance):
|
|
return reverse(
|
|
'rest_api:cabinet-document', args=(
|
|
self.context['cabinet'].pk, instance.pk
|
|
), request=self.context['request'], format=self.context['format']
|
|
)
|
|
|
|
|
|
class NewCabinetDocumentSerializer(serializers.Serializer):
|
|
documents_pk_list = serializers.CharField(
|
|
help_text=_(
|
|
'Comma separated list of document primary keys to add to this '
|
|
'cabinet.'
|
|
)
|
|
)
|
|
|
|
def _add_documents(self, documents_pk_list, instance):
|
|
instance.documents.add(
|
|
*Document.objects.filter(pk__in=documents_pk_list.split(','))
|
|
)
|
|
|
|
def create(self, validated_data):
|
|
documents_pk_list = validated_data['documents_pk_list']
|
|
|
|
if documents_pk_list:
|
|
self._add_documents(
|
|
documents_pk_list=documents_pk_list,
|
|
instance=validated_data['cabinet']
|
|
)
|
|
|
|
return {'documents_pk_list': documents_pk_list}
|