Document indexing refactoring update

This commit is contained in:
Roberto Rosario
2012-02-02 05:01:42 -04:00
parent bbf03e3caa
commit 59f6f7f8cc
7 changed files with 114 additions and 88 deletions

View File

@@ -21,7 +21,11 @@ from .permissions import (PERMISSION_DOCUMENT_INDEXING_VIEW,
def is_root_node(context): def is_root_node(context):
return context['node'].parent==None 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 = {'text': _(u'indexes'), 'view': 'index_setup_list', 'icon': 'tab.png', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]}
@@ -36,10 +40,11 @@ template_node_edit = {'text': _(u'edit'), 'view': 'template_node_edit', 'args':
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} 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_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_list', 'args': 'object.parent.pk', 'famfam': 'arrow_up', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW], 'dont_mark_active': True}
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]} 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.')} 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.')}

View File

@@ -41,9 +41,11 @@ def update_indexes(document):
eval_dict['document'] = document eval_dict['document'] = document
eval_dict['metadata'] = MetadataObject(document_metadata_dict) eval_dict['metadata'] = MetadataObject(document_metadata_dict)
for root in Index.objects.filter(parent=None): for index in Index.objects.all():
index_warnings = _evaluate_index(eval_dict, document, root) root_instance, created = IndexInstanceNode.objects.get_or_create(index_template_node=index.template_root, parent=None)
warnings.extend(index_warnings) for template_node in index.template_root.get_children():
index_warnings = _evaluate_index(eval_dict, document, template_node, root_instance)
warnings.extend(index_warnings)
return warnings return warnings
@@ -54,14 +56,14 @@ def delete_indexes(document):
""" """
warnings = [] warnings = []
for index_instance in document.indexinstance_set.all(): for index_instance in document.indexinstancenode_set.all():
index_warnings = _remove_document_from_index_instance(document, index_instance) index_warnings = _remove_document_from_index_instance(document, index_instance)
warnings.extend(index_warnings) warnings.extend(index_warnings)
return warnings return warnings
def get_instance_link(index_instance=None, text=None, simple=False): def get_instance_link(index_instance_node=None, text=None, simple=False):
""" """
Return an HTML anchor to an index instance Return an HTML anchor to an index instance
""" """
@@ -72,15 +74,15 @@ def get_instance_link(index_instance=None, text=None, simple=False):
template = u'%(value)s' template = u'%(value)s'
else: else:
template = u'<a href="%(url)s">%(value)s</a>' template = u'<a href="%(url)s">%(value)s</a>'
if index_instance: if index_instance_node:
return template % { return template % {
'url': index_instance.get_absolute_url(), 'url': index_instance_node.get_absolute_url(),
'value': text if text else index_instance 'value': text if text else (index_instance_node if index_instance_node.parent else index_instance_node.index_template_node.index)
} }
else: else:
# Root node # Root node
return template % { return template % {
'url': reverse('index_instance_list'), 'url': '#',#reverse('index_instance_node_view', args=[index_instance_node.parent.pk]),
'value': ugettext(u'root') 'value': ugettext(u'root')
} }
@@ -95,7 +97,7 @@ def get_breadcrumbs(index_instance, simple=False, single_link=False, include_cou
# Return the entire breadcrumb path as a single HTML anchor # Return the entire breadcrumb path as a single HTML anchor
simple = True simple = True
result.append(get_instance_link(simple=simple)) #result.append(get_instance_link(index_instance.get_root(), simple=simple))
for instance in index_instance.get_ancestors(): for instance in index_instance.get_ancestors():
result.append(get_instance_link(instance, simple=simple)) result.append(get_instance_link(instance, simple=simple))
@@ -109,7 +111,7 @@ def get_breadcrumbs(index_instance, simple=False, single_link=False, include_cou
if single_link: if single_link:
# Return the entire breadcrumb path as a single HTML anchor # Return the entire breadcrumb path as a single HTML anchor
output.insert(0, get_instance_link(index_instance=index_instance, text=(u' / '.join(result)))) output.insert(0, get_instance_link(index_instance_node=index_instance, text=(u' / '.join(result))))
return mark_safe(u' '.join(output)) return mark_safe(u' '.join(output))
else: else:
output.insert(0, u' / '.join(result)) output.insert(0, u' / '.join(result))
@@ -118,8 +120,8 @@ def get_breadcrumbs(index_instance, simple=False, single_link=False, include_cou
def do_rebuild_all_indexes(): def do_rebuild_all_indexes():
fs_delete_directory_recusive() fs_delete_directory_recusive()
IndexInstance.objects.all().delete() IndexInstanceNone.objects.delete()
DocumentRenameCount.objects.all().delete() DocumentRenameCount.objects.delete()
for document in Document.objects.all(): for document in Document.objects.all():
update_indexes(document) update_indexes(document)
@@ -129,56 +131,61 @@ def do_rebuild_all_indexes():
# Internal functions # Internal functions
def find_lowest_available_suffix(index_instance, document): def find_lowest_available_suffix(index_instance, document):
# TODO: verify extension's role in query # 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)#.filter(document__file_extension=document.file_extension)
files_list = [] files_list = []
for index_instance_document in index_instance_documents: 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): 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 return suffix
raise MaxSuffixCountReached(ugettext(u'Maximum suffix (%s) count reached.') % MAX_SUFFIX_COUNT) raise MaxSuffixCountReached(ugettext(u'Maximum suffix (%s) count reached.') % MAX_SUFFIX_COUNT)
def _evaluate_index(eval_dict, document, node, parent_index_instance=None): def _evaluate_index(eval_dict, document, template_node, parent_index_instance=None):
""" """
Evaluate an enabled index expression and update or create all the Evaluate an enabled index expression and update or create all the
related index instances also recursively calling itself to evaluate related index instances also recursively calling itself to evaluate
all the index's children all the index's children
""" """
warnings = [] warnings = []
if node.enabled: if template_node.enabled:
try: try:
result = eval(node.expression, eval_dict, AVAILABLE_INDEXING_FUNCTIONS) result = eval(template_node.expression, eval_dict, AVAILABLE_INDEXING_FUNCTIONS)
if result: 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: #if created:
fs_create_index_directory(index_instance) #fs_create_index_directory(index_instance)
if node.link_documents: if template_node.link_documents:
suffix = find_lowest_available_suffix(index_instance, document) suffix = find_lowest_available_suffix(index_instance, document)
document_count = DocumentRenameCount( document_count = DocumentRenameCount(
index_instance=index_instance, index_instance_node=index_instance,
document=document, document=document,
suffix=suffix suffix=suffix
) )
document_count.save() document_count.save()
fs_create_document_link(index_instance, document, suffix) #fs_create_document_link(index_instance, document, suffix)
index_instance.documents.add(document) index_instance.documents.add(document)
for children in node.get_children(): for child in template_node.get_children():
children_warnings = _evaluate_index( children_warnings = _evaluate_index(
eval_dict, document, children, index_instance eval_dict, document, child, index_instance
) )
warnings.extend(children_warnings) warnings.extend(children_warnings)
except (NameError, AttributeError), exc: except (NameError, AttributeError), exc:
raise
warnings.append(_(u'Error in document indexing update expression: %(expression)s; %(exception)s') % { warnings.append(_(u'Error in document indexing update expression: %(expression)s; %(exception)s') % {
'expression': node.expression, 'exception': exc}) 'expression': template_node.expression, 'exception': exc})
except Exception, exc: except Exception, exc:
raise
warnings.append(_(u'Error updating document index, expression: %(expression)s; %(exception)s') % { warnings.append(_(u'Error updating document index, expression: %(expression)s; %(exception)s') % {
'expression': node.expression, 'exception': exc}) 'expression': template_node.expression, 'exception': exc})
return warnings return warnings
@@ -191,15 +198,15 @@ def _remove_document_from_index_instance(document, index_instance):
""" """
warnings = [] warnings = []
try: 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) #fs_delete_document_link(index_instance, document, document_rename_count.suffix)
document_rename_count.delete() document_rename_count.delete()
index_instance.documents.remove(document) index_instance.documents.remove(document)
if index_instance.documents.count() == 0 and index_instance.get_children().count() == 0: if index_instance.documents.count() == 0 and index_instance.get_children().count() == 0:
# if there are no more documents and no children, delete # if there are no more documents and no children, delete
# node and check parent for the same conditions # node and check parent for the same conditions
parent = index_instance.parent parent = index_instance.parent
fs_delete_index_directory(index_instance) #fs_delete_index_directory(index_instance)
index_instance.delete() index_instance.delete()
parent_warnings = _remove_document_from_index_instance( parent_warnings = _remove_document_from_index_instance(
document, parent document, parent
@@ -208,6 +215,7 @@ def _remove_document_from_index_instance(document, index_instance):
except DocumentRenameCount.DoesNotExist: except DocumentRenameCount.DoesNotExist:
return warnings return warnings
except Exception, exc: except Exception, exc:
raise
warnings.append(_(u'Unable to delete document indexing node; %s') % exc) warnings.append(_(u'Unable to delete document indexing node; %s') % exc)
return warnings return warnings

View File

@@ -18,9 +18,22 @@ class Index(models.Model):
title = models.CharField(unique=True, max_length=128, verbose_name=_(u'title')) title = models.CharField(unique=True, max_length=128, verbose_name=_(u'title'))
enabled = models.BooleanField(default=True, verbose_name=_(u'enabled')) enabled = models.BooleanField(default=True, verbose_name=_(u'enabled'))
@property
def template_root(self):
# Catch error
return self.indextemplatenode_set.get(parent=None)
@property
def instance_root(self):
return self.template_root.indexinstancenode_set.get()
def __unicode__(self): def __unicode__(self):
return self.title return self.title
@models.permalink
def get_absolute_url(self):
return ('index_instance_node_view', [self.instance_root.pk])
class Meta: class Meta:
verbose_name = _(u'index') verbose_name = _(u'index')
verbose_name_plural = _(u'indexes') verbose_name_plural = _(u'indexes')
@@ -60,7 +73,7 @@ class IndexInstanceNode(MPTTModel):
@models.permalink @models.permalink
def get_absolute_url(self): def get_absolute_url(self):
return ('index_instance_list', [self.pk]) return ('index_instance_node_view', [self.pk])
#def get_document_list_display(self): #def get_document_list_display(self):
# return u', '.join([d.file_filename for d in self.documents.all()]) # return u', '.join([d.file_filename for d in self.documents.all()])

View File

@@ -12,7 +12,7 @@ def assemble_suffixed_filename(filename, suffix=0):
""" """
if suffix: if suffix:
name, extension = filename.split(os.split(os.extsep)) name, extension = os.path.splitext(filename)
return SUFFIX_SEPARATOR.join([name, unicode(suffix), os.extsep, extension]) return SUFFIX_SEPARATOR.join([name, unicode(suffix), os.extsep, extension])
else: else:
return filename return filename

View File

@@ -11,12 +11,9 @@ urlpatterns = patterns('document_indexing.views',
url(r'^setup/template/node/(?P<node_pk>\d+)/edit/$', 'template_node_edit', (), 'template_node_edit'), url(r'^setup/template/node/(?P<node_pk>\d+)/edit/$', 'template_node_edit', (), 'template_node_edit'),
url(r'^setup/template/node/(?P<node_pk>\d+)/delete/$', 'template_node_delete', (), 'template_node_delete'), url(r'^setup/template/node/(?P<node_pk>\d+)/delete/$', 'template_node_delete', (), 'template_node_delete'),
url(r'^list/$', 'index_list', (), 'index_list'), url(r'^index/list/$', 'index_list', (), 'index_list'),
url(r'^instance/node/(?P<index_instance_node_pk>\d+)/$', 'index_instance_node_view', (), 'index_instance_node_view'),
#Broken
url(r'^(?P<index_instance_node_pk>\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'^rebuild/all/$', 'rebuild_index_instances', (), 'rebuild_index_instances'),
url(r'^list/for/document/(?P<document_id>\d+)/$', 'document_index_list', (), 'document_index_list'), url(r'^list/for/document/(?P<document_id>\d+)/$', 'document_index_list', (), 'document_index_list'),
) )

View File

@@ -10,12 +10,14 @@ from django.contrib import messages
#from django.utils.safestring import mark_safe #from django.utils.safestring import mark_safe
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.utils.html import conditional_escape, mark_safe from django.utils.html import conditional_escape, mark_safe
from django.core.exceptions import PermissionDenied
from permissions.models import Permission from permissions.models import Permission
from documents.permissions import PERMISSION_DOCUMENT_VIEW from documents.permissions import PERMISSION_DOCUMENT_VIEW
from documents.models import Document from documents.models import Document
from documents.views import document_list from documents.views import document_list
from common.utils import encapsulate from common.utils import encapsulate
from acls.utils import apply_default_acls
from .forms import IndexForm, IndexTemplateNodeForm from .forms import IndexForm, IndexTemplateNodeForm
from .models import (Index, IndexTemplateNode, IndexInstanceNode) from .models import (Index, IndexTemplateNode, IndexInstanceNode)
@@ -64,7 +66,7 @@ def index_setup_create(request):
form = IndexForm(request.POST) form = IndexForm(request.POST)
if form.is_valid(): if form.is_valid():
index = form.save() index = form.save()
#apply_default_acls(folder, request.user) apply_default_acls(index, request.user)
messages.success(request, _(u'Index created successfully.')) messages.success(request, _(u'Index created successfully.'))
return HttpResponseRedirect(reverse('index_setup_list')) return HttpResponseRedirect(reverse('index_setup_list'))
else: else:
@@ -170,32 +172,6 @@ def index_setup_view(request, index_pk):
context_instance=RequestContext(request)) context_instance=RequestContext(request))
def index_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'},
#]
'overrided_object_links': [{}],
}
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)
)
# Node views # Node views
def template_node_create(request, parent_pk): def template_node_create(request, parent_pk):
parent_node = get_object_or_404(IndexTemplateNode, pk=parent_pk) parent_node = get_object_or_404(IndexTemplateNode, pk=parent_pk)
@@ -301,30 +277,56 @@ def template_node_delete(request, node_pk):
# User views # User views
def index_instance_list(request, index_id=None):
Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_INDEXING_VIEW])
if index_id: #from . import index_roots as index_roots_link
index_instance = get_object_or_404(IndexInstanceNode, pk=index_id)
index_instance_list = [index for index in index_instance.get_children().order_by('value')] def index_list(request):
breadcrumbs = get_breadcrumbs(index_instance) context = {
if index_instance.documents.count(): 'title': _(u'indexes'),
for document in index_instance.documents.all().order_by('file_filename'): #'hide_object': True,
index_instance_list.append(document) #'list_object_variable_name': 'index',
else: 'extra_columns': [
index_instance_list = IndexInstanceNode.objects.filter(parent=None) {'name': _(u'root'), 'attribute': 'root'},
breadcrumbs = get_instance_link() # {'name': _(u'name'), 'attribute': 'name'},
index_instance = None # {'name': _(u'title'), 'attribute': 'title'},
],
'overrided_object_links': [{}],
}
queryset = Index.objects.all()
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) title = mark_safe(_(u'contents for index: %s') % breadcrumbs)
if index_instance: 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 # Document list, use the document_list view for consistency
return document_list( return document_list(
request, request,
title=title, title=title,
object_list=index_instance_list, object_list=index_instance.documents.all(),
extra_context={ extra_context={
'object': index_instance 'object': index_instance
} }
@@ -334,12 +336,12 @@ def index_instance_list(request, index_id=None):
'object_list': index_instance_list, 'object_list': index_instance_list,
'extra_columns_preffixed': [ 'extra_columns_preffixed': [
{ {
'name': _(u'index'), 'name': _(u'node'),
'attribute': encapsulate(lambda x: index_instance_item_link(x)) 'attribute': encapsulate(lambda x: index_instance_item_link(x))
}, },
{ {
'name': _(u'items'), '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, 'title': title,
@@ -378,12 +380,13 @@ def rebuild_index_instances(request):
def document_index_list(request, document_id): def document_index_list(request, document_id):
#TODO: add ACL check
Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW, PERMISSION_DOCUMENT_INDEXING_VIEW]) Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW, PERMISSION_DOCUMENT_INDEXING_VIEW])
document = get_object_or_404(Document, pk=document_id) document = get_object_or_404(Document, pk=document_id)
object_list = [] object_list = []
for index_instance in document.indexinstance_set.all(): for index_instance in document.indexinstancenode_set.all():
object_list.append(get_breadcrumbs(index_instance, single_link=True, include_count=True)) object_list.append(get_breadcrumbs(index_instance, single_link=True, include_count=True))
return render_to_response('generic_list.html', { return render_to_response('generic_list.html', {

View File

@@ -10,7 +10,7 @@ FOLDER_ICON = u'folder'
def index_instance_item_link(index_instance_item): def index_instance_item_link(index_instance_item):
if isinstance(index_instance_item, IndexInstanceNode): if isinstance(index_instance_item, IndexInstanceNode):
if index_instance_item.index.link_documents: if index_instance_item.index_template_node.link_documents:
icon = FOLDER_W_DOCUMENTS icon = FOLDER_W_DOCUMENTS
else: else:
icon = FOLDER_ICON icon = FOLDER_ICON