Simplify and optimize smart linking code and views, remove now unused LINKING_SHOW_EMPTY_SMART_LINKS configuration setting (issue #56)
This commit is contained in:
@@ -194,19 +194,6 @@ Default: ``/usr/bin/libreoffice``
|
|||||||
Path to the libreoffice binary used to call LibreOffice for office document conversion.
|
Path to the libreoffice binary used to call LibreOffice for office document conversion.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Linking
|
|
||||||
=======
|
|
||||||
|
|
||||||
.. setting:: LINKING_SHOW_EMPTY_SMART_LINKS
|
|
||||||
|
|
||||||
**LINKING_SHOW_EMPTY_SMART_LINKS**
|
|
||||||
|
|
||||||
Default: ``True``
|
|
||||||
|
|
||||||
Show smart links even when they don't return any documents.
|
|
||||||
|
|
||||||
|
|
||||||
Storage
|
Storage
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ from documents.models import Document
|
|||||||
from navigation.api import register_links
|
from navigation.api import register_links
|
||||||
from project_setup.api import register_setup
|
from project_setup.api import register_setup
|
||||||
|
|
||||||
from .links import (smart_link_acl_list, smart_link_create,
|
from .classes import ResolvedSmartLink
|
||||||
smart_link_condition_create, smart_link_condition_delete,
|
from .links import (smart_link_acl_list,
|
||||||
smart_link_condition_edit, smart_link_condition_list,
|
smart_link_create, smart_link_condition_create,
|
||||||
smart_link_delete, smart_link_document_types,
|
smart_link_condition_delete, smart_link_condition_edit,
|
||||||
smart_link_edit, smart_link_instances_for_document,
|
smart_link_condition_list, smart_link_delete,
|
||||||
smart_link_list, smart_link_setup)
|
smart_link_document_types, smart_link_edit,
|
||||||
|
smart_link_instance_view, smart_link_instances_for_document, smart_link_list,
|
||||||
|
smart_link_setup)
|
||||||
from .models import SmartLink, SmartLinkCondition
|
from .models import SmartLink, SmartLinkCondition
|
||||||
from .permissions import (PERMISSION_SMART_LINK_DELETE,
|
from .permissions import (PERMISSION_SMART_LINK_DELETE,
|
||||||
PERMISSION_SMART_LINK_EDIT,
|
PERMISSION_SMART_LINK_EDIT,
|
||||||
@@ -21,6 +23,7 @@ register_links(Document, [smart_link_instances_for_document], menu_name='form_he
|
|||||||
register_links(SmartLink, [smart_link_edit, smart_link_document_types, smart_link_condition_list, smart_link_acl_list, smart_link_delete])
|
register_links(SmartLink, [smart_link_edit, smart_link_document_types, smart_link_condition_list, smart_link_acl_list, smart_link_delete])
|
||||||
register_links([SmartLink, 'linking:smart_link_list', 'linking:smart_link_create'], [smart_link_list, smart_link_create], menu_name='secondary_menu')
|
register_links([SmartLink, 'linking:smart_link_list', 'linking:smart_link_create'], [smart_link_list, smart_link_create], menu_name='secondary_menu')
|
||||||
register_links(SmartLinkCondition, [smart_link_condition_edit, smart_link_condition_delete])
|
register_links(SmartLinkCondition, [smart_link_condition_edit, smart_link_condition_delete])
|
||||||
|
register_links(ResolvedSmartLink, [smart_link_instance_view])
|
||||||
register_links(['linking:smart_link_condition_list', 'linking:smart_link_condition_create', 'linking:smart_link_condition_edit', 'linking:smart_link_condition_delete'], [smart_link_condition_create], menu_name='sidebar')
|
register_links(['linking:smart_link_condition_list', 'linking:smart_link_condition_create', 'linking:smart_link_condition_edit', 'linking:smart_link_condition_delete'], [smart_link_condition_create], menu_name='sidebar')
|
||||||
|
|
||||||
register_setup(smart_link_setup)
|
register_setup(smart_link_setup)
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
ResolvedSmartLink = namedtuple('ResolvedSmartLink', ['smart_link', 'queryset'])
|
||||||
@@ -1,15 +1,10 @@
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.utils.safestring import mark_safe
|
|
||||||
from django.utils.translation import ugettext
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from common.classes import ModelAttribute
|
from common.classes import ModelAttribute
|
||||||
from documents.models import Document
|
from documents.models import Document
|
||||||
from documents.widgets import document_html_widget
|
|
||||||
from documents.settings import MULTIPAGE_PREVIEW_SIZE
|
|
||||||
|
|
||||||
from .models import SmartLink, SmartLinkCondition
|
from .models import SmartLink, SmartLinkCondition
|
||||||
|
|
||||||
@@ -22,7 +17,6 @@ class SmartLinkForm(forms.ModelForm):
|
|||||||
|
|
||||||
class SmartLinkConditionForm(forms.ModelForm):
|
class SmartLinkConditionForm(forms.ModelForm):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
smart_link = kwargs.pop('smart_link', None)
|
|
||||||
super(SmartLinkConditionForm, self).__init__(*args, **kwargs)
|
super(SmartLinkConditionForm, self).__init__(*args, **kwargs)
|
||||||
self.fields['foreign_document_data'] = forms.ChoiceField(choices=ModelAttribute.get_choices_for(Document, type_names=['field', 'query']), label=_('Foreign document attribute'))
|
self.fields['foreign_document_data'] = forms.ChoiceField(choices=ModelAttribute.get_choices_for(Document, type_names=['field', 'query']), label=_('Foreign document attribute'))
|
||||||
self.fields['expression'].help_text = ' '.join([self.fields['expression'].help_text, ModelAttribute.help_text_for(Document, type_names=['field', 'related', 'property'])])
|
self.fields['expression'].help_text = ' '.join([self.fields['expression'].help_text, ModelAttribute.help_text_for(Document, type_names=['field', 'related', 'property'])])
|
||||||
@@ -30,66 +24,3 @@ class SmartLinkConditionForm(forms.ModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = SmartLinkCondition
|
model = SmartLinkCondition
|
||||||
exclude = ('smart_link',)
|
exclude = ('smart_link',)
|
||||||
|
|
||||||
|
|
||||||
class SmartLinkImageWidget(forms.widgets.Widget):
|
|
||||||
def render(self, name, value, attrs=None):
|
|
||||||
output = []
|
|
||||||
# TODO: convert to navigation app
|
|
||||||
if value['links']:
|
|
||||||
output.append(u'<div class="group navform wat-cf">')
|
|
||||||
for link in value['links']:
|
|
||||||
output.append(u'''
|
|
||||||
<button class="button" type="submit" name="action" value="%(action)s">
|
|
||||||
<span class="famfam active famfam-%(famfam)s"></span>%(text)s
|
|
||||||
</button>
|
|
||||||
''' % {
|
|
||||||
'famfam': link.get('famfam', u'link'),
|
|
||||||
'text': link['text'],
|
|
||||||
'action': reverse(link.get('view'), args=[value['current_document'].pk, value['smart_link_instance'].pk])
|
|
||||||
})
|
|
||||||
output.append(u'</div>')
|
|
||||||
|
|
||||||
# TODO: Move CSS markup outside of forms.py
|
|
||||||
output.append(u'<div style="white-space:nowrap; overflow: auto;">')
|
|
||||||
for document in value['documents']:
|
|
||||||
output.append(u'<div style="display: inline-block; margin: 0px 10px 10px 10px; %s">' % (u'border: 5px solid black; padding: 3px;' if value['current_document'] == document else u''))
|
|
||||||
output.append(u'<div class="tc">%s</div>' % document)
|
|
||||||
output.append(u'<div class="tc">%s: %d</div>' % (ugettext(u'Pages'), document.pages.count()))
|
|
||||||
output.append(u'<div style="padding: 5px;">')
|
|
||||||
output.append(document_html_widget(document, click_view='documents:document_display', size=MULTIPAGE_PREVIEW_SIZE, fancybox_class='fancybox-noscaling', gallery_name=u'smart_link_%d_documents_gallery' % value['smart_link_instance'].pk))
|
|
||||||
output.append(u'</div>')
|
|
||||||
output.append(u'<div class="tc">')
|
|
||||||
output.append(u'<a href="%s"><span class="famfam active famfam-page_go"></span>%s</a>' % (reverse('documents:document_view_simple', args=[document.pk]), ugettext(u'Select')))
|
|
||||||
output.append(u'</div>')
|
|
||||||
output.append(u'</div>')
|
|
||||||
|
|
||||||
output.append(u'</div>')
|
|
||||||
output.append(
|
|
||||||
u'<br /><span class="famfam active famfam-magnifier"></span>%s' %
|
|
||||||
ugettext(u'Click on the image for full size view of the first page.')
|
|
||||||
)
|
|
||||||
|
|
||||||
return mark_safe(u''.join(output))
|
|
||||||
|
|
||||||
|
|
||||||
class SmartLinkInstanceForm(forms.Form):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
smart_link_instances = kwargs.pop('smart_link_instances', None)
|
|
||||||
links = kwargs.pop('links', None)
|
|
||||||
current_document = kwargs.pop('current_document', None)
|
|
||||||
|
|
||||||
super(SmartLinkInstanceForm, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
for smart_link_instance, data in smart_link_instances.items():
|
|
||||||
self.fields['preview-%s' % smart_link_instance.pk] = forms.CharField(
|
|
||||||
widget=SmartLinkImageWidget(),
|
|
||||||
label=u'%s (%d)' % (unicode(data['title']), len(data['documents'])),
|
|
||||||
required=False,
|
|
||||||
initial={
|
|
||||||
'smart_link_instance': smart_link_instance,
|
|
||||||
'documents': data['documents'],
|
|
||||||
'current_document': current_document,
|
|
||||||
'links': links
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -7,10 +7,8 @@ from documents.permissions import PERMISSION_DOCUMENT_VIEW
|
|||||||
|
|
||||||
from .permissions import (PERMISSION_SMART_LINK_CREATE,
|
from .permissions import (PERMISSION_SMART_LINK_CREATE,
|
||||||
PERMISSION_SMART_LINK_DELETE,
|
PERMISSION_SMART_LINK_DELETE,
|
||||||
PERMISSION_SMART_LINK_EDIT)
|
PERMISSION_SMART_LINK_EDIT,
|
||||||
|
PERMISSION_SMART_LINK_VIEW)
|
||||||
smart_link_instance_view_link = {'text': _(u'Smart links actions'), 'view': 'linking:smart_link_instance_view', 'famfam': 'page_link', 'permissions': [PERMISSION_DOCUMENT_VIEW]}
|
|
||||||
smart_link_instances_for_document = {'text': _(u'Smart links'), 'view': 'linking:smart_link_instances_for_document', 'args': 'object.pk', 'famfam': 'page_link', 'permissions': [PERMISSION_DOCUMENT_VIEW]}
|
|
||||||
|
|
||||||
smart_link_setup = {'text': _(u'Smart links'), 'view': 'linking:smart_link_list', 'icon': 'link.png', 'permissions': [PERMISSION_SMART_LINK_CREATE]}
|
smart_link_setup = {'text': _(u'Smart links'), 'view': 'linking:smart_link_list', 'icon': 'link.png', 'permissions': [PERMISSION_SMART_LINK_CREATE]}
|
||||||
smart_link_list = {'text': _(u'Smart links'), 'view': 'linking:smart_link_list', 'famfam': 'link', 'permissions': [PERMISSION_SMART_LINK_CREATE]}
|
smart_link_list = {'text': _(u'Smart links'), 'view': 'linking:smart_link_list', 'famfam': 'link', 'permissions': [PERMISSION_SMART_LINK_CREATE]}
|
||||||
@@ -19,9 +17,12 @@ smart_link_edit = {'text': _(u'Edit'), 'view': 'linking:smart_link_edit', 'args'
|
|||||||
smart_link_delete = {'text': _(u'Delete'), 'view': 'linking:smart_link_delete', 'args': 'object.pk', 'famfam': 'link_delete', 'permissions': [PERMISSION_SMART_LINK_DELETE]}
|
smart_link_delete = {'text': _(u'Delete'), 'view': 'linking:smart_link_delete', 'args': 'object.pk', 'famfam': 'link_delete', 'permissions': [PERMISSION_SMART_LINK_DELETE]}
|
||||||
smart_link_document_types = {'text': _('Document types'), 'view': 'linking:smart_link_document_types', 'args': 'object.pk', 'famfam': 'layout', 'permissions': [PERMISSION_SMART_LINK_EDIT]}
|
smart_link_document_types = {'text': _('Document types'), 'view': 'linking:smart_link_document_types', 'args': 'object.pk', 'famfam': 'layout', 'permissions': [PERMISSION_SMART_LINK_EDIT]}
|
||||||
|
|
||||||
smart_link_condition_list = {'text': _(u'Conditions'), 'view': 'linking:smart_link_condition_list', 'args': 'object.pk', 'famfam': 'cog', 'permissions': [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_CREATE]}
|
smart_link_instances_for_document = {'text': _(u'Smart links'), 'view': 'linking:smart_link_instances_for_document', 'args': 'object.pk', 'famfam': 'page_link', 'permissions': [PERMISSION_DOCUMENT_VIEW]}
|
||||||
smart_link_condition_create = {'text': _(u'Create condition'), 'view': 'linking:smart_link_condition_create', 'args': 'object.pk', 'famfam': 'cog_add', 'permissions': [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]}
|
smart_link_instance_view = {'text': _('Documents'), 'view': 'linking:smart_link_instance_view', 'args': ['document.pk', 'object.smart_link.pk'], 'famfam': 'layout', 'page': [PERMISSION_SMART_LINK_VIEW]}
|
||||||
smart_link_condition_edit = {'text': _(u'Edit'), 'view': 'linking:smart_link_condition_edit', 'args': 'condition.pk', 'famfam': 'cog_edit', 'permissions': [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]}
|
|
||||||
smart_link_condition_delete = {'text': _(u'Delete'), 'view': 'linking:smart_link_condition_delete', 'args': 'condition.pk', 'famfam': 'cog_delete', 'permissions': [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]}
|
smart_link_condition_list = {'text': _(u'Conditions'), 'view': 'linking:smart_link_condition_list', 'args': 'object.pk', 'famfam': 'cog', 'permissions': [PERMISSION_SMART_LINK_EDIT]}
|
||||||
|
smart_link_condition_create = {'text': _(u'Create condition'), 'view': 'linking:smart_link_condition_create', 'args': 'object.pk', 'famfam': 'cog_add', 'permissions': [PERMISSION_SMART_LINK_EDIT]}
|
||||||
|
smart_link_condition_edit = {'text': _(u'Edit'), 'view': 'linking:smart_link_condition_edit', 'args': 'condition.pk', 'famfam': 'cog_edit', 'permissions': [PERMISSION_SMART_LINK_EDIT]}
|
||||||
|
smart_link_condition_delete = {'text': _(u'Delete'), 'view': 'linking:smart_link_condition_delete', 'args': 'condition.pk', 'famfam': 'cog_delete', 'permissions': [PERMISSION_SMART_LINK_EDIT]}
|
||||||
|
|
||||||
smart_link_acl_list = {'text': _(u'ACLs'), 'view': 'linking:smart_link_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]}
|
smart_link_acl_list = {'text': _(u'ACLs'), 'view': 'linking:smart_link_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]}
|
||||||
|
|||||||
@@ -1,61 +1,10 @@
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
|
||||||
|
|
||||||
from documents.models import Document
|
from .classes import ResolvedSmartLink
|
||||||
|
|
||||||
from .literals import INCLUSION_AND, INCLUSION_OR
|
|
||||||
|
|
||||||
|
|
||||||
class SmartLinkManager(models.Manager):
|
class SmartLinkManager(models.Manager):
|
||||||
def get_for(self, document, smart_link_obj=None):
|
def get_for(self, document):
|
||||||
errors = []
|
return [ResolvedSmartLink(smart_link=smart_link, queryset=smart_link.get_linked_document_for(document)) for smart_link in self.filter(enabled=True).filter(document_types=document.document_type)]
|
||||||
result = {}
|
|
||||||
|
|
||||||
smart_link_qs = self.model.objects.filter(enabled=True)
|
|
||||||
|
|
||||||
if smart_link_obj:
|
|
||||||
smart_link_qs = smart_link_qs.filter(pk=smart_link_obj.pk)
|
|
||||||
|
|
||||||
smart_link_qs = smart_link_qs.filter(document_types=document.document_type)
|
|
||||||
|
|
||||||
for smart_link in smart_link_qs:
|
|
||||||
total_query = Q()
|
|
||||||
for condition in smart_link.smartlinkcondition_set.filter(enabled=True):
|
|
||||||
value_query = Q(**{
|
|
||||||
'%s__%s' % (condition.foreign_document_data, condition.operator): eval(condition.expression, {'document': document})
|
|
||||||
})
|
|
||||||
if condition.negated:
|
|
||||||
query = ~value_query
|
|
||||||
else:
|
|
||||||
query = value_query
|
|
||||||
if condition.inclusion == INCLUSION_AND:
|
|
||||||
total_query &= query
|
|
||||||
elif condition.inclusion == INCLUSION_OR:
|
|
||||||
total_query |= query
|
|
||||||
|
|
||||||
if total_query:
|
|
||||||
try:
|
|
||||||
document_qs = Document.objects.filter(total_query)
|
|
||||||
result[smart_link] = {'documents': document_qs.order_by('date_added') or []}
|
|
||||||
except Exception as exception:
|
|
||||||
result[smart_link] = {'documents': []}
|
|
||||||
errors.append(exception)
|
|
||||||
else:
|
|
||||||
result[smart_link] = {'documents': []}
|
|
||||||
|
|
||||||
if smart_link.dynamic_title:
|
|
||||||
try:
|
|
||||||
result[smart_link]['title'] = eval(smart_link.dynamic_title, {'document': document})
|
|
||||||
except Exception as exception:
|
|
||||||
result[smart_link]['title'] = 'Error; %s' % exception
|
|
||||||
else:
|
|
||||||
result[smart_link]['title'] = smart_link.title
|
|
||||||
|
|
||||||
if smart_link_obj:
|
|
||||||
# Return a single group if documents even if there were
|
|
||||||
# many matches
|
|
||||||
return result[smart_link_obj], errors
|
|
||||||
|
|
||||||
return result, errors
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Q
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext
|
||||||
|
|
||||||
from documents.models import DocumentType
|
from documents.models import Document, DocumentType
|
||||||
|
|
||||||
from .literals import INCLUSION_AND, INCLUSION_CHOICES, OPERATOR_CHOICES
|
from .literals import (INCLUSION_AND, INCLUSION_CHOICES, INCLUSION_OR,
|
||||||
|
OPERATOR_CHOICES)
|
||||||
from .managers import SmartLinkManager
|
from .managers import SmartLinkManager
|
||||||
|
|
||||||
|
|
||||||
@@ -18,19 +20,39 @@ class SmartLink(models.Model):
|
|||||||
|
|
||||||
objects = SmartLinkManager()
|
objects = SmartLinkManager()
|
||||||
|
|
||||||
def get_document_types_not_selected(self):
|
|
||||||
return DocumentType.objects.exclude(pk__in=self.document_types.all())
|
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
|
def get_linked_document_for(self, document):
|
||||||
|
if document.document_type.pk not in self.document_types.values_list('pk', flat=True):
|
||||||
|
raise Exception(_('This smart link is not allowed for the selected document\'s type.'))
|
||||||
|
|
||||||
|
smart_link_query = Q()
|
||||||
|
|
||||||
|
for condition in self.conditions.filter(enabled=True):
|
||||||
|
condition_query = Q(**{
|
||||||
|
'%s__%s' % (condition.foreign_document_data, condition.operator): eval(condition.expression, {'document': document})
|
||||||
|
})
|
||||||
|
if condition.negated:
|
||||||
|
condition_query = ~condition_query
|
||||||
|
|
||||||
|
if condition.inclusion == INCLUSION_AND:
|
||||||
|
smart_link_query &= condition_query
|
||||||
|
elif condition.inclusion == INCLUSION_OR:
|
||||||
|
smart_link_query |= condition_query
|
||||||
|
|
||||||
|
if smart_link_query:
|
||||||
|
return Document.objects.filter(smart_link_query)
|
||||||
|
else:
|
||||||
|
return Document.objects.none()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _(u'Smart link')
|
verbose_name = _(u'Smart link')
|
||||||
verbose_name_plural = _(u'Smart links')
|
verbose_name_plural = _(u'Smart links')
|
||||||
|
|
||||||
|
|
||||||
class SmartLinkCondition(models.Model):
|
class SmartLinkCondition(models.Model):
|
||||||
smart_link = models.ForeignKey(SmartLink, verbose_name=_(u'Smart link'))
|
smart_link = models.ForeignKey(SmartLink, related_name='conditions', verbose_name=_(u'Smart link'))
|
||||||
inclusion = models.CharField(default=INCLUSION_AND, max_length=16, choices=INCLUSION_CHOICES, help_text=_(u'The inclusion is ignored for the first item.'))
|
inclusion = models.CharField(default=INCLUSION_AND, max_length=16, choices=INCLUSION_CHOICES, help_text=_(u'The inclusion is ignored for the first item.'))
|
||||||
foreign_document_data = models.CharField(max_length=128, verbose_name=_(u'Foreign document attribute'), help_text=_(u'This represents the metadata of all other documents.'))
|
foreign_document_data = models.CharField(max_length=128, verbose_name=_(u'Foreign document attribute'), help_text=_(u'This represents the metadata of all other documents.'))
|
||||||
operator = models.CharField(max_length=16, choices=OPERATOR_CHOICES)
|
operator = models.CharField(max_length=16, choices=OPERATOR_CHOICES)
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
"""Configuration options for the linking app"""
|
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
from smart_settings.api import register_settings
|
|
||||||
|
|
||||||
register_settings(
|
|
||||||
namespace=u'linking',
|
|
||||||
module=u'linking.settings',
|
|
||||||
settings=[
|
|
||||||
{'name': u'SHOW_EMPTY_SMART_LINKS', 'global_name': u'LINKING_SHOW_EMPTY_SMART_LINKS', 'default': True, 'description': _(u'Show smart link that don\'t return any documents.')},
|
|
||||||
]
|
|
||||||
)
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from south.utils import datetime_utils as datetime
|
|
||||||
from south.db import db
|
from south.db import db
|
||||||
from south.v2 import SchemaMigration
|
from south.v2 import SchemaMigration
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from south.utils import datetime_utils as datetime
|
|
||||||
from south.db import db
|
from south.db import db
|
||||||
from south.v2 import SchemaMigration
|
from south.v2 import SchemaMigration
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|||||||
+1
-2
@@ -1,5 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from south.utils import datetime_utils as datetime
|
|
||||||
from south.db import db
|
from south.db import db
|
||||||
from south.v2 import SchemaMigration
|
from south.v2 import SchemaMigration
|
||||||
from django.db import models
|
from django.db import models
|
||||||
@@ -45,4 +44,4 @@ class Migration(SchemaMigration):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
complete_apps = ['linking']
|
complete_apps = ['linking']
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
from django.conf.urls import patterns, url
|
from django.conf.urls import patterns, url
|
||||||
|
|
||||||
urlpatterns = patterns('linking.views',
|
urlpatterns = patterns('linking.views',
|
||||||
url(r'^action/$', 'smart_link_action', (), 'smart_link_action'),
|
url(r'^document/(?P<document_id>\d+)/$', 'smart_link_instances_for_document', (), 'smart_link_instances_for_document'),
|
||||||
url(r'^document/(?P<document_id>\d+)/smart_link/(?P<smart_link_pk>\d+)/$', 'smart_link_instance_view', (), 'smart_link_instance_view'),
|
url(r'^document/(?P<document_id>\d+)/smart_link/(?P<smart_link_pk>\d+)/$', 'smart_link_instance_view', (), 'smart_link_instance_view'),
|
||||||
url(r'^smart/for_document/(?P<document_id>\d+)/$', 'smart_link_instances_for_document', (), 'smart_link_instances_for_document'),
|
|
||||||
|
|
||||||
url(r'^setup/list/$', 'smart_link_list', (), 'smart_link_list'),
|
url(r'^setup/list/$', 'smart_link_list', (), 'smart_link_list'),
|
||||||
url(r'^setup/create/$', 'smart_link_create', (), 'smart_link_create'),
|
url(r'^setup/create/$', 'smart_link_create', (), 'smart_link_create'),
|
||||||
|
|||||||
+46
-75
@@ -16,34 +16,20 @@ from acls.views import acl_list_for
|
|||||||
from common.utils import encapsulate, generate_choices_w_labels
|
from common.utils import encapsulate, generate_choices_w_labels
|
||||||
from common.views import assign_remove
|
from common.views import assign_remove
|
||||||
from common.widgets import two_state_template
|
from common.widgets import two_state_template
|
||||||
from documents.models import Document
|
from documents.models import Document, DocumentType
|
||||||
from documents.permissions import PERMISSION_DOCUMENT_VIEW
|
|
||||||
from documents.views import document_list
|
from documents.views import document_list
|
||||||
from permissions.models import Permission
|
from permissions.models import Permission
|
||||||
|
|
||||||
from .forms import (SmartLinkConditionForm, SmartLinkInstanceForm,
|
from .forms import SmartLinkConditionForm, SmartLinkForm
|
||||||
SmartLinkForm)
|
|
||||||
from .links import smart_link_instance_view_link
|
|
||||||
from .models import SmartLink, SmartLinkCondition
|
from .models import SmartLink, SmartLinkCondition
|
||||||
from .permissions import (PERMISSION_SMART_LINK_CREATE,
|
from .permissions import (PERMISSION_SMART_LINK_CREATE,
|
||||||
PERMISSION_SMART_LINK_DELETE,
|
PERMISSION_SMART_LINK_DELETE,
|
||||||
PERMISSION_SMART_LINK_EDIT,
|
PERMISSION_SMART_LINK_EDIT,
|
||||||
PERMISSION_SMART_LINK_VIEW)
|
PERMISSION_SMART_LINK_VIEW)
|
||||||
from .settings import SHOW_EMPTY_SMART_LINKS
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def smart_link_action(request):
|
|
||||||
action = request.GET.get('action', None)
|
|
||||||
|
|
||||||
if not action:
|
|
||||||
messages.error(request, _(u'No action selected.'))
|
|
||||||
return HttpResponseRedirect(request.META.get('HTTP_REFERER', reverse('main:home')))
|
|
||||||
|
|
||||||
return HttpResponseRedirect(action)
|
|
||||||
|
|
||||||
|
|
||||||
def smart_link_instance_view(request, document_id, smart_link_pk):
|
def smart_link_instance_view(request, document_id, smart_link_pk):
|
||||||
document = get_object_or_404(Document, pk=document_id)
|
document = get_object_or_404(Document, pk=document_id)
|
||||||
smart_link = get_object_or_404(SmartLink, pk=smart_link_pk)
|
smart_link = get_object_or_404(SmartLink, pk=smart_link_pk)
|
||||||
@@ -53,14 +39,18 @@ def smart_link_instance_view(request, document_id, smart_link_pk):
|
|||||||
except PermissionDenied:
|
except PermissionDenied:
|
||||||
AccessEntry.objects.check_access(PERMISSION_SMART_LINK_VIEW, request.user, smart_link)
|
AccessEntry.objects.check_access(PERMISSION_SMART_LINK_VIEW, request.user, smart_link)
|
||||||
|
|
||||||
object_list, errors = SmartLink.objects.get_for(document, smart_link)
|
try:
|
||||||
|
object_list = smart_link.get_linked_document_for(document)
|
||||||
|
except Exception as exception:
|
||||||
|
object_list = []
|
||||||
|
|
||||||
|
if request.user.is_staff or request.user.is_superuser:
|
||||||
|
messages.error(request, _(u'Smart link query error: %s' % exception))
|
||||||
|
|
||||||
return document_list(
|
return document_list(
|
||||||
request,
|
request,
|
||||||
title=_(u'Documents in smart link: %(group)s') % {
|
title=_(u'Documents in smart link: %s') % smart_link,
|
||||||
'group': object_list['title']
|
object_list=object_list,
|
||||||
},
|
|
||||||
object_list=object_list['documents'],
|
|
||||||
extra_context={
|
extra_context={
|
||||||
'object': document
|
'object': document
|
||||||
}
|
}
|
||||||
@@ -68,57 +58,40 @@ def smart_link_instance_view(request, document_id, smart_link_pk):
|
|||||||
|
|
||||||
|
|
||||||
def smart_link_instances_for_document(request, document_id):
|
def smart_link_instances_for_document(request, document_id):
|
||||||
subtemplates_list = []
|
|
||||||
document = get_object_or_404(Document, pk=document_id)
|
document = get_object_or_404(Document, pk=document_id)
|
||||||
smart_link_instances, errors = SmartLink.objects.get_for(document)
|
|
||||||
if (request.user.is_staff or request.user.is_superuser) and errors:
|
|
||||||
for error in errors:
|
|
||||||
messages.warning(request, _(u'Smart link query error: %s' % error))
|
|
||||||
|
|
||||||
if not SHOW_EMPTY_SMART_LINKS:
|
queryset = SmartLink.objects.get_for(document)
|
||||||
# If SHOW_EMPTY_SMART_LINKS is False, remove empty groups from
|
|
||||||
# dictionary
|
|
||||||
smart_link_instances = dict([(group, data) for group, data in smart_link_instances.items() if data['documents']])
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW])
|
Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_VIEW])
|
||||||
except PermissionDenied:
|
except PermissionDenied:
|
||||||
smart_link_instances_keys_filtered = AccessEntry.objects.filter_objects_by_access(PERMISSION_SMART_LINK_VIEW, request.user, smart_link_instances.keys())
|
smart_links = AccessEntry.objects.filter_objects_by_access(PERMISSION_SMART_LINK_VIEW, request.user, queryset)
|
||||||
# Remove smart link instances not found in the new filtered key list
|
|
||||||
for key, value in smart_link_instances.items():
|
|
||||||
if key not in smart_link_instances_keys_filtered:
|
|
||||||
smart_link_instances.pop(key)
|
|
||||||
|
|
||||||
value['documents'] = AccessEntry.objects.filter_objects_by_access(PERMISSION_DOCUMENT_VIEW, request.user, value['documents'])
|
|
||||||
|
|
||||||
if smart_link_instances:
|
|
||||||
subtemplates_list = [{
|
|
||||||
'name': 'main/generic_form_subtemplate.html',
|
|
||||||
'context': {
|
|
||||||
'title': _(u'Smart links (%s)') % len(smart_link_instances.keys()),
|
|
||||||
'form': SmartLinkInstanceForm(
|
|
||||||
smart_link_instances=smart_link_instances, current_document=document,
|
|
||||||
links=[smart_link_instance_view_link]
|
|
||||||
),
|
|
||||||
'form_action': reverse('linking:smart_link_action'),
|
|
||||||
'submit_method': 'GET',
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
else:
|
else:
|
||||||
# If there are not group display a placeholder messages saying so
|
smart_links = queryset
|
||||||
subtemplates_list = [{
|
|
||||||
'name': 'main/generic_subtemplate.html',
|
|
||||||
'context': {
|
|
||||||
'title': _(u'Smart links (0)'),
|
|
||||||
'content': _(u'There are no defined smart links for the current document.'),
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
|
|
||||||
return render_to_response('main/generic_detail.html', {
|
context = {
|
||||||
'object': document,
|
|
||||||
'document': document,
|
'document': document,
|
||||||
'subtemplates_list': subtemplates_list,
|
'object': document,
|
||||||
}, context_instance=RequestContext(request))
|
'object_list': smart_links,
|
||||||
|
'title': _(u'Smart links for: %s') % document,
|
||||||
|
'extra_columns': [
|
||||||
|
{'name': _('Indentifier'), 'attribute': 'smart_link'},
|
||||||
|
{'name': _('Documents'), 'attribute': encapsulate(lambda smart_link: smart_link.queryset.count())}
|
||||||
|
],
|
||||||
|
'extra_navigation_links': {
|
||||||
|
SmartLink: {
|
||||||
|
None: {
|
||||||
|
'link': [{'text': 'asd'}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
'hide_object': True,
|
||||||
|
'hide_link': True,
|
||||||
|
}
|
||||||
|
|
||||||
|
return render_to_response('main/generic_list.html', context,
|
||||||
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
|
||||||
def smart_link_list(request):
|
def smart_link_list(request):
|
||||||
@@ -226,12 +199,10 @@ def smart_link_document_types(request, smart_link_pk):
|
|||||||
|
|
||||||
return assign_remove(
|
return assign_remove(
|
||||||
request,
|
request,
|
||||||
left_list=lambda: generate_choices_w_labels(smart_link.get_document_types_not_selected(), display_object_type=False),
|
left_list=lambda: generate_choices_w_labels(DocumentType.objects.exclude(pk__in=smart_link.document_types.all()), display_object_type=False),
|
||||||
right_list=lambda: generate_choices_w_labels(smart_link.document_types.all(), display_object_type=False),
|
right_list=lambda: generate_choices_w_labels(smart_link.document_types.all(), display_object_type=False),
|
||||||
add_method=lambda x: smart_link.document_types.add(x),
|
add_method=lambda x: smart_link.document_types.add(x),
|
||||||
remove_method=lambda x: smart_link.document_types.remove(x),
|
remove_method=lambda x: smart_link.document_types.remove(x),
|
||||||
#left_list_title=_(u'Document types not in index: %s') % smart_link,
|
|
||||||
#right_list_title=_(u'Document types for index: %s') % smart_link,
|
|
||||||
decode_content_type=True,
|
decode_content_type=True,
|
||||||
extra_context={
|
extra_context={
|
||||||
'main_title': _('Document type for which to enable smart link: %s') % smart_link,
|
'main_title': _('Document type for which to enable smart link: %s') % smart_link,
|
||||||
@@ -244,13 +215,13 @@ def smart_link_condition_list(request, smart_link_pk):
|
|||||||
smart_link = get_object_or_404(SmartLink, pk=smart_link_pk)
|
smart_link = get_object_or_404(SmartLink, pk=smart_link_pk)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT])
|
Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_EDIT])
|
||||||
except PermissionDenied:
|
except PermissionDenied:
|
||||||
AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT], request.user, smart_link)
|
AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_EDIT], request.user, smart_link)
|
||||||
|
|
||||||
return render_to_response('main/generic_list.html', {
|
return render_to_response('main/generic_list.html', {
|
||||||
'title': _(u'Conditions for smart link: %s') % smart_link,
|
'title': _(u'Conditions for smart link: %s') % smart_link,
|
||||||
'object_list': smart_link.smartlinkcondition_set.all(),
|
'object_list': smart_link.conditions.all(),
|
||||||
'extra_columns': [
|
'extra_columns': [
|
||||||
{'name': _(u'Enabled'), 'attribute': encapsulate(lambda x: two_state_template(x.enabled))},
|
{'name': _(u'Enabled'), 'attribute': encapsulate(lambda x: two_state_template(x.enabled))},
|
||||||
],
|
],
|
||||||
@@ -264,9 +235,9 @@ def smart_link_condition_create(request, smart_link_pk):
|
|||||||
smart_link = get_object_or_404(SmartLink, pk=smart_link_pk)
|
smart_link = get_object_or_404(SmartLink, pk=smart_link_pk)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT])
|
Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_EDIT])
|
||||||
except PermissionDenied:
|
except PermissionDenied:
|
||||||
AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT], request.user, smart_link)
|
AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_EDIT], request.user, smart_link)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = SmartLinkConditionForm(data=request.POST)
|
form = SmartLinkConditionForm(data=request.POST)
|
||||||
@@ -290,9 +261,9 @@ def smart_link_condition_edit(request, smart_link_condition_pk):
|
|||||||
smart_link_condition = get_object_or_404(SmartLinkCondition, pk=smart_link_condition_pk)
|
smart_link_condition = get_object_or_404(SmartLinkCondition, pk=smart_link_condition_pk)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT])
|
Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_EDIT])
|
||||||
except PermissionDenied:
|
except PermissionDenied:
|
||||||
AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT], request.user, smart_link_condition.smart_link)
|
AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_EDIT], request.user, smart_link_condition.smart_link)
|
||||||
|
|
||||||
next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', reverse('main:home'))))
|
next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', reverse('main:home'))))
|
||||||
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', reverse('main:home'))))
|
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', reverse('main:home'))))
|
||||||
@@ -325,9 +296,9 @@ def smart_link_condition_delete(request, smart_link_condition_pk):
|
|||||||
smart_link_condition = get_object_or_404(SmartLinkCondition, pk=smart_link_condition_pk)
|
smart_link_condition = get_object_or_404(SmartLinkCondition, pk=smart_link_condition_pk)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT])
|
Permission.objects.check_permissions(request.user, [PERMISSION_SMART_LINK_EDIT])
|
||||||
except PermissionDenied:
|
except PermissionDenied:
|
||||||
AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT], request.user, smart_link_condition.smart_link)
|
AccessEntry.objects.check_accesses([PERMISSION_SMART_LINK_EDIT], request.user, smart_link_condition.smart_link)
|
||||||
|
|
||||||
next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', reverse('main:home'))))
|
next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', reverse('main:home'))))
|
||||||
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', reverse('main:home'))))
|
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', reverse('main:home'))))
|
||||||
|
|||||||
Reference in New Issue
Block a user