Initial commit of the new class based and menu based navigation system

This commit is contained in:
Roberto Rosario
2015-04-03 07:09:51 -04:00
parent 192069462f
commit 0246068cd0
27 changed files with 399 additions and 485 deletions

View File

@@ -107,7 +107,7 @@
</div> </div>
<div id="navbar" class="navbar-collapse collapse"> <div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
{% get_top_menu_links %} {% get_top_menu_links as menu_links %}
{% for link in menu_links %} {% for link in menu_links %}
{% with 'true' as as_li %} {% with 'true' as as_li %}
{% with 'true' as hide_active_anchor %} {% with 'true' as hide_active_anchor %}
@@ -156,8 +156,10 @@
</div> </div>
</div> </div>
{% get_contextual_links as links %} {% get_action_links as links %}
{% get_object_facet_links as form_navigation_links %}
{% comment %}
{% if navigation_object_list %} {% if navigation_object_list %}
{% for navigation_object_dict in navigation_object_list %} {% for navigation_object_dict in navigation_object_list %}
{% copy_variable navigation_object_dict.object as "navigation_object_name" %} {% copy_variable navigation_object_dict.object as "navigation_object_name" %}
@@ -166,7 +168,7 @@
{% else %} {% else %}
{% get_object_navigation_links "form_header" as form_navigation_links %} {% get_object_navigation_links "form_header" as form_navigation_links %}
{% endif %} {% endif %}
{% endcomment %}
<div class="row"> <div class="row">
{% if links or form_navigation_links %} {% if links or form_navigation_links %}
<div class="col-xs-8 col-sm-8 col-md-10 col-lg-10"> <div class="col-xs-8 col-sm-8 col-md-10 col-lg-10">

View File

@@ -106,7 +106,12 @@
{% copy_variable list_object_variable_name as "navigation_object_name" %} {% copy_variable list_object_variable_name as "navigation_object_name" %}
{% endif %} {% endif %}
<td class="last"> <td class="last">
{% object_navigation_template %} {% get_object_links as links %}
{% with links as object_navigation_links %}
{% with 'true' as horizontal %}
{% include 'navigation/generic_navigation.html' %}
{% endwith %}
{% endwith %}
</td> </td>
{% endif %} {% endif %}
</tr> </tr>

View File

