diff --git a/apps/document_indexing/__init__.py b/apps/document_indexing/__init__.py index 44021889d7..327f834acb 100644 --- a/apps/document_indexing/__init__.py +++ b/apps/document_indexing/__init__.py @@ -34,6 +34,7 @@ index_setup_create = {'text': _(u'create index'), 'view': 'index_setup_create', index_setup_edit = {'text': _(u'edit'), 'view': 'index_setup_edit', 'args': 'index.pk', 'famfam': 'tab_edit', 'permissions': [PERMISSION_DOCUMENT_INDEXING_EDIT]} index_setup_delete = {'text': _(u'delete'), 'view': 'index_setup_delete', 'args': 'index.pk', 'famfam': 'tab_delete', 'permissions': [PERMISSION_DOCUMENT_INDEXING_DELETE]} index_setup_view = {'text': _(u'tree template'), 'view': 'index_setup_view', 'args': 'index.pk', 'famfam': 'textfield', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]} +index_setup_document_types = {'text': _(u'document types'), 'view': 'index_setup_document_types', 'args': 'index.pk', 'famfam': 'layout', 'permissions': [PERMISSION_DOCUMENT_INDEXING_EDIT]} template_node_create = {'text': _(u'new child node'), 'view': 'template_node_create', 'args': 'node.pk', 'famfam': 'textfield_add', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]} template_node_edit = {'text': _(u'edit'), 'view': 'template_node_edit', 'args': 'node.pk', 'famfam': 'textfield', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP], 'conditional_disable': is_root_node} @@ -60,6 +61,6 @@ register_setup(index_setup) register_links([Index, 'index_setup_list', 'index_setup_create', 'template_node_edit', 'template_node_delete'], [index_setup_list, index_setup_create], menu_name='secondary_menu') -register_links(Index, [index_setup_edit, index_setup_delete, index_setup_view]) +register_links(Index, [index_setup_edit, index_setup_document_types, index_setup_delete, index_setup_view]) register_links(IndexTemplateNode, [template_node_create, template_node_edit, template_node_delete]) diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py index 1f0aa3287a..f5469773b9 100644 --- a/apps/document_indexing/api.py +++ b/apps/document_indexing/api.py @@ -1,5 +1,6 @@ from __future__ import absolute_import +from django.db.models import Q from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext from django.template.defaultfilters import slugify @@ -33,7 +34,8 @@ def update_indexes(document): eval_dict['document'] = document eval_dict['metadata'] = MetadataClass(document_metadata_dict) - for index in Index.objects.filter(enabled=True): + # Only update indexes where the document type is found or that do not have any document type specified + for index in Index.objects.filter(Q(enabled=True) & (Q(document_types=None) | Q(document_types=document.document_type))): root_instance, created = IndexInstanceNode.objects.get_or_create(index_template_node=index.template_root, parent=None) for template_node in index.template_root.get_children(): index_warnings = cascade_eval(eval_dict, document, template_node, root_instance) diff --git a/apps/document_indexing/forms.py b/apps/document_indexing/forms.py index ae42376d6f..3def218a15 100644 --- a/apps/document_indexing/forms.py +++ b/apps/document_indexing/forms.py @@ -12,6 +12,7 @@ class IndexForm(forms.ModelForm): """ class Meta: model = Index + exclude = ('document_types',) class IndexTemplateNodeForm(forms.ModelForm): diff --git a/apps/document_indexing/migrations/0006_auto.py b/apps/document_indexing/migrations/0006_auto.py new file mode 100644 index 0000000000..4ae588b641 --- /dev/null +++ b/apps/document_indexing/migrations/0006_auto.py @@ -0,0 +1,152 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding M2M table for field document_types on 'Index' + db.create_table('document_indexing_index_document_types', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('index', models.ForeignKey(orm['document_indexing.index'], null=False)), + ('documenttype', models.ForeignKey(orm['documents.documenttype'], null=False)) + )) + db.create_unique('document_indexing_index_document_types', ['index_id', 'documenttype_id']) + + + def backwards(self, orm): + # Removing M2M table for field document_types on 'Index' + db.delete_table('document_indexing_index_document_types') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'document_indexing.documentrenamecount': { + 'Meta': {'object_name': 'DocumentRenameCount'}, + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'index_instance_node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['document_indexing.IndexInstanceNode']"}), + 'suffix': ('django.db.models.fields.PositiveIntegerField', [], {'blank': 'True'}) + }, + 'document_indexing.index': { + 'Meta': {'object_name': 'Index'}, + 'document_types': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['documents.DocumentType']", 'symmetrical': 'False'}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}), + 'title': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}) + }, + 'document_indexing.indexinstancenode': { + 'Meta': {'object_name': 'IndexInstanceNode'}, + 'documents': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['documents.Document']", 'symmetrical': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'index_template_node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['document_indexing.IndexTemplateNode']"}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'index_instance_node'", 'null': 'True', 'to': "orm['document_indexing.IndexInstanceNode']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'value': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}) + }, + 'document_indexing.indextemplatenode': { + 'Meta': {'object_name': 'IndexTemplateNode'}, + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'expression': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'index': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['document_indexing.Index']"}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'link_documents': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'index_template_node'", 'null': 'True', 'to': "orm['document_indexing.IndexTemplateNode']"}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['document_indexing'] \ No newline at end of file diff --git a/apps/document_indexing/models.py b/apps/document_indexing/models.py index ce3863ef7e..ccf9cee910 100644 --- a/apps/document_indexing/models.py +++ b/apps/document_indexing/models.py @@ -6,7 +6,7 @@ from django.utils.translation import ugettext_lazy as _ from mptt.models import MPTTModel from mptt.fields import TreeForeignKey -from documents.models import Document +from documents.models import Document, DocumentType from .conf.settings import AVAILABLE_INDEXING_FUNCTIONS @@ -17,6 +17,7 @@ class Index(models.Model): name = models.CharField(unique=True, max_length=64, verbose_name=_(u'name'), help_text=_(u'Internal name used to reference this index.')) title = models.CharField(unique=True, max_length=128, verbose_name=_(u'title'), help_text=_(u'The name that will be visible to users.')) enabled = models.BooleanField(default=True, verbose_name=_(u'enabled'), help_text=_(u'Causes this index to be visible and updated when document data changes.')) + document_types = models.ManyToManyField(DocumentType, verbose_name=_(u'document types')) @property def template_root(self): @@ -33,6 +34,12 @@ class Index(models.Model): def get_absolute_url(self): return ('index_instance_node_view', [self.instance_root.pk]) + def get_index_document_types(self): + return self.document_types.all() + + def get_document_types_not_in_index(self): + return DocumentType.objects.exclude(pk__in=self.get_index_document_types()) + def save(self, *args, **kwargs): super(Index, self).save(*args, **kwargs) index_template_node_root, created = IndexTemplateNode.objects.get_or_create(parent=None, index=self) @@ -51,7 +58,7 @@ class IndexTemplateNode(MPTTModel): link_documents = models.BooleanField(default=False, verbose_name=_(u'link documents'), help_text=_(u'Check this option to have this node act as a container for documents and not as a parent for further nodes.')) def __unicode__(self): - return self.expression if not self.link_documents else u'%s/[document]' % self.expression + return self.expression class Meta: verbose_name = _(u'index template node') diff --git a/apps/document_indexing/urls.py b/apps/document_indexing/urls.py index 099f0f3afe..1755500b18 100644 --- a/apps/document_indexing/urls.py +++ b/apps/document_indexing/urls.py @@ -6,7 +6,8 @@ urlpatterns = patterns('document_indexing.views', url(r'^setup/index/(?P\d+)/edit/$', 'index_setup_edit', (), 'index_setup_edit'), url(r'^setup/index/(?P\d+)/delete/$', 'index_setup_delete', (), 'index_setup_delete'), url(r'^setup/index/(?P\d+)/view/$', 'index_setup_view', (), 'index_setup_view'), - + url(r'^setup/index/(?P\d+)/document_types/$', 'index_setup_document_types', (), 'index_setup_document_types'), + url(r'^setup/template/node/(?P\d+)/create/child/$', 'template_node_create', (), 'template_node_create'), url(r'^setup/template/node/(?P\d+)/edit/$', 'template_node_edit', (), 'template_node_edit'), url(r'^setup/template/node/(?P\d+)/delete/$', 'template_node_delete', (), 'template_node_delete'), diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py index 5442493345..02be658278 100644 --- a/apps/document_indexing/views.py +++ b/apps/document_indexing/views.py @@ -14,7 +14,8 @@ from permissions.models import Permission from documents.permissions import PERMISSION_DOCUMENT_VIEW from documents.models import Document from documents.views import document_list -from common.utils import encapsulate +from common.utils import encapsulate, generate_choices_w_labels +from common.views import assign_remove from common.widgets import two_state_template from acls.utils import apply_default_acls from acls.models import AccessEntry @@ -166,6 +167,7 @@ def index_setup_view(request, index_pk): 'extra_columns': [ {'name': _(u'level'), 'attribute': encapsulate(lambda x: node_level(x))}, {'name': _(u'enabled'), 'attribute': encapsulate(lambda x: two_state_template(x.enabled))}, + {'name': _(u'has document links?'), 'attribute': encapsulate(lambda x: two_state_template(x.link_documents))}, ], } @@ -173,14 +175,39 @@ def index_setup_view(request, index_pk): context_instance=RequestContext(request)) +def index_setup_document_types(request, index_pk): + index = get_object_or_404(Index, pk=index_pk) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_EDIT]) + except PermissionDenied: + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_EDIT, request.user, index) + + return assign_remove( + request, + left_list=lambda: generate_choices_w_labels(index.get_document_types_not_in_index(), display_object_type=False), + right_list=lambda: generate_choices_w_labels(index.get_index_document_types(), display_object_type=False), + add_method=lambda x: index.document_types.add(x), + remove_method=lambda x: index.document_types.remove(x), + left_list_title=_(u'document types not in index: %s') % index, + right_list_title=_(u'document types for index: %s') % index, + decode_content_type=True, + extra_context={ + 'navigation_object_name': 'index', + 'index': index, + 'object_name': _(u'index'), + } + ) + + # Node views def template_node_create(request, parent_pk): parent_node = get_object_or_404(IndexTemplateNode, pk=parent_pk) try: - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_SETUP]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_EDIT]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_SETUP, request.user, parent_node.index) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_EDIT, request.user, parent_node.index) if request.method == 'POST': form = IndexTemplateNodeForm(request.POST) @@ -205,9 +232,9 @@ def template_node_edit(request, node_pk): node = get_object_or_404(IndexTemplateNode, pk=node_pk) try: - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_SETUP]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_EDIT]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_SETUP, request.user, node.index) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_EDIT, request.user, node.index) if request.method == 'POST': form = IndexTemplateNodeForm(request.POST, instance=node) @@ -236,9 +263,9 @@ def template_node_delete(request, node_pk): node = get_object_or_404(IndexTemplateNode, pk=node_pk) try: - Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_SETUP]) + Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_EDIT]) except PermissionDenied: - AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_SETUP, request.user, node.index) + AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_EDIT, request.user, node.index) post_action_redirect = reverse('index_setup_view', args=[node.index.pk])