diff --git a/mayan/apps/document_indexing/__init__.py b/mayan/apps/document_indexing/__init__.py index 12de15ca0a..ee6d5681ba 100644 --- a/mayan/apps/document_indexing/__init__.py +++ b/mayan/apps/document_indexing/__init__.py @@ -9,6 +9,7 @@ from main.api import register_maintenance_links from metadata.models import DocumentMetadata from navigation.api import register_links, register_top_menu from project_setup.api import register_setup +from rest_api.classes import APIEndPoint from .api import update_indexes, delete_indexes from .links import (document_index_list, document_index_main_menu_link, @@ -18,6 +19,7 @@ from .links import (document_index_list, document_index_main_menu_link, rebuild_index_instances, template_node_create, template_node_delete, template_node_edit) from .models import Index, IndexTemplateNode, IndexInstanceNode +from .urls import api_urls @receiver(pre_delete, dispatch_uid='document_index_delete', sender=Document) @@ -52,3 +54,7 @@ register_links(IndexTemplateNode, [template_node_create, template_node_edit, tem register_setup(index_setup) register_top_menu('indexes', document_index_main_menu_link) + +endpoint = APIEndPoint('indexes') +endpoint.register_urls(api_urls) +endpoint.add_endpoint('indexes-list', _(u'Returns a list of all the indexes.')) diff --git a/mayan/apps/document_indexing/api.py b/mayan/apps/document_indexing/api.py index da03778f54..5ee1a00336 100644 --- a/mayan/apps/document_indexing/api.py +++ b/mayan/apps/document_indexing/api.py @@ -1,5 +1,7 @@ from __future__ import absolute_import +import logging + from django.db.models import Q from django.template.defaultfilters import slugify from django.utils.translation import ugettext @@ -15,6 +17,7 @@ from .models import Index, IndexInstanceNode, DocumentRenameCount from .settings import (AVAILABLE_INDEXING_FUNCTIONS, MAX_SUFFIX_COUNT, SLUGIFY_PATHS) +logger = logging.getLogger(__name__) if SLUGIFY_PATHS: SLUGIFY_FUNCTION = slugify else: @@ -52,7 +55,7 @@ def delete_indexes(document): warnings = [] - for index_instance in document.indexinstancenode_set.all(): + for index_instance in document.index_instance_nodes.all(): index_warnings = cascade_document_remove(document, index_instance) warnings.extend(index_warnings) @@ -85,8 +88,10 @@ def cascade_eval(eval_dict, document, template_node, parent_index_instance=None) try: result = eval(template_node.expression, eval_dict, AVAILABLE_INDEXING_FUNCTIONS) except Exception as exception: - warnings.append(_(u'Error in document indexing update expression: %(expression)s; %(exception)s') % { - 'expression': template_node.expression, 'exception': exception}) + error_message = _(u'Error in document indexing update expression: %(expression)s; %(exception)s') % { + 'expression': template_node.expression, 'exception': exception} + warnings.append(error_message) + logger.debug(error_message) else: if result: index_instance, created = IndexInstanceNode.objects.get_or_create(index_template_node=template_node, value=result, parent=parent_index_instance) @@ -109,8 +114,10 @@ def cascade_eval(eval_dict, document, template_node, parent_index_instance=None) try: fs_create_document_link(index_instance, document, suffix) except Exception as exception: - warnings.append(_(u'Error updating document index, expression: %(expression)s; %(exception)s') % { - 'expression': template_node.expression, 'exception': exception}) + error_message = _(u'Error updating document index, expression: %(expression)s; %(exception)s') % { + 'expression': template_node.expression, 'exception': exception} + warnings.append(error_message) + logger.debug(error_message) index_instance.documents.add(document) diff --git a/mayan/apps/document_indexing/api_views.py b/mayan/apps/document_indexing/api_views.py new file mode 100644 index 0000000000..8a13698760 --- /dev/null +++ b/mayan/apps/document_indexing/api_views.py @@ -0,0 +1,64 @@ +from __future__ import absolute_import + +from django.core.exceptions import PermissionDenied +from django.shortcuts import get_object_or_404 + +from rest_framework import generics + +from acls.models import AccessEntry +from documents.models import Document +from documents.permissions import PERMISSION_DOCUMENT_VIEW +from permissions.models import Permission +from rest_api.filters import MayanObjectPermissionsFilter +from rest_api.permissions import MayanPermission + +from .models import Index, IndexInstanceNode +from .permissions import (PERMISSION_DOCUMENT_INDEXING_CREATE, + PERMISSION_DOCUMENT_INDEXING_VIEW) +from .serializers import IndexSerializer + + +class APIIndexView(generics.RetrieveAPIView): + """ + Details of the selected index. + """ + serializer_class = IndexSerializer + queryset = Index.objects.all() + + permission_classes = (MayanPermission,) + mayan_object_permissions = {'GET': [PERMISSION_DOCUMENT_INDEXING_VIEW]} + + +class APIIndexListView(generics.ListCreateAPIView): + """ + Returns a list of all the defined indexes. + """ + + serializer_class = IndexSerializer + queryset = Index.objects.all() + + filter_backends = (MayanObjectPermissionsFilter,) + mayan_object_permissions = {'GET': [PERMISSION_DOCUMENT_INDEXING_VIEW]} + mayan_view_permissions = {'POST': [PERMISSION_DOCUMENT_INDEXING_CREATE]} + + +class APIIndexNodeInstanceDocumentListView(generics.ListAPIView): + """ + Returns a list of all the documents contained by a particular index node instance. + """ + + filter_backends = (MayanObjectPermissionsFilter,) + mayan_object_permissions = {'GET': [PERMISSION_DOCUMENT_VIEW]} + + def get_serializer_class(self): + from documents.serializers import DocumentSerializer + return DocumentSerializer + + def get_queryset(self): + index_node_instance = get_object_or_404(IndexInstanceNode, pk=self.kwargs['pk']) + try: + Permission.objects.check_permissions(self.request.user, [PERMISSION_DOCUMENT_INDEXING_VIEW]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_VIEW, self.request.user, index_node_instance.index) + + return index_node_instance.documents.all() diff --git a/mayan/apps/document_indexing/models.py b/mayan/apps/document_indexing/models.py index 8ac8dbb1b2..e9f315484d 100644 --- a/mayan/apps/document_indexing/models.py +++ b/mayan/apps/document_indexing/models.py @@ -24,11 +24,11 @@ class Index(models.Model): @property def template_root(self): - return self.indextemplatenode_set.get(parent=None) + return self.template_nodes.get(parent=None) @property def instance_root(self): - return self.template_root.node_instance + return self.template_root.node_instance.get() def __unicode__(self): return self.title @@ -41,6 +41,7 @@ class Index(models.Model): return DocumentType.objects.exclude(pk__in=self.document_types.all()) def save(self, *args, **kwargs): + """Automatically create the root index template node""" super(Index, self).save(*args, **kwargs) index_template_node_root, created = IndexTemplateNode.objects.get_or_create(parent=None, index=self) @@ -56,14 +57,18 @@ class Index(models.Model): except IndexInstanceNode.DoesNotExist: return 0 + @property + def node_instances(self): + return [template_node.node_instance.get() for template_node in self.template_nodes.all()] + class Meta: verbose_name = _(u'Index') verbose_name_plural = _(u'Indexes') class IndexTemplateNode(MPTTModel): - parent = TreeForeignKey('self', null=True, blank=True, related_name='index_template_node') - index = models.ForeignKey(Index, verbose_name=_(u'Index')) + parent = TreeForeignKey('self', null=True, blank=True) + index = models.ForeignKey(Index, verbose_name=_(u'Index'), related_name='template_nodes') expression = models.CharField(max_length=128, verbose_name=_(u'Indexing expression'), help_text=_(u'Enter a python string expression to be evaluated.')) # % available_indexing_functions_string) enabled = models.BooleanField(default=True, verbose_name=_(u'Enabled'), help_text=_(u'Causes this node to be visible and updated when document data changes.')) @@ -72,24 +77,23 @@ class IndexTemplateNode(MPTTModel): def __unicode__(self): return self.expression - @property - def node_instance(self): - return self.indexinstancenode_set.get() - class Meta: verbose_name = _(u'Index template node') verbose_name_plural = _(u'Indexes template nodes') class IndexInstanceNode(MPTTModel): - parent = TreeForeignKey('self', null=True, blank=True, related_name='index_instance_node') - index_template_node = models.ForeignKey(IndexTemplateNode, verbose_name=_(u'Index template node')) + parent = TreeForeignKey('self', null=True, blank=True) + index_template_node = models.ForeignKey(IndexTemplateNode, related_name='node_instance', verbose_name=_(u'Index template node')) value = models.CharField(max_length=128, blank=True, verbose_name=_(u'Value')) - documents = models.ManyToManyField(Document, verbose_name=_(u'Documents')) + documents = models.ManyToManyField(Document, related_name='index_instance_nodes', verbose_name=_(u'Documents')) def __unicode__(self): return self.value + def index(self): + return self.index_template_node.index + @models.permalink def get_absolute_url(self): return ('indexing:index_instance_node_view', [self.pk]) diff --git a/mayan/apps/document_indexing/serializers.py b/mayan/apps/document_indexing/serializers.py new file mode 100644 index 0000000000..925bdd5fba --- /dev/null +++ b/mayan/apps/document_indexing/serializers.py @@ -0,0 +1,27 @@ +from __future__ import absolute_import + +from rest_framework import serializers + +from .models import Index, IndexInstanceNode, IndexTemplateNode + + + +class IndexInstanceNodeSerializer(serializers.ModelSerializer): + documents = serializers.HyperlinkedIdentityField(view_name='index-node-documents') + + class Meta: + fields = ('id', 'parent', 'index_template_node', 'value', 'level', 'documents') + model = IndexInstanceNode + + +class IndexTemplateNodeSerializer(serializers.ModelSerializer): + class Meta: + model = IndexTemplateNode + + +class IndexSerializer(serializers.ModelSerializer): + template_nodes = IndexTemplateNodeSerializer(read_only=True, many=True) + node_instances = IndexInstanceNodeSerializer(read_only=True, many=True) + + class Meta: + model = Index diff --git a/mayan/apps/document_indexing/urls.py b/mayan/apps/document_indexing/urls.py index d4f9847553..e0eecd9de0 100644 --- a/mayan/apps/document_indexing/urls.py +++ b/mayan/apps/document_indexing/urls.py @@ -1,5 +1,8 @@ from django.conf.urls import patterns, url +from .api_views import (APIIndexView, APIIndexListView, + APIIndexNodeInstanceDocumentListView) + urlpatterns = patterns('document_indexing.views', url(r'^setup/index/list/$', 'index_setup_list', (), 'index_setup_list'), url(r'^setup/index/create/$', 'index_setup_create', (), 'index_setup_create'), @@ -18,3 +21,10 @@ urlpatterns = patterns('document_indexing.views', url(r'^rebuild/all/$', 'rebuild_index_instances', (), 'rebuild_index_instances'), url(r'^list/for/document/(?P\d+)/$', 'document_index_list', (), 'document_index_list'), ) + +api_urls = patterns('', + url(r'^index/node/(?P[0-9]+)/documents/$', APIIndexNodeInstanceDocumentListView.as_view(), name='index-node-documents'), + url(r'^indexes/(?P[0-9]+)/$', APIIndexView.as_view(), name='index-detail'), + url(r'^indexes/$', APIIndexListView.as_view(), name='index-list'), + #url(r'^document/(?P[0-9]+)/folders/$', APIDocumentFolderListView.as_view(), name='document-folder-list'), +)