@@ -6,13 +6,14 @@ from django import apps
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions from acls.api import class_permissions
from common.menus import menu_main
from documents.models import Document from documents.models import Document
from mayan.celery import app from mayan.celery import app
from navigation.api import register_links, register_top_menu from navigation.api import register_links
from rest_api.classes import APIEndPoint from rest_api.classes import APIEndPoint
from .links import ( from .links import (
checkin_document, checkout_document, checkout_info, checkout_list checkin_document, checkout_document, checkout_info, link_checkout_list
) )
from .models import DocumentCheckout from .models import DocumentCheckout
from .permissions import ( from .permissions import (
@@ -51,6 +52,7 @@ class CheckoutsApp(apps.AppConfig):
register_links(Document, [checkout_info], menu_name='form_header') register_links(Document, [checkout_info], menu_name='form_header')
register_links(['checkouts:checkout_info', 'checkouts:checkout_document', 'checkouts:checkin_document'], [checkout_document, checkin_document], menu_name="sidebar") register_links(['checkouts:checkout_info', 'checkouts:checkout_document', 'checkouts:checkin_document'], [checkout_document, checkin_document], menu_name="sidebar")
register_top_menu(name='checkouts', link=checkout_list)
menu_main.bind_links(links=[link_checkout_list])
APIEndPoint('checkouts') APIEndPoint('checkouts')

View File

@@ -2,6 +2,8 @@ from __future__ import absolute_import, unicode_literals
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from navigation import Link
from .permissions import ( from .permissions import (
PERMISSION_DOCUMENT_CHECKOUT, PERMISSION_DOCUMENT_CHECKIN, PERMISSION_DOCUMENT_CHECKOUT, PERMISSION_DOCUMENT_CHECKIN,
PERMISSION_DOCUMENT_CHECKIN_OVERRIDE PERMISSION_DOCUMENT_CHECKIN_OVERRIDE
@@ -16,7 +18,7 @@ def is_not_checked_out(context):
return not context['object'].is_checked_out() return not context['object'].is_checked_out()
checkout_list = {'text': _('Checkouts'), 'view': 'checkouts:checkout_list', 'icon': 'fa fa-shopping-cart'} link_checkout_list = Link(icon='fa fa-shopping-cart', text=_('Checkouts'), view='checkouts:checkout_list')
checkout_document = {'text': _('Check out document'), 'view': 'checkouts:checkout_document', 'args': 'object.pk', 'famfam': 'basket_put', 'condition': is_not_checked_out, 'permissions': [PERMISSION_DOCUMENT_CHECKOUT]} checkout_document = {'text': _('Check out document'), 'view': 'checkouts:checkout_document', 'args': 'object.pk', 'famfam': 'basket_put', 'condition': is_not_checked_out, 'permissions': [PERMISSION_DOCUMENT_CHECKOUT]}
checkin_document = {'text': _('Check in document'), 'view': 'checkouts:checkin_document', 'args': 'object.pk', 'famfam': 'basket_remove', 'condition': is_checked_out, 'permissions': [PERMISSION_DOCUMENT_CHECKIN, PERMISSION_DOCUMENT_CHECKIN_OVERRIDE]} checkin_document = {'text': _('Check in document'), 'view': 'checkouts:checkin_document', 'args': 'object.pk', 'famfam': 'basket_remove', 'condition': is_checked_out, 'permissions': [PERMISSION_DOCUMENT_CHECKIN, PERMISSION_DOCUMENT_CHECKIN_OVERRIDE]}
checkout_info = {'text': _('Check in/out'), 'view': 'checkouts:checkout_info', 'args': 'object.pk', 'famfam': 'basket', 'permissions': [PERMISSION_DOCUMENT_CHECKIN, PERMISSION_DOCUMENT_CHECKIN_OVERRIDE, PERMISSION_DOCUMENT_CHECKOUT]} checkout_info = {'text': _('Check in/out'), 'view': 'checkouts:checkout_info', 'args': 'object.pk', 'famfam': 'basket', 'permissions': [PERMISSION_DOCUMENT_CHECKIN, PERMISSION_DOCUMENT_CHECKIN_OVERRIDE, PERMISSION_DOCUMENT_CHECKOUT]}

View File

@@ -12,7 +12,7 @@ from django.db.models.signals import post_migrate, post_save
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from common import settings as common_settings from common import settings as common_settings
from navigation.api import register_links, register_top_menu from navigation.api import register_links
from .links import ( from .links import (
link_about, link_current_user_details, link_current_user_edit, link_about, link_current_user_details, link_current_user_edit,
@@ -20,6 +20,7 @@ from .links import (
link_current_user_locale_profile_edit, link_license, link_logout, link_current_user_locale_profile_edit, link_license, link_logout,
link_password_change link_password_change
) )
from .menus import menu_main, menu_secondary
from .models import ( from .models import (
AnonymousUserSingleton, AutoAdminSingleton, UserLocaleProfile AnonymousUserSingleton, AutoAdminSingleton, UserLocaleProfile
) )
@@ -93,10 +94,11 @@ class CommonApp(apps.AppConfig):
verbose_name = _('Common') verbose_name = _('Common')
def ready(self): def ready(self):
register_links(['common:current_user_details', 'common:current_user_edit', 'common:current_user_locale_profile_details', 'common:current_user_locale_profile_edit', 'common:password_change_view'], [link_current_user_details, link_current_user_edit, link_current_user_locale_profile_details, link_current_user_locale_profile_edit, link_password_change, link_logout], menu_name='secondary_menu') menu_main.bind_links(links=[link_about], position=-1)
register_links(['common:about_view', 'common:license_view'], [link_about, link_license], menu_name='secondary_menu') menu_secondary.bind_links(links=[link_about, link_license], sources=['common:about_view', 'common:license_view'])
register_top_menu('about', link_about, position=-1) register_links(['common:current_user_details', 'common:current_user_edit', 'common:current_user_locale_profile_details', 'common:current_user_locale_profile_edit', 'common:password_change_view'], [link_current_user_details, link_current_user_edit, link_current_user_locale_profile_details, link_current_user_locale_profile_edit, link_password_change, link_logout], menu_name='secondary_menu')
#register_links(['common:about_view', 'common:license_view'], [link_about, link_license], menu_name='secondary_menu')
post_migrate.connect(create_superuser_and_anonymous_user, dispatch_uid='create_superuser_and_anonymous_user') post_migrate.connect(create_superuser_and_anonymous_user, dispatch_uid='create_superuser_and_anonymous_user')
post_save.connect(auto_admin_account_passwd_change, dispatch_uid='auto_admin_account_passwd_change', sender=User) post_save.connect(auto_admin_account_passwd_change, dispatch_uid='auto_admin_account_passwd_change', sender=User)

View File

@@ -2,18 +2,19 @@ from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from navigation import Link
def has_usable_password(context): def has_usable_password(context):
return context['request'].user.has_usable_password return context['request'].user.has_usable_password
link_about = Link(icon='fa fa-question', text=_('About'), view='common:about_view')
link_license = Link(icon='fa fa-book', text=_('License'), view='common:license_view')
link_password_change = {'text': _('Change password'), 'view': 'common:password_change_view', 'icon': 'fa fa-key', 'condition': has_usable_password} link_password_change = {'text': _('Change password'), 'view': 'common:password_change_view', 'icon': 'fa fa-key', 'condition': has_usable_password}
link_current_user_details = {'text': _('User details'), 'view': 'common:current_user_details', 'icon': 'fa fa-user'} link_current_user_details = {'text': _('User details'), 'view': 'common:current_user_details', 'icon': 'fa fa-user'}
link_current_user_edit = {'text': _('Edit details'), 'view': 'common:current_user_edit', 'icon': 'fa fa-user'} link_current_user_edit = {'text': _('Edit details'), 'view': 'common:current_user_edit', 'icon': 'fa fa-user'}
link_about = {'text': _('About'), 'view': 'common:about_view', 'icon': 'fa fa-question'}
link_license = {'text': _('License'), 'view': 'common:license_view', 'icon': 'fa fa-book'}
link_current_user_locale_profile_details = {'text': _('Locale profile'), 'view': 'common:current_user_locale_profile_details', 'icon': 'fa fa-globe'} link_current_user_locale_profile_details = {'text': _('Locale profile'), 'view': 'common:current_user_locale_profile_details', 'icon': 'fa fa-globe'}
link_current_user_locale_profile_edit = {'text': _('Edit locale profile'), 'view': 'common:current_user_locale_profile_edit', 'icon': 'fa fa-globe'} link_current_user_locale_profile_edit = {'text': _('Edit locale profile'), 'view': 'common:current_user_locale_profile_edit', 'icon': 'fa fa-globe'}

View File

@@ -0,0 +1,9 @@
from __future__ import unicode_literals
from navigation import Menu
menu_facet = Menu(name='object facet')
menu_object = Menu(name='object menu')
menu_main = Menu(name='main menu')
menu_secondary = Menu(name='secondary menu')
menu_sidebar = Menu(name='sidebar menu')

View File

@@ -4,18 +4,19 @@ from django import apps
from django.db.models.signals import post_save, post_delete from django.db.models.signals import post_save, post_delete
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from common.menus import menu_main
from documents.models import Document from documents.models import Document
from main.api import register_maintenance_links from main.api import register_maintenance_links
from metadata.models import DocumentMetadata from metadata.models import DocumentMetadata
from navigation.api import register_links, register_top_menu from navigation.api import register_links
from project_setup.api import register_setup from project_setup.api import register_setup
from rest_api.classes import APIEndPoint from rest_api.classes import APIEndPoint
from .links import ( from .links import (
document_index_list, document_index_main_menu_link, index_parent, document_index_list, link_index_main_menu, index_parent,
index_setup, index_setup_create, index_setup_document_types, index_setup, index_setup_create, index_setup_document_types,
index_setup_delete, index_setup_edit, index_setup_list, index_setup_view, index_setup_delete, index_setup_edit, index_setup_list, index_setup_view,
rebuild_index_instances, template_node_create, template_node_delete, link_rebuild_index_instances, template_node_create, template_node_delete,
template_node_edit template_node_edit
) )
from .models import Index, IndexTemplateNode, IndexInstanceNode from .models import Index, IndexTemplateNode, IndexInstanceNode
@@ -43,7 +44,7 @@ class DocumentIndexingApp(apps.AppConfig):
post_save.connect(document_metadata_index_update, dispatch_uid='document_metadata_index_update', sender=DocumentMetadata) post_save.connect(document_metadata_index_update, dispatch_uid='document_metadata_index_update', sender=DocumentMetadata)
post_delete.connect(document_metadata_index_post_delete, dispatch_uid='document_metadata_index_post_delete', sender=DocumentMetadata) post_delete.connect(document_metadata_index_post_delete, dispatch_uid='document_metadata_index_post_delete', sender=DocumentMetadata)
register_maintenance_links([rebuild_index_instances], namespace='document_indexing', title=_('Indexes')) register_maintenance_links([link_rebuild_index_instances], namespace='document_indexing', title=_('Indexes'))
register_links(Document, [document_index_list], menu_name='form_header') register_links(Document, [document_index_list], menu_name='form_header')
register_links([Index, 'indexing:index_setup_list', 'indexing:index_setup_create'], [index_setup_list, index_setup_create], menu_name='secondary_menu') register_links([Index, 'indexing:index_setup_list', 'indexing:index_setup_create'], [index_setup_list, index_setup_create], menu_name='secondary_menu')
@@ -53,6 +54,6 @@ class DocumentIndexingApp(apps.AppConfig):
register_setup(index_setup) register_setup(index_setup)
register_top_menu('indexes', document_index_main_menu_link) menu_main.bind_links(links=[link_index_main_menu])
APIEndPoint('indexes', app_name='document_indexing') APIEndPoint('indexes', app_name='document_indexing')

View File

@@ -3,6 +3,7 @@ from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from documents.permissions import PERMISSION_DOCUMENT_VIEW from documents.permissions import PERMISSION_DOCUMENT_VIEW
from navigation import Link
from .permissions import ( from .permissions import (
PERMISSION_DOCUMENT_INDEXING_CREATE, PERMISSION_DOCUMENT_INDEXING_EDIT, PERMISSION_DOCUMENT_INDEXING_CREATE, PERMISSION_DOCUMENT_INDEXING_EDIT,
@@ -20,6 +21,8 @@ def is_not_root_node(context):
return not context['node'].is_root_node() return not context['node'].is_root_node()
link_index_main_menu = Link(icon='fa fa-sitemap', text=_('Indexes'), view='indexing:index_list')
index_setup = {'text': _('Indexes'), 'view': 'indexing:index_setup_list', 'icon': 'fa fa-sitemap', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]} index_setup = {'text': _('Indexes'), 'view': 'indexing:index_setup_list', 'icon': 'fa fa-sitemap', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]}
index_setup_list = {'text': _('Indexes'), 'view': 'indexing:index_setup_list', 'famfam': 'tab', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]} index_setup_list = {'text': _('Indexes'), 'view': 'indexing:index_setup_list', 'famfam': 'tab', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]}
index_setup_create = {'text': _('Create index'), 'view': 'indexing:index_setup_create', 'famfam': 'tab_add', 'permissions': [PERMISSION_DOCUMENT_INDEXING_CREATE]} index_setup_create = {'text': _('Create index'), 'view': 'indexing:index_setup_create', 'famfam': 'tab_add', 'permissions': [PERMISSION_DOCUMENT_INDEXING_CREATE]}
@@ -37,6 +40,9 @@ index_list = {'text': _('Index list'), 'view': 'indexing:index_list', 'famfam':
index_parent = {'text': _('Go up one level'), 'view': 'indexing: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} index_parent = {'text': _('Go up one level'), 'view': 'indexing: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': _('Indexes'), 'view': 'indexing:document_index_list', 'args': 'object.pk', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_VIEW]} document_index_list = {'text': _('Indexes'), 'view': 'indexing:document_index_list', 'args': 'object.pk', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_VIEW]}
document_index_main_menu_link = {'text': _('Indexes'), 'icon': 'fa fa-sitemap', 'view': 'indexing:index_list'} # Maintenance
link_rebuild_index_instances = Link(
rebuild_index_instances = {'text': _('Rebuild indexes'), 'view': 'indexing:rebuild_index_instances', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES], 'description': _('Deletes and creates from scratch all the document indexes.')} permissions=[PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES],
description=_('Deletes and creates from scratch all the document indexes.'),
text=_('Rebuild indexes'), view='indexing:rebuild_index_instances'
)

View File

@@ -9,6 +9,7 @@ from actstream import registry
from acls.api import class_permissions from acls.api import class_permissions
from common.classes import ModelAttribute from common.classes import ModelAttribute
from common.menus import menu_facet, menu_object
from common.utils import encapsulate, validate_path from common.utils import encapsulate, validate_path
from dynamic_search.classes import SearchModel from dynamic_search.classes import SearchModel
from events.permissions import PERMISSION_EVENTS_VIEW from events.permissions import PERMISSION_EVENTS_VIEW
@@ -22,10 +23,10 @@ from statistics.classes import StatisticNamespace
from documents import settings as document_settings from documents import settings as document_settings
from .links import ( from .links import (
document_clear_image_cache, document_clear_transformations, link_clear_image_cache, link_document_clear_transformations,
document_content, document_delete, document_document_type_edit, link_document_content, link_document_delete, link_document_document_type_edit,
document_events_view, document_multiple_document_type_edit, link_document_events_view, document_multiple_document_type_edit,
document_download, document_edit, document_list, document_list_recent, link_document_download, link_document_edit, document_list, document_list_recent,
document_multiple_delete, document_multiple_clear_transformations, document_multiple_delete, document_multiple_clear_transformations,
document_multiple_download, document_multiple_update_page_count, document_multiple_download, document_multiple_update_page_count,
document_page_edit, document_page_navigation_first, document_page_edit, document_page_navigation_first,
@@ -35,13 +36,13 @@ from .links import (
document_page_transformation_list, document_page_transformation_create, document_page_transformation_list, document_page_transformation_create,
document_page_transformation_edit, document_page_transformation_delete, document_page_transformation_edit, document_page_transformation_delete,
document_page_view, document_page_view_reset, document_page_zoom_in, document_page_view, document_page_view_reset, document_page_zoom_in,
document_page_zoom_out, document_preview, document_print, document_page_zoom_out, link_document_preview, link_document_print,
document_properties, document_type_create, document_type_delete, link_document_properties, document_type_create, document_type_delete,
document_type_edit, document_type_filename_create, document_type_edit, document_type_filename_create,
document_type_filename_delete, document_type_filename_edit, document_type_filename_delete, document_type_filename_edit,
document_type_filename_list, document_type_list, document_type_setup, document_type_filename_list, document_type_list, document_type_setup,
document_update_page_count, document_version_download, link_document_update_page_count, document_version_download,
document_version_list, document_version_revert link_document_version_list, document_version_revert
) )
from .models import ( from .models import (
Document, DocumentPage, DocumentPageTransformation, DocumentType, Document, DocumentPage, DocumentPageTransformation, DocumentType,
@@ -69,13 +70,16 @@ class DocumentsApp(apps.AppConfig):
register_links(DocumentTypeFilename, [document_type_filename_edit, document_type_filename_delete]) register_links(DocumentTypeFilename, [document_type_filename_edit, document_type_filename_delete])
register_links([DocumentTypeFilename, 'documents:document_type_filename_list', 'documents:document_type_filename_create'], [document_type_filename_create], menu_name='sidebar') register_links([DocumentTypeFilename, 'documents:document_type_filename_list', 'documents:document_type_filename_create'], [document_type_filename_create], menu_name='sidebar')
# Register document links # Register document facet links
register_links(Document, [document_edit, document_document_type_edit, document_print, document_delete, document_download, document_clear_transformations, document_update_page_count]) menu_facet.bind_links(links=[link_document_preview], sources=[Document], position=0)
menu_facet.bind_links(links=[link_document_content], sources=[Document], position=1)
menu_facet.bind_links(links=[link_document_properties], sources=[Document], position=2)
menu_facet.bind_links(links=[link_document_events_view, link_document_version_list], sources=[Document], position=2)
# Document actions
menu_object.bind_links(links=[link_document_edit, link_document_document_type_edit, link_document_print, link_document_delete, link_document_download, link_document_clear_transformations, link_document_update_page_count], sources=[Document])
register_links([Document], [document_multiple_clear_transformations, document_multiple_delete, document_multiple_download, document_multiple_update_page_count, document_multiple_document_type_edit, link_spacer], menu_name='multi_item_links') register_links([Document], [document_multiple_clear_transformations, document_multiple_delete, document_multiple_download, document_multiple_update_page_count, document_multiple_document_type_edit, link_spacer], menu_name='multi_item_links')
register_links(Document, [document_preview], menu_name='form_header', position=0)
register_links(Document, [document_content], menu_name='form_header', position=1)
register_links(Document, [document_properties], menu_name='form_header', position=2)
register_links(Document, [document_events_view, document_version_list], menu_name='form_header')
# Document Version links # Document Version links
register_links(DocumentVersion, [document_version_revert, document_version_download]) register_links(DocumentVersion, [document_version_revert, document_version_download])
@@ -98,7 +102,7 @@ class DocumentsApp(apps.AppConfig):
register_links('documents:document_page_transformation_create', [document_page_transformation_create], menu_name='sidebar') register_links('documents:document_page_transformation_create', [document_page_transformation_create], menu_name='sidebar')
register_links(['documents:document_page_transformation_edit', 'documents:document_page_transformation_delete'], [document_page_transformation_create], menu_name='sidebar') register_links(['documents:document_page_transformation_edit', 'documents:document_page_transformation_delete'], [document_page_transformation_create], menu_name='sidebar')
register_maintenance_links([document_clear_image_cache], namespace='documents', title=_('Documents')) register_maintenance_links([link_clear_image_cache], namespace='documents', title=_('Documents'))
register_model_list_columns(Document, [ register_model_list_columns(Document, [
{ {
'name': _('Thumbnail'), 'attribute': 'name': _('Thumbnail'), 'attribute':

View File

@@ -3,6 +3,7 @@ from __future__ import absolute_import, unicode_literals
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from events.permissions import PERMISSION_EVENTS_VIEW from events.permissions import PERMISSION_EVENTS_VIEW
from navigation import Link
from .permissions import ( from .permissions import (
PERMISSION_DOCUMENT_PROPERTIES_EDIT, PERMISSION_DOCUMENT_VIEW, PERMISSION_DOCUMENT_PROPERTIES_EDIT, PERMISSION_DOCUMENT_VIEW,
@@ -37,28 +38,38 @@ def is_current_version(context):
return context['object'].document.latest_version.timestamp == context['object'].timestamp return context['object'].document.latest_version.timestamp == context['object'].timestamp
# Facet
link_document_preview = Link(permissions=[PERMISSION_DOCUMENT_VIEW], text=_('Preview'), view='documents:document_preview', args='object.id')
link_document_content = Link(permissions=[PERMISSION_DOCUMENT_VIEW], text=_('Content'), view='documents:document_content', args='object.id')
link_document_properties = Link(permissions=[PERMISSION_DOCUMENT_VIEW], text=_('Properties'), view='documents:document_properties', args='object.id')
link_document_events_view = Link(permissions=[PERMISSION_EVENTS_VIEW], text=_('Events'), view='events:events_for_object', args=['"documents"', '"document"', 'object.id'])
link_document_version_list = Link(permissions=[PERMISSION_DOCUMENT_VIEW], text=_('Versions'), view='documents:document_version_list', args='object.pk')
# Actions
link_document_clear_transformations = Link(permissions=[PERMISSION_DOCUMENT_TRANSFORM], text=_('Clear transformations'), view='documents:document_clear_transformations', args='object.id')
link_document_delete = Link(permissions=[PERMISSION_DOCUMENT_DELETE], text=_('Delete'), view='documents:document_delete', args='object.id')
link_document_edit = Link(permissions=[PERMISSION_DOCUMENT_PROPERTIES_EDIT], text=_('Edit properties'), view='documents:document_edit', args='object.id')
link_document_document_type_edit = Link(permissions=[PERMISSION_DOCUMENT_PROPERTIES_EDIT], text=_('Change type'), view='documents:document_document_type_edit', args='object.id')
link_document_download = Link(permissions=[PERMISSION_DOCUMENT_DOWNLOAD], text=_('Download'), view='documents:document_download', args='object.id')
link_document_print = Link(permissions=[PERMISSION_DOCUMENT_VIEW], text=_('Print'), view='documents:document_print', args='object.id')
link_document_update_page_count = Link(permissions=[PERMISSION_DOCUMENT_TOOLS], text=_('Reset page count'), view='documents:document_update_page_count', args='object.pk')
# Views
document_list = {'text': _('All documents'), 'view': 'documents:document_list', 'icon': 'fa fa-file'} document_list = {'text': _('All documents'), 'view': 'documents:document_list', 'icon': 'fa fa-file'}
document_list_recent = {'text': _('Recent documents'), 'view': 'documents:document_list_recent', 'icon': 'fa fa-clock-o'} document_list_recent = {'text': _('Recent documents'), 'view': 'documents:document_list_recent', 'icon': 'fa fa-clock-o'}
document_preview = {'text': _('Preview'), 'view': 'documents:document_preview', 'args': 'object.id', 'famfam': 'page', 'permissions': [PERMISSION_DOCUMENT_VIEW]}
document_content = {'text': _('Content'), 'view': 'documents:document_content', 'args': 'object.id', 'famfam': 'page_white_text', 'permissions': [PERMISSION_DOCUMENT_VIEW]}
document_properties = {'text': _('Properties'), 'view': 'documents:document_properties', 'args': 'object.id', 'famfam': 'page_gear', 'permissions': [PERMISSION_DOCUMENT_VIEW]}
document_delete = {'text': _('Delete'), 'view': 'documents:document_delete', 'args': 'object.id', 'famfam': 'page_delete', 'permissions': [PERMISSION_DOCUMENT_DELETE]}
document_multiple_delete = {'text': _('Delete'), 'view': 'documents:document_multiple_delete', 'famfam': 'page_delete', 'permissions': [PERMISSION_DOCUMENT_DELETE]} document_multiple_delete = {'text': _('Delete'), 'view': 'documents:document_multiple_delete', 'famfam': 'page_delete', 'permissions': [PERMISSION_DOCUMENT_DELETE]}
document_edit = {'text': _('Edit properties'), 'view': 'documents:document_edit', 'args': 'object.id', 'famfam': 'page_edit', 'permissions': [PERMISSION_DOCUMENT_PROPERTIES_EDIT]}
document_document_type_edit = {'text': _('Change type'), 'view': 'documents:document_document_type_edit', 'args': 'object.id', 'famfam': 'layout', 'permissions': [PERMISSION_DOCUMENT_PROPERTIES_EDIT]}
document_multiple_document_type_edit = {'text': _('Change type'), 'view': 'documents:document_multiple_document_type_edit', 'famfam': 'layout', 'permissions': [PERMISSION_DOCUMENT_PROPERTIES_EDIT]} document_multiple_document_type_edit = {'text': _('Change type'), 'view': 'documents:document_multiple_document_type_edit', 'famfam': 'layout', 'permissions': [PERMISSION_DOCUMENT_PROPERTIES_EDIT]}
document_download = {'text': _('Download'), 'view': 'documents:document_download', 'args': 'object.id', 'famfam': 'page_save', 'permissions': [PERMISSION_DOCUMENT_DOWNLOAD]}
document_multiple_download = {'text': _('Download'), 'view': 'documents:document_multiple_download', 'famfam': 'page_save', 'permissions': [PERMISSION_DOCUMENT_DOWNLOAD]} document_multiple_download = {'text': _('Download'), 'view': 'documents:document_multiple_download', 'famfam': 'page_save', 'permissions': [PERMISSION_DOCUMENT_DOWNLOAD]}
document_version_download = {'text': _('Download'), 'view': 'documents:document_version_download', 'args': 'object.pk', 'famfam': 'page_save', 'permissions': [PERMISSION_DOCUMENT_DOWNLOAD]} document_version_download = {'text': _('Download'), 'view': 'documents:document_version_download', 'args': 'object.pk', 'famfam': 'page_save', 'permissions': [PERMISSION_DOCUMENT_DOWNLOAD]}
document_update_page_count = {'text': _('Reset page count'), 'view': 'documents:document_update_page_count', 'args': 'object.pk', 'famfam': 'page_white_csharp', 'permissions': [PERMISSION_DOCUMENT_TOOLS]}
document_multiple_update_page_count = {'text': _('Reset page count'), 'view': 'documents:document_multiple_update_page_count', 'famfam': 'page_white_csharp', 'permissions': [PERMISSION_DOCUMENT_TOOLS]} document_multiple_update_page_count = {'text': _('Reset page count'), 'view': 'documents:document_multiple_update_page_count', 'famfam': 'page_white_csharp', 'permissions': [PERMISSION_DOCUMENT_TOOLS]}
document_clear_transformations = {'text': _('Clear transformations'), 'view': 'documents:document_clear_transformations', 'args': 'object.id', 'famfam': 'page_paintbrush', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]}
document_multiple_clear_transformations = {'text': _('Clear transformations'), 'view': 'documents:document_multiple_clear_transformations', 'famfam': 'page_paintbrush', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]} document_multiple_clear_transformations = {'text': _('Clear transformations'), 'view': 'documents:document_multiple_clear_transformations', 'famfam': 'page_paintbrush', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]}
document_print = {'text': _('Print'), 'view': 'documents:document_print', 'args': 'object.id', 'famfam': 'printer', 'permissions': [PERMISSION_DOCUMENT_VIEW]}
document_events_view = {'text': _('Events'), 'view': 'events:events_for_object', 'args': ['"documents"', '"document"', 'object.id'], 'famfam': 'book_go', 'permissions': [PERMISSION_EVENTS_VIEW]}
# Tools # Tools
document_clear_image_cache = {'text': _('Clear the document image cache'), 'view': 'documents:document_clear_image_cache', 'famfam': 'camera_delete', 'permissions': [PERMISSION_DOCUMENT_TOOLS], 'description': _('Clear the graphics representations used to speed up the documents\' display and interactive transformations results.')} link_clear_image_cache = Link(
description=_('Clear the graphics representations used to speed up the documents\' display and interactive transformations results.'),
permissions=[PERMISSION_DOCUMENT_TOOLS], text=_('Clear the document image cache'),
view='documents:document_clear_image_cache'
)
# Document pages # Document pages
document_page_transformation_list = {'text': _('Page transformations'), 'class': 'no-parent-history', 'view': 'documents:document_page_transformation_list', 'args': 'page.pk', 'famfam': 'pencil_go', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]} document_page_transformation_list = {'text': _('Page transformations'), 'class': 'no-parent-history', 'view': 'documents:document_page_transformation_list', 'args': 'page.pk', 'famfam': 'pencil_go', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]}
@@ -80,7 +91,6 @@ document_page_rotate_left = {'text': _('Rotate left'), 'class': 'no-parent-histo
document_page_view_reset = {'text': _('Reset view'), 'class': 'no-parent-history', 'view': 'documents:document_page_view_reset', 'args': 'page.pk', 'famfam': 'page_white', 'permissions': [PERMISSION_DOCUMENT_VIEW]} document_page_view_reset = {'text': _('Reset view'), 'class': 'no-parent-history', 'view': 'documents:document_page_view_reset', 'args': 'page.pk', 'famfam': 'page_white', 'permissions': [PERMISSION_DOCUMENT_VIEW]}
# Document versions # Document versions
document_version_list = {'text': _('Versions'), 'view': 'documents:document_version_list', 'args': 'object.pk', 'famfam': 'page_world', 'permissions': [PERMISSION_DOCUMENT_VIEW]}
document_version_revert = {'text': _('Revert'), 'view': 'documents:document_version_revert', 'args': 'object.pk', 'famfam': 'page_refresh', 'permissions': [PERMISSION_DOCUMENT_VERSION_REVERT], 'conditional_disable': is_current_version} document_version_revert = {'text': _('Revert'), 'view': 'documents:document_version_revert', 'args': 'object.pk', 'famfam': 'page_refresh', 'permissions': [PERMISSION_DOCUMENT_VERSION_REVERT], 'conditional_disable': is_current_version}
# Document type related links # Document type related links

View File

@@ -5,18 +5,18 @@ from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions from acls.api import class_permissions
from acls.permissions import ACLS_EDIT_ACL, ACLS_VIEW_ACL from acls.permissions import ACLS_EDIT_ACL, ACLS_VIEW_ACL
from common.menus import menu_secondary, menu_object, menu_main
from common.utils import encapsulate from common.utils import encapsulate
from documents.models import Document from documents.models import Document
from navigation.api import ( from navigation.api import register_links, register_model_list_columns
register_links, register_model_list_columns, register_top_menu
)
from navigation.links import link_spacer from navigation.links import link_spacer
from rest_api.classes import APIEndPoint from rest_api.classes import APIEndPoint
from .links import ( from .links import (
document_folder_list, folder_acl_list, folder_add_document, link_folder_list,
folder_add_multiple_documents, folder_create, folder_delete, document_folder_list, link_folder_acl_list, folder_add_document,
folder_document_multiple_remove, folder_edit, folder_list, folder_view folder_add_multiple_documents, link_folder_create, link_folder_delete,
folder_document_multiple_remove, link_folder_edit, link_folder_view
) )
from .models import Folder from .models import Folder
from .permissions import ( from .permissions import (
@@ -31,13 +31,13 @@ class FoldersApp(apps.AppConfig):
verbose_name = _('Folders') verbose_name = _('Folders')
def ready(self): def ready(self):
register_links(Folder, [folder_view, folder_edit, folder_acl_list, folder_delete]) menu_main.bind_links(links=[link_folder_list])
register_links([Folder, 'folders:folder_list', 'folders:folder_create'], [folder_list, folder_create], menu_name='secondary_menu') menu_secondary.bind_links(links=[link_folder_list, link_folder_create], sources=[Folder, 'folders:folder_list', 'folders:folder_create'])
register_links(['folders:document_folder_list', 'folders:folder_add_document'], [folder_add_document], menu_name="sidebar") menu_object.bind_links(links=[link_folder_view, link_folder_edit, link_folder_acl_list, link_folder_delete], sources=[Folder])
register_links(Document, [document_folder_list], menu_name='form_header')
register_links([Document], [folder_add_multiple_documents, folder_document_multiple_remove, link_spacer], menu_name='multi_item_links')
register_top_menu(name='folders', link=folder_list) #register_links(['folders:document_folder_list', 'folders:folder_add_document'], [folder_add_document], menu_name="sidebar")
#register_links(Document, [document_folder_list], menu_name='form_header')
#register_links([Document], [folder_add_multiple_documents, folder_document_multiple_remove, link_spacer], menu_name='multi_item_links')
class_permissions(Folder, [ class_permissions(Folder, [
ACLS_EDIT_ACL, ACLS_VIEW_ACL, PERMISSION_FOLDER_DELETE, ACLS_EDIT_ACL, ACLS_VIEW_ACL, PERMISSION_FOLDER_DELETE,

View File

@@ -4,6 +4,7 @@ from django.utils.translation import ugettext_lazy as _
from acls.permissions import ACLS_VIEW_ACL from acls.permissions import ACLS_VIEW_ACL
from documents.permissions import PERMISSION_DOCUMENT_VIEW from documents.permissions import PERMISSION_DOCUMENT_VIEW
from navigation import Link
from .permissions import ( from .permissions import (
PERMISSION_FOLDER_ADD_DOCUMENT, PERMISSION_FOLDER_CREATE, PERMISSION_FOLDER_ADD_DOCUMENT, PERMISSION_FOLDER_CREATE,
@@ -11,14 +12,16 @@ from .permissions import (
PERMISSION_FOLDER_REMOVE_DOCUMENT PERMISSION_FOLDER_REMOVE_DOCUMENT
) )
folder_list = {'text': _('Folders'), 'view': 'folders:folder_list', 'icon': 'fa fa-folder'} link_folder_create = Link(permissions=[PERMISSION_FOLDER_CREATE], text=_('Create folder'), view='folders:folder_create')
folder_create = {'text': _('Create folder'), 'view': 'folders:folder_create', 'famfam': 'folder_add', 'permissions': [PERMISSION_FOLDER_CREATE]} link_folder_list = Link(icon='fa fa-folder', text=_('Folders'), view='folders:folder_list')
folder_edit = {'text': _('Edit'), 'view': 'folders:folder_edit', 'args': 'object.pk', 'famfam': 'folder_edit', 'permissions': [PERMISSION_FOLDER_EDIT]}
folder_delete = {'text': _('Delete'), 'view': 'folders:folder_delete', 'args': 'object.pk', 'famfam': 'folder_delete', 'permissions': [PERMISSION_FOLDER_DELETE]} link_folder_edit = Link(permissions=[PERMISSION_FOLDER_EDIT], text=_('Edit'), view='folders:folder_edit', args='object.pk')
link_folder_delete = Link(permissions=[PERMISSION_FOLDER_DELETE], text=_('Delete'), view='folders:folder_delete', args='object.pk')
link_folder_view = Link(permissions=[PERMISSION_FOLDER_VIEW], text=_('Documents'), view='folders:folder_view', args='object.pk')
link_folder_acl_list = Link(permissions=[ACLS_VIEW_ACL], text=_('ACLs'), view='folders:folder_acl_list', args='object.pk')
folder_document_multiple_remove = {'text': _('Remove from folder'), 'view': 'folders:folder_document_multiple_remove', 'args': 'object.pk', 'famfam': 'folder_delete', 'permissions': [PERMISSION_FOLDER_REMOVE_DOCUMENT]} folder_document_multiple_remove = {'text': _('Remove from folder'), 'view': 'folders:folder_document_multiple_remove', 'args': 'object.pk', 'famfam': 'folder_delete', 'permissions': [PERMISSION_FOLDER_REMOVE_DOCUMENT]}
folder_view = {'text': _('Documents'), 'view': 'folders:folder_view', 'args': 'object.pk', 'famfam': 'page', 'permissions': [PERMISSION_FOLDER_VIEW]}
folder_add_document = {'text': _('Add to a folder'), 'view': 'folders:folder_add_document', 'args': 'object.pk', 'famfam': 'folder_add', 'permissions': [PERMISSION_FOLDER_ADD_DOCUMENT]} folder_add_document = {'text': _('Add to a folder'), 'view': 'folders:folder_add_document', 'args': 'object.pk', 'famfam': 'folder_add', 'permissions': [PERMISSION_FOLDER_ADD_DOCUMENT]}
folder_add_multiple_documents = {'text': _('Add to folder'), 'view': 'folders:folder_add_multiple_documents', 'famfam': 'folder_add'} folder_add_multiple_documents = {'text': _('Add to folder'), 'view': 'folders:folder_add_multiple_documents', 'famfam': 'folder_add'}
document_folder_list = {'text': _('Folders'), 'view': 'folders:document_folder_list', 'args': 'object.pk', 'famfam': 'folder_user', 'permissions': [PERMISSION_DOCUMENT_VIEW]} document_folder_list = {'text': _('Folders'), 'view': 'folders:document_folder_list', 'args': 'object.pk', 'famfam': 'folder_user', 'permissions': [PERMISSION_DOCUMENT_VIEW]}
folder_acl_list = {'text': _('ACLs'), 'view': 'folders:folder_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]}

View File

@@ -10,6 +10,5 @@ def register_maintenance_links(links, title=None, namespace=None):
namespace_dict = tools.get(namespace, {'title': None, 'links': []}) namespace_dict = tools.get(namespace, {'title': None, 'links': []})
namespace_dict['title'] = title namespace_dict['title'] = title
for link in links: for link in links:
link['url'] = link.get('url', reverse_lazy(link['view']))
namespace_dict['links'].append(link) namespace_dict['links'].append(link)
tools[namespace] = namespace_dict tools[namespace] = namespace_dict

View File

@@ -3,7 +3,6 @@ from __future__ import unicode_literals
from django import apps from django import apps
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from navigation.api import register_top_menu
from project_setup.api import register_setup from project_setup.api import register_setup
from project_tools.api import register_tool from project_tools.api import register_tool

View File

@@ -44,12 +44,9 @@ def maintenance_menu(request):
} }
user_tools[namespace].setdefault('links', []) user_tools[namespace].setdefault('links', [])
for link in values['links']: for link in values['links']:
try: resolved_link = link.resolve(context=RequestContext(request))
permissions = link.get('permissions', []) if resolved_link:
Permission.objects.check_permissions(request.user, permissions) user_tools[namespace]['links'].append(resolved_link)
user_tools[namespace]['links'].append(link)
except PermissionDenied:
pass
return render_to_response('appearance/tools.html', { return render_to_response('appearance/tools.html', {
'blocks': user_tools, 'blocks': user_tools,

View File

@@ -0,0 +1 @@
from .classes import Link, Menu # NOQA

View File

@@ -2,7 +2,6 @@ from __future__ import unicode_literals
object_navigation = {} object_navigation = {}
model_list_columns = {} model_list_columns = {}
top_menu_entries = []
def register_links(src, links, menu_name=None, position=None): def register_links(src, links, menu_name=None, position=None):
@@ -28,31 +27,6 @@ def register_links(src, links, menu_name=None, position=None):
object_navigation[menu_name][src]['links'].extend(links) object_navigation[menu_name][src]['links'].extend(links)
def register_top_menu(name, link, position=None):
"""
Register a new menu entry for the main menu displayed at the top
of the page
"""
entry = {'link': link, 'name': name}
if position is not None:
entry['position'] = position
top_menu_entries.insert(position, entry)
else:
length = len(top_menu_entries)
entry['position'] = length
top_menu_entries.append(entry)
sort_menu_entries()
return entry
def sort_menu_entries():
global top_menu_entries
top_menu_entries = sorted(top_menu_entries, key=lambda k: (k['position'] < 0, k['position']))
def register_model_list_columns(model, columns): def register_model_list_columns(model, columns):
""" """
Define which columns will be displayed in the generic list template Define which columns will be displayed in the generic list template

View File

@@ -5,6 +5,7 @@ import logging
import urllib import urllib
import urlparse import urlparse
from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import NoReverseMatch, resolve, reverse from django.core.urlresolvers import NoReverseMatch, resolve, reverse
from django.template import VariableDoesNotExist, Variable from django.template import VariableDoesNotExist, Variable
from django.utils.encoding import smart_str, smart_unicode from django.utils.encoding import smart_str, smart_unicode
@@ -12,34 +13,125 @@ from django.utils.http import urlencode, urlquote
from django.utils.text import unescape_string_literal from django.utils.text import unescape_string_literal
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from permissions.models import Permission
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class ResolvedLink(object): class ResolvedLink(object):
active = False active = False
url = '#' description = None
icon = None
text = _('Unnamed link') text = _('Unnamed link')
url = '#'
class Menu(object):
_registry = {}
@classmethod
def get(cls, name):
return cls._registry[name]
def __init__(self, name):
if name in self.__class__._registry:
raise Exception('A menu with this name already exists')
self.name = name
self.bound_links = {}
self.__class__._registry[name] = self
def bind_links(self, links, sources=None, position=0):
"""
Associate a link to a model, a view, or an url inside this menu
"""
if sources:
for source in sources:
source_links = self.bound_links.setdefault(source, [])
source_links.extend(links)
else:
# Unsourced links display always
source_links = self.bound_links.setdefault(None, [])
source_links.extend(links)
def resolve(self, context):
result = []
request = Variable('request').resolve(context)
current_path = request.META['PATH_INFO']
# Get sources: view name, view objects
current_view = resolve(current_path).view_name
resolved_navigation_object_list = []
navigation_object_list = context.get('navigation_object_list', [{'object': 'object'}])
# Multiple objects
for navigation_object in navigation_object_list:
try:
resolved_navigation_object_list.append(Variable(navigation_object['object']).resolve(context))
except VariableDoesNotExist:
pass
# Main menu links
for link in self.bound_links.get(None, []):
result.append(link.resolve(context))
for resolved_navigation_object in resolved_navigation_object_list:
for source, links in self.bound_links.iteritems():
if inspect.isclass(source) and isinstance(resolved_navigation_object, source) or Combined(obj=type(resolved_navigation_object), view=current_view) == source:
for link in links:
result.append(link.resolve(context))
#break # No need for further content object match testing
return result
class Link(object): class Link(object):
bound_links = {}
@classmethod @classmethod
def bind_links(cls, sources, links, menu_name=None, position=0): def resolve_template_variable(cls, context, name):
"""
Associate a link to a model, a view, or an url
"""
cls.bound_links.setdefault(menu_name, {})
try: try:
for source in sources: return unescape_string_literal(name)
cls.bound_links[menu_name].setdefault(source, {'links': []}) except ValueError:
try: #return Variable(name).resolve(context)
cls.bound_links[menu_name][source]['links'].extend(links) #TODO: Research if should return always as a str
except TypeError: return str(Variable(name).resolve(context))
# Try to see if links is a single link
cls.bound_links[menu_name][source]['links'].append(links)
except TypeError: except TypeError:
raise Exception('The bind_links source argument must be a list, even for single element sources.') return name
@classmethod
def resolve_arguments(cls, context, src_args):
args = []
kwargs = {}
if isinstance(src_args, list):
for i in src_args:
try:
# Try to execute as a function
val = i(context=context)
except TypeError:
val = Link.resolve_template_variable(context, i)
if val:
args.append(val)
else:
args.append(val)
elif isinstance(src_args, dict):
for key, value in src_args.items():
try:
# Try to execute as a function
val = i(context=context)
except TypeError:
val = Link.resolve_template_variable(context, value)
if val:
kwargs[key] = val
else:
kwargs[key] = val
else:
val = Link.resolve_template_variable(context, src_args)
if val:
args.append(val)
return args, kwargs
def __init__(self, text, view, klass=None, args=None, icon=None, def __init__(self, text, view, klass=None, args=None, icon=None,
permissions=None, condition=None, conditional_disable=None, permissions=None, condition=None, conditional_disable=None,
@@ -60,89 +152,67 @@ class Link(object):
self.keep_query = keep_query self.keep_query = keep_query
self.conditional_highlight = conditional_highlight # Used by dynamic sources self.conditional_highlight = conditional_highlight # Used by dynamic sources
def resolve(self, context, request=None, current_path=None, current_view=None, resolved_object=None): def resolve(self, context):
# Don't calculate these if passed in an argument request = Variable('request').resolve(context)
request = request or Variable('request').resolve(context) current_path = request.META['PATH_INFO']
current_path = current_path or request.META['PATH_INFO'] current_view = resolve(current_path).view_name
if not current_view:
match = resolve(current_path)
if match.namespace:
current_view = '{}:{}'.format(match.namespace, match.url_name)
else:
current_view = match.url_name
# Preserve unicode data in URL query if self.permissions:
previous_path = smart_unicode(urllib.unquote_plus(smart_str(request.get_full_path()) or smart_str(request.META.get('HTTP_REFERER', reverse('main:home'))))) try:
query_string = urlparse.urlparse(previous_path).query Permission.objects.check_permissions(request.user, self.permissions)
parsed_query_string = urlparse.parse_qs(query_string) except PermissionDenied:
return None
logger.debug('condition: %s', self.condition)
if resolved_object:
context['resolved_object'] = resolved_object
# Check to see if link has conditional display # Check to see if link has conditional display
if self.condition: if self.condition:
self.condition_result = self.condition(context) if not self.condition(context):
else: return None
self.condition_result = True
logger.debug('self.condition_result: %s', self.condition_result) #logger.debug('self.condition_result: %s', self.condition_result)
if self.condition_result: resolved_link = ResolvedLink()
resolved_link = ResolvedLink() resolved_link.text = self.text
resolved_link.text = self.text resolved_link.icon = self.icon
resolved_link.icon = self.icon resolved_link.description = self.description
resolved_link.permissions = self.permissions #resolved_link.permissions = self.permissions
resolved_link.condition_result = self.condition_result #resolved_link.condition_result = self.condition_result
try: #django/template/defaulttags.py
#args, kwargs = resolve_arguments(context, self.get('args', {}))
args, kwargs = Link.resolve_arguments(context, self.args)
except VariableDoesNotExist:
args = []
kwargs = {}
if self.view: #class URLNode(Node):
if not self.dont_mark_active:
resolved_link.active = self.view == current_view
try: #def __init__(self, view_name, args, kwargs, asvar):
if kwargs: # self.view_name = view_name
resolved_link.url = reverse(self.view, kwargs=kwargs) # self.args = args
else: # self.kwargs = kwargs
resolved_link.url = reverse(self.view, args=args) # self.asvar = asvar
if self.keep_query: # def render(self, context):
resolved_link.url = '%s?%s' % (urlquote(resolved_link.url), urlencode(parsed_query_string, doseq=True))
except NoReverseMatch, exc: try:
resolved_link.url = '#' args, kwargs = Link.resolve_arguments(context, self.args)
resolved_link.error = exc except VariableDoesNotExist:
elif self.url: args = []
if not self.dont_mark_active: kwargs = {}
resolved_link.url.active = self.url == current_path
if kwargs: if not self.dont_mark_active:
resolved_link.url = self.url % kwargs resolved_link.active = self.view == current_view
else:
resolved_link.url = self.url % args try:
if self.keep_query: if kwargs:
resolved_link.url = '%s?%s' % (urlquote(resolved_link.url), urlencode(parsed_query_string, doseq=True)) resolved_link.url = reverse(self.view, kwargs=kwargs)
else: else:
resolved_link.active = False resolved_link.url = reverse(self.view, args=args)
if self.keep_query:
resolved_link.url = '%s?%s' % (urlquote(resolved_link.url), urlencode(parsed_query_string, doseq=True))
if self.conditional_highlight: except NoReverseMatch, exc:
resolved_link.active = self.conditional_highlight(context) resolved_link.url = '#'
resolved_link.error = exc
if self.conditional_disable:
resolved_link.disabled = self.conditional_disable(context)
else:
resolved_link.disabled = False
# TODO: add tree base main menu support to auto activate parent links return resolved_link
return resolved_link
'''
@classmethod @classmethod
def get_context_navigation_links(cls, context, menu_name=None, links_dict=None): def get_context_navigation_links(cls, context, menu_name=None, links_dict=None):
request = Variable('request').resolve(context) request = Variable('request').resolve(context)
@@ -237,52 +307,92 @@ class Link(object):
objects[resolved_object]['label'] = object_label objects[resolved_object]['label'] = object_label
return objects return objects
'''
@classmethod '''
def resolve_template_variable(cls, context, name): def resolve(self, context, request=None, current_path=None, current_view=None, resolved_object=None):
try: # Don't calculate these if passed in an argument
return unescape_string_literal(name) request = request or Variable('request').resolve(context)
except ValueError: current_path = current_path or request.META['PATH_INFO']
#return Variable(name).resolve(context) if not current_view:
#TODO: Research if should return always as a str match = resolve(current_path)
return str(Variable(name).resolve(context)) if match.namespace:
except TypeError: current_view = '{}:{}'.format(match.namespace, match.url_name)
return name else:
current_view = match.url_name
@classmethod # Preserve unicode data in URL query
def resolve_arguments(cls, context, src_args): previous_path = smart_unicode(urllib.unquote_plus(smart_str(request.get_full_path()) or smart_str(request.META.get('HTTP_REFERER', reverse('main:home')))))
args = [] query_string = urlparse.urlparse(previous_path).query
kwargs = {} parsed_query_string = urlparse.parse_qs(query_string)
if isinstance(src_args, list): logger.debug('condition: %s', self.condition)
for i in src_args:
try: if resolved_object:
# Try to execute as a function context['resolved_object'] = resolved_object
val = i(context=context)
except TypeError: # Check to see if link has conditional display
val = Link.resolve_template_variable(context, i) if self.condition:
if val: self.condition_result = self.condition(context)
args.append(val)
else:
args.append(val)
elif isinstance(src_args, dict):
for key, value in src_args.items():
try:
# Try to execute as a function
val = i(context=context)
except TypeError:
val = Link.resolve_template_variable(context, value)
if val:
kwargs[key] = val
else:
kwargs[key] = val
else: else:
val = Link.resolve_template_variable(context, src_args) self.condition_result = True
if val:
args.append(val)
return args, kwargs logger.debug('self.condition_result: %s', self.condition_result)
if self.condition_result:
resolved_link = ResolvedLink()
resolved_link.text = self.text
resolved_link.icon = self.icon
resolved_link.permissions = self.permissions
resolved_link.condition_result = self.condition_result
try:
#args, kwargs = resolve_arguments(context, self.get('args', {}))
args, kwargs = Link.resolve_arguments(context, self.args)
except VariableDoesNotExist:
args = []
kwargs = {}
if self.view:
if not self.dont_mark_active:
resolved_link.active = self.view == current_view
try:
if kwargs:
resolved_link.url = reverse(self.view, kwargs=kwargs)
else:
resolved_link.url = reverse(self.view, args=args)
if self.keep_query:
resolved_link.url = '%s?%s' % (urlquote(resolved_link.url), urlencode(parsed_query_string, doseq=True))
except NoReverseMatch, exc:
resolved_link.url = '#'
resolved_link.error = exc
elif self.url:
if not self.dont_mark_active:
resolved_link.url.active = self.url == current_path
if kwargs:
resolved_link.url = self.url % kwargs
else:
resolved_link.url = self.url % args
if self.keep_query:
resolved_link.url = '%s?%s' % (urlquote(resolved_link.url), urlencode(parsed_query_string, doseq=True))
else:
resolved_link.active = False
if self.conditional_highlight:
resolved_link.active = self.conditional_highlight(context)
if self.conditional_disable:
resolved_link.disabled = self.conditional_disable(context)
else:
resolved_link.disabled = False
# TODO: add tree base main menu support to auto activate parent links
return resolved_link
'''
class ModelListColumn(object): class ModelListColumn(object):
_model_list_columns = {} _model_list_columns = {}

View File

@@ -15,270 +15,46 @@ from django.utils.text import unescape_string_literal
from common.utils import urlquote from common.utils import urlquote
from ..api import object_navigation, top_menu_entries from ..api import object_navigation
from ..classes import Menu
from ..forms import MultiItemForm from ..forms import MultiItemForm
register = Library() register = Library()
class TopMenuNavigationNode(Node): @register.assignment_tag(takes_context=True)
def render(self, context): def get_top_menu_links(context):
request = Variable('request').resolve(context) return Menu.get('main menu').resolve(context=context)
current_path = request.META['PATH_INFO']
current_view = resolve(current_path).view_name
all_menu_links = [entry.get('link', {}) for entry in top_menu_entries]
menu_links = resolve_links(context, all_menu_links, current_view, current_path)
context['menu_links'] = menu_links
return ''
@register.tag @register.assignment_tag(takes_context=True)
def get_top_menu_links(parser, token): def get_object_facet_links(context):
return TopMenuNavigationNode() return Menu.get('object facet').resolve(context=context)
def resolve_arguments(context, src_args): @register.assignment_tag(takes_context=True)
args = [] def get_action_links(context):
kwargs = {} result = []
if isinstance(src_args, list):
for i in src_args:
val = resolve_template_variable(context, i)
if val:
args.append(val)
elif isinstance(src_args, dict):
for key, value in src_args.items():
val = resolve_template_variable(context, value)
if val:
kwargs[key] = val
else:
val = resolve_template_variable(context, src_args)
if val:
args.append(val)
return args, kwargs for menu_name in ['object menu', 'sidebar menu', 'secondary menu']:
links = Menu.get(name=menu_name).resolve(context)
if links:
result.append(links)
return result
def resolve_links(context, links, current_view, current_path, parsed_query_string=None):
"""
Express a list of links from definition to final values
"""
context_links = []
for link in links:
# Check to see if link has conditional display
if 'condition' in link:
condition_result = link['condition'](context)
else:
condition_result = True
if condition_result:
new_link = copy.copy(link)
try:
args, kwargs = resolve_arguments(context, link.get('args', {}))
except VariableDoesNotExist:
args = []
kwargs = {}
if 'view' in link:
if not link.get('dont_mark_active', False):
new_link['active'] = link['view'] == current_view
try:
if kwargs:
new_link['url'] = reverse(link['view'], kwargs=kwargs)
else:
new_link['url'] = reverse(link['view'], args=args)
if link.get('keep_query', False):
try:
for key in link.get('remove_from_query', []):
del parsed_query_string[key]
except KeyError:
# We were asked to remove a key not found in the
# query string, that is not fatal
pass
new_link['url'] = urlquote(new_link['url'], parsed_query_string)
except NoReverseMatch as exception:
new_link['url'] = '#'
new_link['error'] = exception
elif 'url' in link:
if not link.get('dont_mark_active', False):
new_link['active'] = link['url'] == current_path
if kwargs:
new_link['url'] = link['url'] % kwargs
else:
new_link['url'] = link['url'] % args
if link.get('keep_query', False):
try:
for key in link.get('remove_from_query', []):
del parsed_query_string[key]
except KeyError:
# We were asked to remove a key not found in the
# query string, that is not fatal
pass
new_link['url'] = urlquote(new_link['url'], parsed_query_string)
else:
new_link['active'] = False
if 'conditional_highlight' in link:
new_link['active'] = link['conditional_highlight'](context)
if 'conditional_disable' in link:
new_link['disabled'] = link['conditional_disable'](context)
else:
new_link['disabled'] = False
context_links.append(new_link)
return context_links
def get_navigation_object(context, object_name=None):
if not object_name:
try:
object_name = Variable('navigation_object_name').resolve(context)
except VariableDoesNotExist:
object_name = 'object'
try:
obj = Variable(object_name).resolve(context)
except VariableDoesNotExist:
obj = None
return obj, object_name
def _get_object_navigation_links(context, menu_name=None, links_dict=object_navigation, obj=None, object_name=None):
request = Variable('request').resolve(context)
current_path = request.META['PATH_INFO']
current_view = resolve(current_path).view_name
context_links = []
# Don't fudge with the original global dictionary
links_dict = links_dict.copy()
# Preserve unicode data in URL query
previous_path = smart_unicode(urllib.unquote_plus(smart_str(request.get_full_path()) or smart_str(request.META.get('HTTP_REFERER', reverse('main:home')))))
query_string = urlparse.urlparse(previous_path).query
parsed_query_string = urlparse.parse_qs(query_string)
try:
# Check for an inject temporary navigation dictionary
temp_navigation_links = Variable('extra_navigation_links').resolve(context)
except VariableDoesNotExist:
pass
else:
if temp_navigation_links:
links_dict.update(temp_navigation_links)
# Match view links
try:
links = links_dict[menu_name][current_view]['links']
for link in resolve_links(context, links, current_view, current_path, parsed_query_string):
context_links.append(link)
except KeyError:
pass
if not obj:
obj, object_name = get_navigation_object(context, object_name=object_name)
# Match context navigation object links
for source, data in links_dict[menu_name].items():
if inspect.isclass(source) and isinstance(obj, source):
for link in resolve_links(context, data['links'], current_view, current_path, parsed_query_string):
context_links.append(link)
break
return context_links
def resolve_template_variable(context, name):
try:
return unescape_string_literal(name)
except ValueError:
# return Variable(name).resolve(context)
# TODO: Research if should return always as a str
return str(Variable(name).resolve(context))
except TypeError:
return name
class GetNavigationLinks(Node):
def __init__(self, menu_name=None, links_dict=object_navigation, var_name='object_navigation_links'):
self.menu_name = menu_name
self.links_dict = links_dict
self.var_name = var_name
def render(self, context):
menu_name = resolve_template_variable(context, self.menu_name)
context[self.var_name] = _get_object_navigation_links(context, menu_name, links_dict=self.links_dict)
obj, object_name = get_navigation_object(context)
context['navigation_object'] = obj
return ''
@register.tag
def get_object_navigation_links(parser, token):
tag_name, arg = token.contents.split(None, 1)
m = re.search(r'("?\w+"?)?.?as (\w+)', arg)
if not m:
raise TemplateSyntaxError('%r tag had invalid arguments' % tag_name)
menu_name, var_name = m.groups()
return GetNavigationLinks(menu_name=menu_name, var_name=var_name)
@register.inclusion_tag('navigation/generic_navigation.html', takes_context=True)
def object_navigation_template(context):
new_context = copy.copy(context)
new_context.update({
'horizontal': True,
'object_navigation_links': _get_object_navigation_links(context)
})
return new_context
@register.simple_tag(takes_context=True) @register.simple_tag(takes_context=True)
def get_multi_item_links_form(context, object_list=None): def get_multi_item_links_form(context, object_list):
if object_list: first_object = object_list[0]
first_object = object_list[0]
else: actions = []#(link.url, link.text) for link in Menu.get('multi items').resolve(context=context, obj=first_object)]
first_object = None
actions = [(link['url'], link['text']) for link in _get_object_navigation_links(context, menu_name='multi_item_links', obj=first_object)]
form = MultiItemForm(actions=actions) form = MultiItemForm(actions=actions)
context.update({'multi_item_form': form, 'multi_item_actions': actions}) context.update({'multi_item_form': form, 'multi_item_actions': actions})
return '' return ''
def get_navigation_links(context, menu_name=None, links_dict=object_navigation, object_name=None):
return _get_object_navigation_links(context=context, menu_name=menu_name, links_dict=links_dict, object_name=object_name)
@register.assignment_tag(takes_context=True) @register.assignment_tag(takes_context=True)
def get_contextual_links(context): def get_object_links(context):
result = [] return Menu.get('object menu').resolve(context=context)
navigation_object_list = context.get('navigation_object_list', [])
if navigation_object_list:
for navigation_object in context.get('navigation_object_list', []):
links = get_navigation_links(context, object_name=navigation_object['object'])
if links:
result.append(links)
else:
links = get_navigation_links(context)
if links:
result.append(links)
links = get_navigation_links(context, menu_name='sidebar')
if links:
result.append(links)
links = get_navigation_links(context, menu_name='secondary_menu')
if links:
result.append(links)
return result

View File

@@ -2,6 +2,8 @@ from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from navigation import Link
from .permissions import ( from .permissions import (
PERMISSION_OCR_CLEAN_ALL_PAGES, PERMISSION_OCR_DOCUMENT, PERMISSION_OCR_CLEAN_ALL_PAGES, PERMISSION_OCR_DOCUMENT,
PERMISSION_OCR_DOCUMENT_DELETE PERMISSION_OCR_DOCUMENT_DELETE
@@ -14,6 +16,10 @@ link_entry_re_queue_multiple = {'text': _('Re-queue'), 'view': 'ocr:entry_re_que
link_entry_delete = {'text': _('Delete'), 'view': 'ocr:entry_delete', 'args': 'object.id', 'famfam': 'hourglass_delete', 'permissions': [PERMISSION_OCR_DOCUMENT_DELETE]} link_entry_delete = {'text': _('Delete'), 'view': 'ocr:entry_delete', 'args': 'object.id', 'famfam': 'hourglass_delete', 'permissions': [PERMISSION_OCR_DOCUMENT_DELETE]}
link_entry_delete_multiple = {'text': _('Delete'), 'view': 'ocr:entry_delete_multiple', 'famfam': 'hourglass_delete'} link_entry_delete_multiple = {'text': _('Delete'), 'view': 'ocr:entry_delete_multiple', 'famfam': 'hourglass_delete'}
link_document_all_ocr_cleanup = {'text': _('Clean up pages content'), 'view': 'ocr:document_all_ocr_cleanup', 'famfam': 'text_strikethrough', 'permissions': [PERMISSION_OCR_CLEAN_ALL_PAGES], 'description': _('Runs a language filter to remove common OCR mistakes from document pages content.')} link_document_all_ocr_cleanup = Link(
description=_('Runs a language filter to remove common OCR mistakes from document pages content.'),
permissions=[PERMISSION_OCR_CLEAN_ALL_PAGES],
text=_('Clean up pages content'), view='ocr:document_all_ocr_cleanup'
)
link_entry_list = {'text': _('OCR Errors'), 'view': 'ocr:entry_list', 'icon': 'fa fa-file-text-o', 'permissions': [PERMISSION_OCR_DOCUMENT]} link_entry_list = {'text': _('OCR Errors'), 'view': 'ocr:entry_list', 'icon': 'fa fa-file-text-o', 'permissions': [PERMISSION_OCR_DOCUMENT]}

View File

@@ -3,7 +3,7 @@ from __future__ import unicode_literals
from django import apps from django import apps
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from navigation.api import register_top_menu from common.menus import menu_main
from .links import link_setup from .links import link_setup
@@ -13,4 +13,4 @@ class ProjectSetupApp(apps.AppConfig):
verbose_name = _('Project setup') verbose_name = _('Project setup')
def ready(self): def ready(self):
register_top_menu('setup_menu', link=link_setup, position=-2) menu_main.bind_links(links=[link_setup], position=-2)

View File

@@ -2,4 +2,6 @@ from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
link_setup = {'text': _('Setup'), 'view': 'project_setup:setup_list', 'icon': 'fa fa-gear'} from navigation import Link
link_setup = Link(icon='fa fa-gear', text=_('Setup'), view='project_setup:setup_list')

View File

@@ -3,7 +3,7 @@ from __future__ import unicode_literals
from django import apps from django import apps
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from navigation.api import register_top_menu from common.menus import menu_main
from .links import link_tools from .links import link_tools
@@ -13,4 +13,4 @@ class ProjectToolsApp(apps.AppConfig):
verbose_name = _('Project tools') verbose_name = _('Project tools')
def ready(self): def ready(self):
register_top_menu('tools', link=link_tools, position=-3) menu_main.bind_links(links=[link_tools], position=-3)

View File

@@ -2,4 +2,6 @@ from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
link_tools = {'text': _('Tools'), 'view': 'project_tools:tools_list', 'icon': 'fa fa-wrench'} from navigation import Link
link_tools = Link(icon='fa fa-wrench', text=_('Tools'), view='project_tools:tools_list')

View File

@@ -4,18 +4,17 @@ from django import apps
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from acls.api import class_permissions from acls.api import class_permissions
from common.menus import menu_secondary, menu_object, menu_main
from common.utils import encapsulate from common.utils import encapsulate
from documents.models import Document from documents.models import Document
from navigation.api import ( from navigation.api import register_links, register_model_list_columns
register_links, register_model_list_columns, register_top_menu
)
from navigation.links import link_spacer from navigation.links import link_spacer
from rest_api.classes import APIEndPoint from rest_api.classes import APIEndPoint
from .links import ( from .links import (
multiple_documents_selection_tag_remove, multiple_documents_selection_tag_remove,
single_document_multiple_tag_remove, tag_acl_list, tag_attach, tag_create, single_document_multiple_tag_remove, tag_acl_list, tag_attach, tag_create,
tag_delete, tag_document_list, tag_edit, tag_list, tag_multiple_attach, tag_delete, tag_document_list, tag_edit, link_tag_list, tag_multiple_attach,
tag_multiple_delete, tag_tagged_item_list tag_multiple_delete, tag_tagged_item_list
) )
from .models import Tag from .models import Tag
@@ -58,11 +57,11 @@ class TagsApp(apps.AppConfig):
}, },
]) ])
register_top_menu('tags', link=tag_list) menu_main.bind_links(links=[link_tag_list])
register_links(Tag, [tag_tagged_item_list, tag_edit, tag_acl_list, tag_delete]) register_links(Tag, [tag_tagged_item_list, tag_edit, tag_acl_list, tag_delete])
register_links([Tag], [tag_multiple_delete], menu_name='multi_item_links') register_links([Tag], [tag_multiple_delete], menu_name='multi_item_links')
register_links([Tag, 'tags:tag_list', 'tags:tag_create'], [tag_list, tag_create], menu_name='secondary_menu') register_links([Tag, 'tags:tag_list', 'tags:tag_create'], [link_tag_list, tag_create], menu_name='secondary_menu')
register_links(Document, [tag_document_list], menu_name='form_header') register_links(Document, [tag_document_list], menu_name='form_header')
register_links(['tags:document_tags', 'tags:tag_remove', 'tags:tag_multiple_remove', 'tags:tag_attach'], [tag_attach], menu_name='sidebar') register_links(['tags:document_tags', 'tags:tag_remove', 'tags:tag_multiple_remove', 'tags:tag_attach'], [tag_attach], menu_name='sidebar')

View File

@@ -3,13 +3,15 @@ from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from acls.permissions import ACLS_VIEW_ACL from acls.permissions import ACLS_VIEW_ACL
from navigation import Link
from .permissions import ( from .permissions import (
PERMISSION_TAG_ATTACH, PERMISSION_TAG_CREATE, PERMISSION_TAG_DELETE, PERMISSION_TAG_ATTACH, PERMISSION_TAG_CREATE, PERMISSION_TAG_DELETE,
PERMISSION_TAG_EDIT, PERMISSION_TAG_REMOVE PERMISSION_TAG_EDIT, PERMISSION_TAG_REMOVE
) )
tag_list = {'text': _('Tags'), 'view': 'tags:tag_list', 'icon': 'fa fa-tag'} link_tag_list = Link(icon='fa fa-tag', text=_('Tags'), view='tags:tag_list')
tag_create = {'text': _('Create new tag'), 'view': 'tags:tag_create', 'famfam': 'tag_blue_add', 'permissions': [PERMISSION_TAG_CREATE]} tag_create = {'text': _('Create new tag'), 'view': 'tags:tag_create', 'famfam': 'tag_blue_add', 'permissions': [PERMISSION_TAG_CREATE]}
tag_attach = {'text': _('Attach tag'), 'view': 'tags:tag_attach', 'args': 'object.pk', 'famfam': 'tag_blue_add', 'permissions': [PERMISSION_TAG_ATTACH]} tag_attach = {'text': _('Attach tag'), 'view': 'tags:tag_attach', 'args': 'object.pk', 'famfam': 'tag_blue_add', 'permissions': [PERMISSION_TAG_ATTACH]}