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 ===