diff --git a/apps/document_indexing/__init__.py b/apps/document_indexing/__init__.py
index c71a55f544..7b1b921442 100644
--- a/apps/document_indexing/__init__.py
+++ b/apps/document_indexing/__init__.py
@@ -8,17 +8,43 @@ from navigation.api import register_top_menu, register_sidebar_template, \
from main.api import register_maintenance_links
from documents.permissions import PERMISSION_DOCUMENT_VIEW
from documents.models import Document
+from project_setup.api import register_setup
-from .models import IndexInstance
+from .models import (Index, IndexTemplateNode, IndexInstanceNode)
from .permissions import (PERMISSION_DOCUMENT_INDEXING_VIEW,
- PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES)
+ PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES,
+ PERMISSION_DOCUMENT_INDEXING_SETUP,
+ PERMISSION_DOCUMENT_INDEXING_CREATE,
+ PERMISSION_DOCUMENT_INDEXING_EDIT,
+ PERMISSION_DOCUMENT_INDEXING_DELETE
+)
-index_list = {'text': _(u'index list'), 'view': 'index_instance_list', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW]}
-index_parent = {'text': _(u'go up one level'), 'view': 'index_instance_list', 'args': 'object.parent.pk', 'famfam': 'arrow_up', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW], 'dont_mark_active': True}
+def is_root_node(context):
+ return context['node'].parent is None
+
+
+def is_not_instance_root_node(context):
+ return context['object'].parent is not None
+
+
+index_setup = {'text': _(u'indexes'), 'view': 'index_setup_list', 'icon': 'tab.png', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]}
+index_setup_list = {'text': _(u'index list'), 'view': 'index_setup_list', 'famfam': 'tab', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]}
+index_setup_create = {'text': _(u'create index'), 'view': 'index_setup_create', 'famfam': 'tab_add', 'permissions': [PERMISSION_DOCUMENT_INDEXING_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]}
+
+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}
+template_node_delete = {'text': _(u'delete'), 'view': 'template_node_delete', 'args': 'node.pk', 'famfam': 'textfield_delete', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP], 'conditional_disable': is_root_node}
+
+index_list = {'text': _(u'index list'), 'view': 'index_list', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW]}
+
+index_parent = {'text': _(u'go up one level'), 'view': 'index_instance_node_view', 'args': 'object.parent.pk', 'famfam': 'arrow_up', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW], 'dont_mark_active': True, 'condition': is_not_instance_root_node}
document_index_list = {'text': _(u'indexes'), 'view': 'document_index_list', 'args': 'object.pk', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_VIEW]}
-register_top_menu('indexes', link={'text': _('indexes'), 'famfam': 'folder_page', 'view': 'index_instance_list'})
+register_top_menu('indexes', link={'text': _('indexes'), 'famfam': 'folder_page', 'view': 'index_list'})
rebuild_index_instances = {'text': _('rebuild indexes'), 'view': 'rebuild_index_instances', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES], 'description': _(u'Deletes and creates from scratch all the document indexes.')}
@@ -26,6 +52,14 @@ register_maintenance_links([rebuild_index_instances], namespace='document_indexi
register_sidebar_template(['index_instance_list'], 'indexing_help.html')
-register_links(IndexInstance, [index_parent])
+register_links(IndexInstanceNode, [index_parent])
register_links(Document, [document_index_list], menu_name='form_header')
+
+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(IndexTemplateNode, [template_node_create, template_node_edit, template_node_delete])
diff --git a/apps/document_indexing/admin.py b/apps/document_indexing/admin.py
index cfe2cd6f99..1b9c833754 100644
--- a/apps/document_indexing/admin.py
+++ b/apps/document_indexing/admin.py
@@ -1,27 +1,23 @@
+from __future__ import absolute_import
+
from django.contrib import admin
from mptt.admin import MPTTModelAdmin
-from document_indexing.models import Index, IndexInstance, \
- DocumentRenameCount
+from .models import (Index, IndexTemplateNode, IndexInstanceNode,
+ DocumentRenameCount)
-class IndexInstanceInline(admin.StackedInline):
- model = IndexInstance
- extra = 1
- classes = ('collapse-open',)
- allow_add = True
-
-
-class IndexAdmin(MPTTModelAdmin):
+class IndexTemplateNodeAdmin(MPTTModelAdmin):
list_display = ('expression', 'enabled', 'link_documents')
-class IndexInstanceAdmin(MPTTModelAdmin):
- model = IndexInstance
- list_display = ('value', 'index', 'get_document_list_display')
+class IndexInstanceNodeAdmin(MPTTModelAdmin):
+ model = IndexInstanceNode
+ list_display = ('value',)
-admin.site.register(Index, IndexAdmin)
-admin.site.register(IndexInstance, IndexInstanceAdmin)
+admin.site.register(Index)
+admin.site.register(IndexTemplateNode, IndexTemplateNodeAdmin)
+admin.site.register(IndexInstanceNode, IndexInstanceNodeAdmin)
admin.site.register(DocumentRenameCount)
diff --git a/apps/document_indexing/api.py b/apps/document_indexing/api.py
index 6b996fce17..0e68bb623b 100644
--- a/apps/document_indexing/api.py
+++ b/apps/document_indexing/api.py
@@ -3,19 +3,18 @@ from __future__ import absolute_import
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
from django.core.urlresolvers import reverse
-from django.utils.safestring import mark_safe
from django.template.defaultfilters import slugify
-from documents.models import Document
-from metadata.classes import MetadataObject
+from metadata.classes import MetadataClass
-from .models import (Index, IndexInstance, DocumentRenameCount)
+from .models import (Index, IndexTemplateNode, IndexInstanceNode,
+ DocumentRenameCount)
from .conf.settings import (AVAILABLE_INDEXING_FUNCTIONS,
MAX_SUFFIX_COUNT, SLUGIFY_PATHS)
from .filesystem import (fs_create_index_directory,
fs_create_document_link, fs_delete_document_link,
- fs_delete_index_directory, fs_delete_directory_recusive)
-from .os_specifics import assemble_suffixed_filename
+ fs_delete_index_directory, assemble_suffixed_filename)
+from .exceptions import MaxSuffixCountReached
if SLUGIFY_PATHS == False:
# Do not slugify path or filenames and extensions
@@ -24,10 +23,6 @@ else:
SLUGIFY_FUNCTION = slugify
-class MaxSuffixCountReached(Exception):
- pass
-
-
# External functions
def update_indexes(document):
"""
@@ -38,11 +33,13 @@ def update_indexes(document):
eval_dict = {}
document_metadata_dict = dict([(metadata.metadata_type.name, metadata.value) for metadata in document.documentmetadata_set.all() if metadata.value])
eval_dict['document'] = document
- eval_dict['metadata'] = MetadataObject(document_metadata_dict)
+ eval_dict['metadata'] = MetadataClass(document_metadata_dict)
- for root in Index.objects.filter(parent=None):
- index_warnings = _evaluate_index(eval_dict, document, root)
- warnings.extend(index_warnings)
+ for index in Index.objects.filter(enabled=True):
+ 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)
+ warnings.extend(index_warnings)
return warnings
@@ -53,136 +50,80 @@ def delete_indexes(document):
"""
warnings = []
- for index_instance in document.indexinstance_set.all():
- index_warnings = _remove_document_from_index_instance(document, index_instance)
+ for index_instance in document.indexinstancenode_set.all():
+ index_warnings = cascade_document_remove(document, index_instance)
warnings.extend(index_warnings)
return warnings
-def get_instance_link(index_instance=None, text=None, simple=False):
- """
- Return an HTML anchor to an index instance
- """
-
- if simple:
- # Just display the instance's value or overrided text, no
- # HTML anchor
- template = u'%(value)s'
- else:
- template = u'%(value)s'
- if index_instance:
- return template % {
- 'url': index_instance.get_absolute_url(),
- 'value': text if text else index_instance
- }
- else:
- # Root node
- return template % {
- 'url': reverse('index_instance_list'),
- 'value': ugettext(u'root')
- }
-
-
-def get_breadcrumbs(index_instance, simple=False, single_link=False, include_count=False):
- """
- Return a joined string of HTML anchors to every index instance's
- parent from the root of the tree to the index instance
- """
- result = []
- if single_link:
- # Return the entire breadcrumb path as a single HTML anchor
- simple = True
-
- result.append(get_instance_link(simple=simple))
-
- for instance in index_instance.get_ancestors():
- result.append(get_instance_link(instance, simple=simple))
-
- result.append(get_instance_link(index_instance, simple=simple))
-
- output = []
-
- if include_count:
- output.append(u'(%d)' % index_instance.documents.count())
-
- if single_link:
- # Return the entire breadcrumb path as a single HTML anchor
- output.insert(0, get_instance_link(index_instance=index_instance, text=(u' / '.join(result))))
- return mark_safe(u' '.join(output))
- else:
- output.insert(0, u' / '.join(result))
- return mark_safe(u' '.join(output))
-
-
-def do_rebuild_all_indexes():
- fs_delete_directory_recusive()
- IndexInstance.objects.all().delete()
- DocumentRenameCount.objects.all().delete()
- for document in Document.objects.all():
- update_indexes(document)
-
- return [] # Warnings - None
-
-
# Internal functions
def find_lowest_available_suffix(index_instance, document):
- # TODO: verify extension's role in query
- index_instance_documents = DocumentRenameCount.objects.filter(index_instance=index_instance)#.filter(document__file_extension=document.file_extension)
+ index_instance_documents = DocumentRenameCount.objects.filter(index_instance_node=index_instance)
files_list = []
for index_instance_document in index_instance_documents:
- files_list.append(assemble_suffixed_filename(index_instance_document.document.file.name, index_instance_document.suffix))
+ files_list.append(assemble_suffixed_filename(index_instance_document.document.file_filename, index_instance_document.suffix))
for suffix in xrange(MAX_SUFFIX_COUNT):
- if assemble_suffixed_filename(document.file.name, suffix) not in files_list:
+ if assemble_suffixed_filename(document.file_filename, suffix) not in files_list:
return suffix
raise MaxSuffixCountReached(ugettext(u'Maximum suffix (%s) count reached.') % MAX_SUFFIX_COUNT)
-def _evaluate_index(eval_dict, document, node, parent_index_instance=None):
+def cascade_eval(eval_dict, document, template_node, parent_index_instance=None):
"""
Evaluate an enabled index expression and update or create all the
related index instances also recursively calling itself to evaluate
all the index's children
"""
warnings = []
- if node.enabled:
+ if template_node.enabled:
try:
- result = eval(node.expression, eval_dict, AVAILABLE_INDEXING_FUNCTIONS)
+ result = eval(template_node.expression, eval_dict, AVAILABLE_INDEXING_FUNCTIONS)
+ except (NameError, AttributeError), exc:
+ warnings.append(_(u'Error in document indexing update expression: %(expression)s; %(exception)s') % {
+ 'expression': template_node.expression, 'exception': exc})
+ else:
if result:
- index_instance, created = IndexInstance.objects.get_or_create(index=node, value=result, parent=parent_index_instance)
+ index_instance, created = IndexInstanceNode.objects.get_or_create(index_template_node=template_node)
+ index_instance.value = result
+ index_instance.parent = parent_index_instance
+ index_instance.save()
#if created:
- fs_create_index_directory(index_instance)
- if node.link_documents:
+ try:
+ fs_create_index_directory(index_instance)
+ except Exception, exc:
+ warnings.append(_(u'Error updating document index, expression: %(expression)s; %(exception)s') % {
+ 'expression': template_node.expression, 'exception': exc})
+
+ if template_node.link_documents:
suffix = find_lowest_available_suffix(index_instance, document)
document_count = DocumentRenameCount(
- index_instance=index_instance,
+ index_instance_node=index_instance,
document=document,
suffix=suffix
)
document_count.save()
- fs_create_document_link(index_instance, document, suffix)
+ try:
+ fs_create_document_link(index_instance, document, suffix)
+ except Exception, exc:
+ warnings.append(_(u'Error updating document index, expression: %(expression)s; %(exception)s') % {
+ 'expression': template_node.expression, 'exception': exc})
+
index_instance.documents.add(document)
- for children in node.get_children():
- children_warnings = _evaluate_index(
- eval_dict, document, children, index_instance
+ for child in template_node.get_children():
+ children_warnings = cascade_eval(
+ eval_dict, document, child, index_instance
)
warnings.extend(children_warnings)
- except (NameError, AttributeError), exc:
- warnings.append(_(u'Error in document indexing update expression: %(expression)s; %(exception)s') % {
- 'expression': node.expression, 'exception': exc})
- except Exception, exc:
- warnings.append(_(u'Error updating document index, expression: %(expression)s; %(exception)s') % {
- 'expression': node.expression, 'exception': exc})
-
return warnings
-def _remove_document_from_index_instance(document, index_instance):
+def cascade_document_remove(document, index_instance):
"""
Delete a documents reference from an index instance and call itself
recusively deleting documents and empty index instances up to the
@@ -190,7 +131,7 @@ def _remove_document_from_index_instance(document, index_instance):
"""
warnings = []
try:
- document_rename_count = DocumentRenameCount.objects.get(index_instance=index_instance, document=document)
+ document_rename_count = DocumentRenameCount.objects.get(index_instance_node=index_instance, document=document)
fs_delete_document_link(index_instance, document, document_rename_count.suffix)
document_rename_count.delete()
index_instance.documents.remove(document)
@@ -200,7 +141,7 @@ def _remove_document_from_index_instance(document, index_instance):
parent = index_instance.parent
fs_delete_index_directory(index_instance)
index_instance.delete()
- parent_warnings = _remove_document_from_index_instance(
+ parent_warnings = cascade_document_remove(
document, parent
)
warnings.extend(parent_warnings)
diff --git a/apps/document_indexing/conf/settings.py b/apps/document_indexing/conf/settings.py
index b313035a8d..beb66ca3dd 100644
--- a/apps/document_indexing/conf/settings.py
+++ b/apps/document_indexing/conf/settings.py
@@ -1,5 +1,7 @@
"""Configuration options for the document_indexing app"""
+from django.utils.translation import ugettext_lazy as _
+
from common.utils import proper_name
from smart_settings.api import register_settings
@@ -17,7 +19,6 @@ register_settings(
# Filesystem serving
{'name': u'SLUGIFY_PATHS', 'global_name': u'DOCUMENT_INDEXING_FILESYSTEM_SLUGIFY_PATHS', 'default': False},
{'name': u'MAX_SUFFIX_COUNT', 'global_name': u'DOCUMENT_INDEXING_FILESYSTEM_MAX_SUFFIX_COUNT', 'default': 1000},
- {'name': u'FILESERVING_PATH', 'global_name': u'DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_PATH', 'default': u'/tmp/mayan/documents', 'exists': True},
- {'name': u'FILESERVING_ENABLE', 'global_name': u'DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_ENABLE', 'default': True}
+ {'name': u'FILESYSTEM_SERVING', 'global_name': u'DOCUMENT_INDEXING_FILESYSTEM_SERVING', 'default': {}, 'description': _(u'A dictionary that maps the index name and where on the filesystem that index will be mirrored.')}
]
)
diff --git a/apps/document_indexing/exceptions.py b/apps/document_indexing/exceptions.py
new file mode 100644
index 0000000000..9e095fae11
--- /dev/null
+++ b/apps/document_indexing/exceptions.py
@@ -0,0 +1,6 @@
+class MaxSuffixCountReached(Exception):
+ """
+ Raised when there are too many documents with the same filename in the
+ same node/directory
+ """
+ pass
diff --git a/apps/document_indexing/filesystem.py b/apps/document_indexing/filesystem.py
index 7c732007cc..b29f63fb74 100644
--- a/apps/document_indexing/filesystem.py
+++ b/apps/document_indexing/filesystem.py
@@ -5,9 +5,24 @@ import os
from django.utils.translation import ugettext_lazy as _
-from .os_specifics import (assemble_suffixed_filename,
- assemble_path_from_list)
-from .conf.settings import (FILESERVING_ENABLE, FILESERVING_PATH)
+from .conf.settings import (FILESYSTEM_SERVING, SUFFIX_SEPARATOR)
+
+
+def assemble_suffixed_filename(filename, suffix=0):
+ """
+ Split document filename, to attach suffix to the name part then
+ re attacht the extension
+ """
+
+ if suffix:
+ name, extension = os.path.splitext(filename)
+ return SUFFIX_SEPARATOR.join([name, unicode(suffix), os.extsep, extension])
+ else:
+ return filename
+
+
+def assemble_path_from_list(directory_list):
+ return os.sep.join(directory_list)
def get_instance_path(index_instance):
@@ -25,8 +40,8 @@ def get_instance_path(index_instance):
def fs_create_index_directory(index_instance):
- if FILESERVING_ENABLE:
- target_directory = assemble_path_from_list([FILESERVING_PATH, get_instance_path(index_instance)])
+ if index_instance.index_template_node.index.name in FILESYSTEM_SERVING:
+ target_directory = assemble_path_from_list([FILESYSTEM_SERVING[index_instance.index_template_node.index.name], get_instance_path(index_instance)])
try:
os.mkdir(target_directory)
except OSError, exc:
@@ -37,9 +52,9 @@ def fs_create_index_directory(index_instance):
def fs_create_document_link(index_instance, document, suffix=0):
- if FILESERVING_ENABLE:
- filename = assemble_suffixed_filename(document.file.name, suffix)
- filepath = assemble_path_from_list([FILESERVING_PATH, get_instance_path(index_instance), filename])
+ if index_instance.index_template_node.index.name in FILESYSTEM_SERVING:
+ filename = assemble_suffixed_filename(document.file_filename, suffix)
+ filepath = assemble_path_from_list([FILESYSTEM_SERVING[index_instance.index_template_node.index.name], get_instance_path(index_instance), filename])
try:
os.symlink(document.file.path, filepath)
@@ -57,9 +72,9 @@ def fs_create_document_link(index_instance, document, suffix=0):
def fs_delete_document_link(index_instance, document, suffix=0):
- if FILESERVING_ENABLE:
- filename = assemble_suffixed_filename(document.file.name, suffix)
- filepath = assemble_path_from_list([FILESERVING_PATH, get_instance_path(index_instance), filename])
+ if index_instance.index_template_node.index.name in FILESYSTEM_SERVING:
+ filename = assemble_suffixed_filename(document.file_filename, suffix)
+ filepath = assemble_path_from_list([FILESYSTEM_SERVING[index_instance.index_template_node.index.name], get_instance_path(index_instance), filename])
try:
os.unlink(filepath)
@@ -70,8 +85,8 @@ def fs_delete_document_link(index_instance, document, suffix=0):
def fs_delete_index_directory(index_instance):
- if FILESERVING_ENABLE:
- target_directory = assemble_path_from_list([FILESERVING_PATH, get_instance_path(index_instance)])
+ if index_instance.index_template_node.index.name in FILESYSTEM_SERVING:
+ target_directory = assemble_path_from_list([FILESYSTEM_SERVING[index_instance.index_template_node.index.name], get_instance_path(index_instance)])
try:
os.removedirs(target_directory)
except OSError, exc:
@@ -81,8 +96,9 @@ def fs_delete_index_directory(index_instance):
raise Exception(_(u'Unable to delete indexing directory; %s') % exc)
-def fs_delete_directory_recusive(path=FILESERVING_PATH):
- if FILESERVING_ENABLE:
+def fs_delete_directory_recusive(index):
+ if index.name in FILESYSTEM_SERVING:
+ path = FILESYSTEM_SERVING[index.name]
for dirpath, dirnames, filenames in os.walk(path, topdown=False):
for filename in filenames:
os.unlink(os.path.join(dirpath, filename))
diff --git a/apps/document_indexing/forms.py b/apps/document_indexing/forms.py
new file mode 100644
index 0000000000..ae42376d6f
--- /dev/null
+++ b/apps/document_indexing/forms.py
@@ -0,0 +1,27 @@
+from __future__ import absolute_import
+
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+
+from .models import Index, IndexTemplateNode
+
+
+class IndexForm(forms.ModelForm):
+ """
+ A standard model form to allow users to create a new index
+ """
+ class Meta:
+ model = Index
+
+
+class IndexTemplateNodeForm(forms.ModelForm):
+ """
+ A standard model form to allow users to create a new index template node
+ """
+ def __init__(self, *args, **kwargs):
+ super(IndexTemplateNodeForm, self).__init__(*args, **kwargs)
+ self.fields['index'].widget = forms.widgets.HiddenInput()
+ self.fields['parent'].widget = forms.widgets.HiddenInput()
+
+ class Meta:
+ model = IndexTemplateNode
diff --git a/apps/document_indexing/migrations/0001_initial.py b/apps/document_indexing/migrations/0001_initial.py
new file mode 100644
index 0000000000..40847032c5
--- /dev/null
+++ b/apps/document_indexing/migrations/0001_initial.py
@@ -0,0 +1,189 @@
+# encoding: 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 model 'Index'
+ db.create_table('document_indexing_index', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('parent', self.gf('mptt.fields.TreeForeignKey')(blank=True, related_name='index_meta_class', null=True, to=orm['document_indexing.Index'])),
+ ('expression', self.gf('django.db.models.fields.CharField')(max_length=128)),
+ ('enabled', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('link_documents', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ('lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ))
+ db.send_create_signal('document_indexing', ['Index'])
+
+ # Adding model 'IndexInstance'
+ db.create_table('document_indexing_indexinstance', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('parent', self.gf('mptt.fields.TreeForeignKey')(blank=True, related_name='index_meta_instance', null=True, to=orm['document_indexing.IndexInstance'])),
+ ('index', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['document_indexing.Index'])),
+ ('value', self.gf('django.db.models.fields.CharField')(max_length=128, blank=True)),
+ ('lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ))
+ db.send_create_signal('document_indexing', ['IndexInstance'])
+
+ # Adding M2M table for field documents on 'IndexInstance'
+ db.create_table('document_indexing_indexinstance_documents', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('indexinstance', models.ForeignKey(orm['document_indexing.indexinstance'], null=False)),
+ ('document', models.ForeignKey(orm['documents.document'], null=False))
+ ))
+ db.create_unique('document_indexing_indexinstance_documents', ['indexinstance_id', 'document_id'])
+
+ # Adding model 'DocumentRenameCount'
+ db.create_table('document_indexing_documentrenamecount', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('index_instance', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['document_indexing.IndexInstance'])),
+ ('document', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.Document'])),
+ ('suffix', self.gf('django.db.models.fields.PositiveIntegerField')(blank=True)),
+ ))
+ db.send_create_signal('document_indexing', ['DocumentRenameCount'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'Index'
+ db.delete_table('document_indexing_index')
+
+ # Deleting model 'IndexInstance'
+ db.delete_table('document_indexing_indexinstance')
+
+ # Removing M2M table for field documents on 'IndexInstance'
+ db.delete_table('document_indexing_indexinstance_documents')
+
+ # Deleting model 'DocumentRenameCount'
+ db.delete_table('document_indexing_documentrenamecount')
+
+
+ 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': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['document_indexing.IndexInstance']"}),
+ 'suffix': ('django.db.models.fields.PositiveIntegerField', [], {'blank': 'True'})
+ },
+ 'document_indexing.index': {
+ 'Meta': {'object_name': 'Index'},
+ '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'}),
+ '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_meta_class'", 'null': 'True', 'to': "orm['document_indexing.Index']"}),
+ 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+ 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
+ },
+ 'document_indexing.indexinstance': {
+ 'Meta': {'object_name': 'IndexInstance'},
+ 'documents': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['documents.Document']", 'symmetrical': 'False'}),
+ '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'}),
+ 'parent': ('mptt.fields.TreeForeignKey', [], {'blank': 'True', 'related_name': "'index_meta_instance'", 'null': 'True', 'to': "orm['document_indexing.IndexInstance']"}),
+ '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'})
+ },
+ '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', 'db_index': 'True'})
+ },
+ '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']
diff --git a/apps/document_indexing/migrations/0002_auto__del_documentrenamecount__del_indexinstance__del_index.py b/apps/document_indexing/migrations/0002_auto__del_documentrenamecount__del_indexinstance__del_index.py
new file mode 100644
index 0000000000..5ec49448dd
--- /dev/null
+++ b/apps/document_indexing/migrations/0002_auto__del_documentrenamecount__del_indexinstance__del_index.py
@@ -0,0 +1,75 @@
+# encoding: 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):
+
+ # Deleting model 'DocumentRenameCount'
+ db.delete_table('document_indexing_documentrenamecount')
+
+ # Deleting model 'IndexInstance'
+ db.delete_table('document_indexing_indexinstance')
+
+ # Removing M2M table for field documents on 'IndexInstance'
+ db.delete_table('document_indexing_indexinstance_documents')
+
+ # Deleting model 'Index'
+ db.delete_table('document_indexing_index')
+
+
+ def backwards(self, orm):
+
+ # Adding model 'DocumentRenameCount'
+ db.create_table('document_indexing_documentrenamecount', (
+ ('suffix', self.gf('django.db.models.fields.PositiveIntegerField')(blank=True)),
+ ('index_instance', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['document_indexing.IndexInstance'])),
+ ('document', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.Document'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('document_indexing', ['DocumentRenameCount'])
+
+ # Adding model 'IndexInstance'
+ db.create_table('document_indexing_indexinstance', (
+ ('index', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['document_indexing.Index'])),
+ ('parent', self.gf('mptt.fields.TreeForeignKey')(related_name='index_meta_instance', null=True, to=orm['document_indexing.IndexInstance'], blank=True)),
+ ('level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('value', self.gf('django.db.models.fields.CharField')(max_length=128, blank=True)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('document_indexing', ['IndexInstance'])
+
+ # Adding M2M table for field documents on 'IndexInstance'
+ db.create_table('document_indexing_indexinstance_documents', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('indexinstance', models.ForeignKey(orm['document_indexing.indexinstance'], null=False)),
+ ('document', models.ForeignKey(orm['documents.document'], null=False))
+ ))
+ db.create_unique('document_indexing_indexinstance_documents', ['indexinstance_id', 'document_id'])
+
+ # Adding model 'Index'
+ db.create_table('document_indexing_index', (
+ ('lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('parent', self.gf('mptt.fields.TreeForeignKey')(related_name='index_meta_class', null=True, to=orm['document_indexing.Index'], blank=True)),
+ ('level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('link_documents', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ('expression', self.gf('django.db.models.fields.CharField')(max_length=128)),
+ ('tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('enabled', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ))
+ db.send_create_signal('document_indexing', ['Index'])
+
+
+ models = {
+
+ }
+
+ complete_apps = ['document_indexing']
diff --git a/apps/document_indexing/migrations/0003_auto__add_indextemplatenode__add_indexinstancenode__add_index.py b/apps/document_indexing/migrations/0003_auto__add_indextemplatenode__add_indexinstancenode__add_index.py
new file mode 100644
index 0000000000..6d488c2c34
--- /dev/null
+++ b/apps/document_indexing/migrations/0003_auto__add_indextemplatenode__add_indexinstancenode__add_index.py
@@ -0,0 +1,191 @@
+# encoding: 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 model 'IndexTemplateNode'
+ db.create_table('document_indexing_indextemplatenode', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('parent', self.gf('mptt.fields.TreeForeignKey')(blank=True, related_name='index_template_node', null=True, to=orm['document_indexing.IndexTemplateNode'])),
+ ('index', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['document_indexing.Index'])),
+ ('expression', self.gf('django.db.models.fields.CharField')(max_length=128)),
+ ('enabled', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('link_documents', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ('lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ))
+ db.send_create_signal('document_indexing', ['IndexTemplateNode'])
+
+ # Adding model 'IndexInstanceNode'
+ db.create_table('document_indexing_indexinstancenode', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('parent', self.gf('mptt.fields.TreeForeignKey')(blank=True, related_name='index_instance_node', null=True, to=orm['document_indexing.IndexInstanceNode'])),
+ ('index_template_node', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['document_indexing.IndexTemplateNode'])),
+ ('value', self.gf('django.db.models.fields.CharField')(max_length=128, blank=True)),
+ ('lft', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('rght', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('tree_id', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ('level', self.gf('django.db.models.fields.PositiveIntegerField')(db_index=True)),
+ ))
+ db.send_create_signal('document_indexing', ['IndexInstanceNode'])
+
+ # Adding M2M table for field documents on 'IndexInstanceNode'
+ db.create_table('document_indexing_indexinstancenode_documents', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('indexinstancenode', models.ForeignKey(orm['document_indexing.indexinstancenode'], null=False)),
+ ('document', models.ForeignKey(orm['documents.document'], null=False))
+ ))
+ db.create_unique('document_indexing_indexinstancenode_documents', ['indexinstancenode_id', 'document_id'])
+
+ # Adding model 'Index'
+ db.create_table('document_indexing_index', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=64)),
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=128)),
+ ('enabled', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ))
+ db.send_create_signal('document_indexing', ['Index'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'IndexTemplateNode'
+ db.delete_table('document_indexing_indextemplatenode')
+
+ # Deleting model 'IndexInstanceNode'
+ db.delete_table('document_indexing_indexinstancenode')
+
+ # Removing M2M table for field documents on 'IndexInstanceNode'
+ db.delete_table('document_indexing_indexinstancenode_documents')
+
+ # Deleting model 'Index'
+ db.delete_table('document_indexing_index')
+
+
+ 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.index': {
+ 'Meta': {'object_name': 'Index'},
+ 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'title': ('django.db.models.fields.CharField', [], {'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', 'db_index': 'True'})
+ },
+ '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']
diff --git a/apps/document_indexing/migrations/0004_auto__add_documentrenamecount.py b/apps/document_indexing/migrations/0004_auto__add_documentrenamecount.py
new file mode 100644
index 0000000000..1b3c59c0c5
--- /dev/null
+++ b/apps/document_indexing/migrations/0004_auto__add_documentrenamecount.py
@@ -0,0 +1,153 @@
+# encoding: 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 model 'DocumentRenameCount'
+ db.create_table('document_indexing_documentrenamecount', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('index_instance_node', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['document_indexing.IndexInstanceNode'])),
+ ('document', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.Document'])),
+ ('suffix', self.gf('django.db.models.fields.PositiveIntegerField')(blank=True)),
+ ))
+ db.send_create_signal('document_indexing', ['DocumentRenameCount'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'DocumentRenameCount'
+ db.delete_table('document_indexing_documentrenamecount')
+
+
+ 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'},
+ 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'title': ('django.db.models.fields.CharField', [], {'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', 'db_index': 'True'})
+ },
+ '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']
diff --git a/apps/document_indexing/migrations/0005_auto__add_unique_index_name__add_unique_index_title.py b/apps/document_indexing/migrations/0005_auto__add_unique_index_name__add_unique_index_title.py
new file mode 100644
index 0000000000..8593f8253a
--- /dev/null
+++ b/apps/document_indexing/migrations/0005_auto__add_unique_index_name__add_unique_index_title.py
@@ -0,0 +1,153 @@
+# encoding: 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 unique constraint on 'Index', fields ['name']
+ db.create_unique('document_indexing_index', ['name'])
+
+ # Adding unique constraint on 'Index', fields ['title']
+ db.create_unique('document_indexing_index', ['title'])
+
+
+ def backwards(self, orm):
+
+ # Removing unique constraint on 'Index', fields ['title']
+ db.delete_unique('document_indexing_index', ['title'])
+
+ # Removing unique constraint on 'Index', fields ['name']
+ db.delete_unique('document_indexing_index', ['name'])
+
+
+ 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'},
+ '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', 'db_index': 'True'})
+ },
+ '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']
diff --git a/apps/document_indexing/migrations/__init__.py b/apps/document_indexing/migrations/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/apps/document_indexing/models.py b/apps/document_indexing/models.py
index a9df3f4dc2..ce3863ef7e 100644
--- a/apps/document_indexing/models.py
+++ b/apps/document_indexing/models.py
@@ -13,24 +13,54 @@ from .conf.settings import AVAILABLE_INDEXING_FUNCTIONS
available_indexing_functions_string = (_(u'Available functions: %s') % u','.join([u'%s()' % name for name, function in AVAILABLE_INDEXING_FUNCTIONS.items()])) if AVAILABLE_INDEXING_FUNCTIONS else u''
-class Index(MPTTModel):
- parent = TreeForeignKey('self', null=True, blank=True, related_name='index_meta_class')
- 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'))
- link_documents = models.BooleanField(default=False, verbose_name=_(u'link documents'))
+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.'))
+
+ @property
+ def template_root(self):
+ return self.indextemplatenode_set.get(parent=None)
+
+ @property
+ def instance_root(self):
+ return self.template_root.indexinstancenode_set.get()
def __unicode__(self):
- return self.expression if not self.link_documents else u'%s/[document]' % self.expression
+ return self.title
+
+ @models.permalink
+ def get_absolute_url(self):
+ return ('index_instance_node_view', [self.instance_root.pk])
+
+ 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)
class Meta:
verbose_name = _(u'index')
verbose_name_plural = _(u'indexes')
-class IndexInstance(MPTTModel):
- parent = TreeForeignKey('self', null=True, blank=True, related_name='index_meta_instance')
+class IndexTemplateNode(MPTTModel):
+ parent = TreeForeignKey('self', null=True, blank=True, related_name='index_template_node')
index = models.ForeignKey(Index, verbose_name=_(u'index'))
+ 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.'))
+ 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
+
+ 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'))
value = models.CharField(max_length=128, blank=True, verbose_name=_(u'value'))
documents = models.ManyToManyField(Document, verbose_name=_(u'documents'))
@@ -39,23 +69,20 @@ class IndexInstance(MPTTModel):
@models.permalink
def get_absolute_url(self):
- return ('index_instance_list', [self.pk])
-
- def get_document_list_display(self):
- return u', '.join([d.file_filename for d in self.documents.all()])
+ return ('index_instance_node_view', [self.pk])
class Meta:
- verbose_name = _(u'index instance')
- verbose_name_plural = _(u'indexes instances')
+ verbose_name = _(u'index instance node')
+ verbose_name_plural = _(u'indexes instance nodes')
class DocumentRenameCount(models.Model):
- index_instance = models.ForeignKey(IndexInstance, verbose_name=_(u'index instance'))
+ index_instance_node = models.ForeignKey(IndexInstanceNode, verbose_name=_(u'index instance'))
document = models.ForeignKey(Document, verbose_name=_(u'document'))
suffix = models.PositiveIntegerField(blank=True, verbose_name=(u'suffix'))
def __unicode__(self):
- return u'%s - %s - %s' % (self.index_instance, self.document, self.suffix or u'0')
+ return u'%s - %s - %s' % (self.index_instance_node, self.document, self.suffix or u'0')
class Meta:
verbose_name = _(u'document rename count')
diff --git a/apps/document_indexing/os_specifics.py b/apps/document_indexing/os_specifics.py
deleted file mode 100644
index d57eae409c..0000000000
--- a/apps/document_indexing/os_specifics.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from __future__ import absolute_import
-
-import os
-
-from .conf.settings import SUFFIX_SEPARATOR
-
-
-def assemble_suffixed_filename(filename, suffix=0):
- """
- Split document filename, to attach suffix to the name part then
- re attacht the extension
- """
-
- if suffix:
- name, extension = filename.split(os.split(os.extsep))
- return SUFFIX_SEPARATOR.join([name, unicode(suffix), os.extsep, extension])
- else:
- return filename
-
-
-def assemble_path_from_list(directory_list):
- return os.sep.join(directory_list)
diff --git a/apps/document_indexing/permissions.py b/apps/document_indexing/permissions.py
index 01f1afa652..d752e158b6 100644
--- a/apps/document_indexing/permissions.py
+++ b/apps/document_indexing/permissions.py
@@ -6,5 +6,10 @@ from permissions.models import PermissionNamespace, Permission
document_indexing_namespace = PermissionNamespace('document_indexing', _(u'Indexing'))
+PERMISSION_DOCUMENT_INDEXING_SETUP = Permission.objects.register(document_indexing_namespace, 'document_index_setup', _(u'Configure document indexes'))
+PERMISSION_DOCUMENT_INDEXING_CREATE = Permission.objects.register(document_indexing_namespace, 'document_index_create', _(u'Create new document indexes'))
+PERMISSION_DOCUMENT_INDEXING_EDIT = Permission.objects.register(document_indexing_namespace, 'document_index_edit', _(u'Edit document indexes'))
+PERMISSION_DOCUMENT_INDEXING_DELETE = Permission.objects.register(document_indexing_namespace, 'document_index_delete', _(u'Delete document indexes'))
+
PERMISSION_DOCUMENT_INDEXING_VIEW = Permission.objects.register(document_indexing_namespace, 'document_index_view', _(u'View document indexes'))
PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES = Permission.objects.register(document_indexing_namespace, 'document_rebuild_indexes', _(u'Rebuild document indexes'))
diff --git a/apps/document_indexing/static/images/icons/tab.png b/apps/document_indexing/static/images/icons/tab.png
new file mode 100644
index 0000000000..0bff3c4d63
Binary files /dev/null and b/apps/document_indexing/static/images/icons/tab.png differ
diff --git a/apps/document_indexing/static/images/icons/tab_delete.png b/apps/document_indexing/static/images/icons/tab_delete.png
new file mode 100644
index 0000000000..e2aec7a214
Binary files /dev/null and b/apps/document_indexing/static/images/icons/tab_delete.png differ
diff --git a/apps/document_indexing/static/images/icons/textfield_delete.png b/apps/document_indexing/static/images/icons/textfield_delete.png
new file mode 100644
index 0000000000..1b0e5b470c
Binary files /dev/null and b/apps/document_indexing/static/images/icons/textfield_delete.png differ
diff --git a/apps/document_indexing/tools.py b/apps/document_indexing/tools.py
new file mode 100644
index 0000000000..71837b0930
--- /dev/null
+++ b/apps/document_indexing/tools.py
@@ -0,0 +1,19 @@
+from __future__ import absolute_import
+
+from documents.models import Document
+
+from .models import Index, IndexInstanceNode, DocumentRenameCount
+from .filesystem import fs_delete_directory_recusive
+from .api import update_indexes
+
+
+def do_rebuild_all_indexes():
+ for index in Index.objects.all():
+ fs_delete_directory_recusive(index)
+
+ IndexInstanceNode.objects.all().delete()
+ DocumentRenameCount.objects.all().delete()
+ for document in Document.objects.all():
+ update_indexes(document)
+
+ return [] # Warnings - None
diff --git a/apps/document_indexing/urls.py b/apps/document_indexing/urls.py
index d3337e4991..099f0f3afe 100644
--- a/apps/document_indexing/urls.py
+++ b/apps/document_indexing/urls.py
@@ -1,9 +1,19 @@
from django.conf.urls.defaults import patterns, url
urlpatterns = patterns('document_indexing.views',
- url(r'^(?P\d+)/list/$', 'index_instance_list', (), 'index_instance_list'),
- url(r'^list/$', 'index_instance_list', (), 'index_instance_list'),
- url(r'^rebuild/all/$', 'rebuild_index_instances', (), 'rebuild_index_instances'),
+ url(r'^setup/index/list/$', 'index_setup_list', (), 'index_setup_list'),
+ url(r'^setup/index/create/$', 'index_setup_create', (), 'index_setup_create'),
+ 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/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'),
+
+ url(r'^index/list/$', 'index_list', (), 'index_list'),
+ url(r'^instance/node/(?P\d+)/$', 'index_instance_node_view', (), 'index_instance_node_view'),
+
+ url(r'^rebuild/all/$', 'rebuild_index_instances', (), 'rebuild_index_instances'),
url(r'^list/for/document/(?P\d+)/$', 'document_index_list', (), 'document_index_list'),
)
diff --git a/apps/document_indexing/views.py b/apps/document_indexing/views.py
index 8d405fc3d5..d44c5d105e 100644
--- a/apps/document_indexing/views.py
+++ b/apps/document_indexing/views.py
@@ -1,3 +1,5 @@
+# -*- coding: utf-8 -*-
+
from __future__ import absolute_import
from django.utils.translation import ugettext_lazy as _
@@ -5,46 +7,319 @@ from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from django.contrib import messages
-from django.utils.safestring import mark_safe
+from django.core.urlresolvers import reverse
+from django.utils.html import conditional_escape, mark_safe
+from django.core.exceptions import PermissionDenied
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 acls.utils import apply_default_acls
+from acls.models import AccessEntry
+from .forms import IndexForm, IndexTemplateNodeForm
+from .models import (Index, IndexTemplateNode, IndexInstanceNode)
+from .tools import do_rebuild_all_indexes
+from .widgets import (index_instance_item_link, get_breadcrumbs)
from .permissions import (PERMISSION_DOCUMENT_INDEXING_VIEW,
- PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES)
-from .models import IndexInstance
-from .api import (get_breadcrumbs, get_instance_link,
- do_rebuild_all_indexes)
-from .widgets import index_instance_item_link
+ PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES,
+ PERMISSION_DOCUMENT_INDEXING_SETUP,
+ PERMISSION_DOCUMENT_INDEXING_CREATE,
+ PERMISSION_DOCUMENT_INDEXING_EDIT,
+ PERMISSION_DOCUMENT_INDEXING_DELETE
+)
-def index_instance_list(request, index_id=None):
- Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_VIEW])
+# Setup views
+def index_setup_list(request):
+ context = {
+ 'title': _(u'indexes'),
+ 'hide_object': True,
+ 'list_object_variable_name': 'index',
+ 'extra_columns': [
+ {'name': _(u'name'), 'attribute': 'name'},
+ {'name': _(u'title'), 'attribute': 'title'},
+ ]
+ }
- if index_id:
- index_instance = get_object_or_404(IndexInstance, pk=index_id)
- index_instance_list = [index for index in index_instance.get_children().order_by('value')]
- breadcrumbs = get_breadcrumbs(index_instance)
- if index_instance.documents.count():
- for document in index_instance.documents.all().order_by('file_filename'):
- index_instance_list.append(document)
+ queryset = Index.objects.all()
+
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_SETUP])
+ except PermissionDenied:
+ queryset = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_INDEXING_SETUP, request.user, queryset)
+
+ context['object_list'] = queryset
+
+ return render_to_response('generic_list.html',
+ context,
+ context_instance=RequestContext(request)
+ )
+
+
+def index_setup_create(request):
+ Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_CREATE])
+
+ if request.method == 'POST':
+ form = IndexForm(request.POST)
+ if form.is_valid():
+ index = form.save()
+ apply_default_acls(index, request.user)
+ messages.success(request, _(u'Index created successfully.'))
+ return HttpResponseRedirect(reverse('index_setup_list'))
else:
- index_instance_list = IndexInstance.objects.filter(parent=None)
- breadcrumbs = get_instance_link()
- index_instance = None
+ form = IndexForm()
+
+ return render_to_response('generic_form.html', {
+ 'title': _(u'create index'),
+ 'form': form,
+ },
+ context_instance=RequestContext(request))
+
+
+def index_setup_edit(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_CREATE, request.user, index)
+
+ if request.method == 'POST':
+ form = IndexForm(request.POST, instance=index)
+ if form.is_valid():
+ form.save()
+ messages.success(request, _(u'Index edited successfully'))
+ return HttpResponseRedirect(reverse('index_setup_list'))
+ else:
+ form = IndexForm(instance=index)
+
+ return render_to_response('generic_form.html', {
+ 'title': _(u'edit index: %s') % index,
+ 'form': form,
+ 'index': index,
+ 'object_name': _(u'index'),
+ 'navigation_object_name': 'index',
+ },
+ context_instance=RequestContext(request))
+
+
+def index_setup_delete(request, index_pk):
+ index = get_object_or_404(Index, pk=index_pk)
+
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_DELETE])
+ except PermissionDenied:
+ AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_DELETE, request.user, index)
+
+ post_action_redirect = reverse('index_setup_list')
+
+ previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/')))
+ next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', '/')))
+
+ if request.method == 'POST':
+ try:
+ index.delete()
+ messages.success(request, _(u'Index: %s deleted successfully.') % index)
+ except Exception, e:
+ messages.error(request, _(u'Index: %(index)s delete error: %(error)s') % {
+ 'index': index, 'error': e})
+
+ return HttpResponseRedirect(next)
+
+ context = {
+ 'index': index,
+ 'object_name': _(u'index'),
+ 'navigation_object_name': 'index',
+ 'delete_view': True,
+ 'previous': previous,
+ 'next': next,
+ 'title': _(u'Are you sure you with to delete the index: %s?') % index,
+ 'form_icon': u'tab_delete.png',
+ }
+
+ return render_to_response('generic_confirm.html', context,
+ context_instance=RequestContext(request))
+
+
+def index_setup_view(request, index_pk):
+ index = get_object_or_404(Index, pk=index_pk)
+
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_SETUP])
+ except PermissionDenied:
+ AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_SETUP, request.user, index)
+
+ root, created = IndexTemplateNode.objects.get_or_create(parent=None, index=index)
+ object_list = root.get_descendants(include_self=True)
+
+ context = {
+ 'object_list': object_list,
+ 'index': index,
+ 'object_name': _(u'index'),
+ 'list_object_variable_name': 'node',
+ 'navigation_object_name': 'index',
+ 'title': _(u'tree template nodes for index: %s') % index,
+ 'hide_object': True,
+ 'extra_columns': [
+ {'name': _(u'level'), 'attribute': encapsulate(lambda x: u''.join([mark_safe(conditional_escape(u'--') * (getattr(x, x._mptt_meta.level_attr) - 0)), unicode(x if x.parent else 'root') ] ))},
+ ],
+ }
+
+ return render_to_response('generic_list.html', context,
+ context_instance=RequestContext(request))
+
+
+# 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])
+ except PermissionDenied:
+ AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_SETUP, request.user, parent_node.index)
+
+ if request.method == 'POST':
+ form = IndexTemplateNodeForm(request.POST)
+ if form.is_valid():
+ node = form.save()
+ messages.success(request, _(u'Index template node created successfully.'))
+ return HttpResponseRedirect(reverse('index_setup_view', args=[node.index.pk]))
+ else:
+ form = IndexTemplateNodeForm(initial={'index': parent_node.index, 'parent': parent_node})
+
+ return render_to_response('generic_form.html', {
+ 'title': _(u'create child node'),
+ 'form': form,
+ 'index': parent_node.index,
+ 'object_name': _(u'index'),
+ 'navigation_object_name': 'index',
+ },
+ context_instance=RequestContext(request))
+
+
+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])
+ except PermissionDenied:
+ AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_SETUP, request.user, node.index)
+
+ if request.method == 'POST':
+ form = IndexTemplateNodeForm(request.POST, instance=node)
+ if form.is_valid():
+ form.save()
+ messages.success(request, _(u'Index template node edited successfully'))
+ return HttpResponseRedirect(reverse('index_setup_view', args=[node.index.pk]))
+ else:
+ form = IndexTemplateNodeForm(instance=node)
+
+ return render_to_response('generic_form.html', {
+ 'title': _(u'edit index template node: %s') % node,
+ 'form': form,
+ 'index': node.index,
+ 'node': node,
+
+ 'navigation_object_list': [
+ {'object': 'index', 'name': _(u'index')},
+ {'object': 'node', 'name': _(u'node')}
+ ],
+ },
+ context_instance=RequestContext(request))
+
+
+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])
+ except PermissionDenied:
+ AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_SETUP, request.user, node.index)
+
+ post_action_redirect = reverse('index_setup_view', args=[node.index.pk])
+
+ previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/')))
+ next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', '/')))
+
+ if request.method == 'POST':
+ try:
+ node.delete()
+ messages.success(request, _(u'Node: %s deleted successfully.') % node)
+ except Exception, e:
+ messages.error(request, _(u'Node: %(node)s delete error: %(error)s') % {
+ 'node': node, 'error': e})
+
+ return HttpResponseRedirect(next)
+
+ context = {
+ 'delete_view': True,
+ 'previous': previous,
+ 'next': next,
+ 'title': _(u'Are you sure you with to delete the index template node: %s?') % node,
+ 'form_icon': u'textfield_delete.png',
+ 'index': node.index,
+ 'node': node,
+
+ 'navigation_object_list': [
+ {'object': 'index', 'name': _(u'index')},
+ {'object': 'node', 'name': _(u'node')}
+ ],
+ }
+
+ return render_to_response('generic_confirm.html', context,
+ context_instance=RequestContext(request))
+
+
+def index_list(request):
+ context = {
+ 'title': _(u'indexes'),
+ #'hide_object': True,
+ #'list_object_variable_name': 'index',
+ #'extra_columns': [
+ # {'name': _(u'elements'), 'attribute': 'root'},
+ # {'name': _(u'name'), 'attribute': 'name'},
+ # {'name': _(u'title'), 'attribute': 'title'},
+ #],
+ 'overrided_object_links': [{}],
+ }
+
+ queryset = Index.objects.filter(enabled=True)
+
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_VIEW])
+ except PermissionDenied:
+ queryset = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_INDEXING_VIEW, request.user, queryset)
+
+ context['object_list'] = queryset
+
+ return render_to_response('generic_list.html',
+ context,
+ context_instance=RequestContext(request)
+ )
+
+
+def index_instance_node_view(request, index_instance_node_pk):
+ index_instance = get_object_or_404(IndexInstanceNode, pk=index_instance_node_pk)
+ index_instance_list = [index for index in index_instance.get_children().order_by('value')]
+ breadcrumbs = get_breadcrumbs(index_instance)
+
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_VIEW])
+ except PermissionDenied:
+ AccessEntry.objects.check_access(PERMISSION_DOCUMENT_INDEXING_VIEW, request.user, index_instance.index)
title = mark_safe(_(u'contents for index: %s') % breadcrumbs)
if index_instance:
- if index_instance.index.link_documents:
+ if index_instance.index_template_node.link_documents:
# Document list, use the document_list view for consistency
return document_list(
request,
title=title,
- object_list=index_instance_list,
+ object_list=index_instance.documents.all(),
extra_context={
'object': index_instance
}
@@ -54,12 +329,12 @@ def index_instance_list(request, index_id=None):
'object_list': index_instance_list,
'extra_columns_preffixed': [
{
- 'name': _(u'index'),
+ 'name': _(u'node'),
'attribute': encapsulate(lambda x: index_instance_item_link(x))
},
{
'name': _(u'items'),
- 'attribute': encapsulate(lambda x: x.documents.count() if x.index.link_documents else x.get_children().count())
+ 'attribute': encapsulate(lambda x: x.documents.count() if x.index_template_node.link_documents else x.get_children().count())
}
],
'title': title,
@@ -98,12 +373,16 @@ def rebuild_index_instances(request):
def document_index_list(request, document_id):
- Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW, PERMISSION_DOCUMENT_INDEXING_VIEW])
document = get_object_or_404(Document, pk=document_id)
-
object_list = []
- for index_instance in document.indexinstance_set.all():
+ queryset = document.indexinstancenode_set.all()
+ try:
+ Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW, PERMISSION_DOCUMENT_INDEXING_VIEW])
+ except PermissionDenied:
+ queryset = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_INDEXING_VIEW, request.user, queryset)
+
+ for index_instance in queryset:
object_list.append(get_breadcrumbs(index_instance, single_link=True, include_count=True))
return render_to_response('generic_list.html', {
diff --git a/apps/document_indexing/widgets.py b/apps/document_indexing/widgets.py
index bc25f8e0e5..4448c63e0b 100644
--- a/apps/document_indexing/widgets.py
+++ b/apps/document_indexing/widgets.py
@@ -1,14 +1,16 @@
+from __future__ import absolute_import
+
from django.utils.safestring import mark_safe
-from document_indexing.models import IndexInstance
+from .models import IndexInstanceNode
FOLDER_W_DOCUMENTS = u'folder_page'
FOLDER_ICON = u'folder'
def index_instance_item_link(index_instance_item):
- if isinstance(index_instance_item, IndexInstance):
- if index_instance_item.index.link_documents:
+ if isinstance(index_instance_item, IndexInstanceNode):
+ if index_instance_item.index_template_node.link_documents:
icon = FOLDER_W_DOCUMENTS
else:
icon = FOLDER_ICON
@@ -20,3 +22,52 @@ def index_instance_item_link(index_instance_item):
'icon_template': icon_template,
'text': index_instance_item
})
+
+
+def get_instance_link(index_instance_node, text=None, simple=False):
+ """
+ Return an HTML anchor to an index instance
+ """
+
+ if simple:
+ # Just display the instance's value or overrided text, no
+ # HTML anchor
+ template = u'%(value)s'
+ else:
+ template = u'%(value)s'
+
+ return template % {
+ 'url': index_instance_node.get_absolute_url(),
+ 'value': text if text else (index_instance_node if index_instance_node.parent else index_instance_node.index_template_node.index)
+ }
+
+
+def get_breadcrumbs(index_instance, simple=False, single_link=False, include_count=False):
+ """
+ Return a joined string of HTML anchors to every index instance's
+ parent from the root of the tree to the index instance
+ """
+ result = []
+ if single_link:
+ # Return the entire breadcrumb path as a single HTML anchor
+ simple = True
+
+ #result.append(get_instance_link(index_instance.get_root(), simple=simple))
+
+ for instance in index_instance.get_ancestors():
+ result.append(get_instance_link(instance, simple=simple))
+
+ result.append(get_instance_link(index_instance, simple=simple))
+
+ output = []
+
+ if include_count:
+ output.append(u'(%d)' % index_instance.documents.count())
+
+ if single_link:
+ # Return the entire breadcrumb path as a single HTML anchor
+ output.insert(0, get_instance_link(index_instance_node=index_instance, text=(u' / '.join(result))))
+ return mark_safe(u' '.join(output))
+ else:
+ output.insert(0, u' / '.join(result))
+ return mark_safe(u' '.join(output))
diff --git a/apps/linking/managers.py b/apps/linking/managers.py
index 4583b646ad..41d4275e15 100644
--- a/apps/linking/managers.py
+++ b/apps/linking/managers.py
@@ -3,7 +3,7 @@ from __future__ import absolute_import
from django.db import models
from django.db.models import Q
-from metadata.classes import MetadataObject
+from metadata.classes import MetadataClass
from documents.models import Document
from .literals import INCLUSION_AND, INCLUSION_OR
@@ -18,7 +18,7 @@ class SmartLinkManager(models.Manager):
metadata_dict[document_metadata.metadata_type.name] = document_metadata.value
eval_dict = {}
eval_dict['document'] = document
- eval_dict['metadata'] = MetadataObject(metadata_dict)
+ eval_dict['metadata'] = MetadataClass(metadata_dict)
if smart_link_obj:
smart_link_qs = self.model.objects.filter(Q(enabled=True) & Q(pk=smart_link_obj.pk))
diff --git a/apps/metadata/classes.py b/apps/metadata/classes.py
index b8476a744f..b370dcae21 100644
--- a/apps/metadata/classes.py
+++ b/apps/metadata/classes.py
@@ -1,7 +1,7 @@
from django.utils.translation import ugettext_lazy as _
-class MetadataObject(object):
+class MetadataClass(object):
def __init__(self, dictionary):
self.dictionary = dictionary
diff --git a/docs/releases/0.12.rst b/docs/releases/0.12.rst
index dd198d13ed..748520b87c 100644
--- a/docs/releases/0.12.rst
+++ b/docs/releases/0.12.rst
@@ -122,6 +122,19 @@ column after those is ignored.
* The ``--skip-repeated`` tells the importedr to not stop when finding
that a user already exists in the database.
+Refactored document indexing
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The document indexing functionality has been improved and moved from experimental
+stage to beta stage. Index configuration menus are now available on the
+``Setup`` menu and allows administrators to create a skeleton tree that will
+be populated with document links depending on their metadata and properties.
+This populated tree can also be mirrored on the physical filesystem and shared
+using Samba or another filesharing server giving users a structured view
+of the documents contained within **Mayan EDMS** from the ``Indexes`` tab
+or from a mirrored index shared via the network. A new configuration option
+has been added, :setting:`DOCUMENT_INDEXING_FILESYSTEM_SERVING`, which maps
+the index internal name with the physical directory where such index will be
+mirrored on disk.
Upgrading from a previous version
=================================
@@ -191,15 +204,21 @@ so write down your role permission setup before upgrading.
Bugs fixed
==========
* Issue #17, special thanks to Dave Herring for all the help including
- access to a machine suffering with the issue.
+ access to a machine suffering with the issue, and to Сергей Глита for
+ his research and eventual find of the core cause.
* Statistics fixes.
* Fixed get_image_cache_name regression in the OCR app.
Stuff removed
=============
-* Removal of the OCR_CACHE_URI configuration option.
* Support for Celery and Sentry has been drop
for now.
* Removed the 'db_index' argument from Text fields definition and
migrations as it was causing error messages for MySQL users, thanks to
Сергей Глита for reporting this one.
+* Configuration options removed:
+
+ * OCR_CACHE_URI
+ * DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_PATH - Use the newest :setting:`DOCUMENT_INDEXING_FILESYSTEM_SERVING`
+ * DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_ENABLE - Use the newest :setting:`DOCUMENT_INDEXING_FILESYSTEM_SERVING`
+
diff --git a/docs/topics/settings.rst b/docs/topics/settings.rst
index 9989752a7d..d01de8049d 100644
--- a/docs/topics/settings.rst
+++ b/docs/topics/settings.rst
@@ -297,21 +297,15 @@ DOCUMENT_INDEXING_FILESYSTEM_MAX_SUFFIX_COUNT
Default: ``1000``
-.. setting:: DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_PATH
+.. setting:: DOCUMENT_INDEXING_FILESYSTEM_SERVING
-DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_PATH
----------------------------------------------
-
-Default: ``/tmp/mayan/documents``
-
-
-.. setting:: DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_ENABLE
+DOCUMENT_INDEXING_FILESYSTEM_SERVING
+------------------------------------
+
+Default: ``{}``
+
+A dictionary that maps the index name and where on the filesystem that index will be mirrored.
-DOCUMENT_INDEXING_FILESYSTEM_FILESERVING_ENABLE
------------------------------------------------
-
-Default: ``True``
-
OCR
===