diff --git a/README.md b/README.md index 7e4b8e1203..000f5f57a3 100644 --- a/README.md +++ b/README.md @@ -27,4 +27,3 @@ Donations --------- Please [donate](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=W6LMMZHTNUJ6L) if you are willing to support the further development of this project. -[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=rosarior&url=http://github.com/rosarior/mayan&title=Mayan EDMS&language=en_GB&tags=github&category=software) diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index 7a83009b39..fe2e4b2cf7 100644 --- a/apps/acls/__init__.py +++ b/apps/acls/__init__.py @@ -2,7 +2,7 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ -from navigation.api import register_links, register_multi_item_links +from navigation.api import bind_links, register_multi_item_links, Link from project_setup.api import register_setup from .classes import (AccessHolder, AccessObjectClass, ClassAccessHolder, @@ -11,29 +11,30 @@ from .permissions import (ACLS_EDIT_ACL, ACLS_VIEW_ACL, ACLS_CLASS_EDIT_ACL, ACLS_CLASS_VIEW_ACL) -acl_list = {'text': _(u'ACLs'), 'view': 'acl_list', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} -acl_detail = {'text': _(u'details'), 'view': 'acl_detail', 'args': ['access_object.gid', 'object.gid'], 'famfam': 'key_go', 'permissions': [ACLS_VIEW_ACL]} -acl_grant = {'text': _(u'grant'), 'view': 'acl_multiple_grant', 'famfam': 'key_add', 'permissions': [ACLS_EDIT_ACL]} -acl_revoke = {'text': _(u'revoke'), 'view': 'acl_multiple_revoke', 'famfam': 'key_delete', 'permissions': [ACLS_EDIT_ACL]} -acl_holder_new = {'text': _(u'New holder'), 'view': 'acl_holder_new', 'args': 'access_object.gid', 'famfam': 'user', 'permissions': [ACLS_EDIT_ACL]} +acl_list = Link(text=_(u'ACLs'), view='acl_list', sprite='lock', permissions=[ACLS_VIEW_ACL]) +acl_detail = Link(text=_(u'details'), view='acl_detail', args=['access_object.gid', 'object.gid'], sprite='key_go', permissions=[ACLS_VIEW_ACL]) +acl_grant = Link(text=_(u'grant'), view='acl_multiple_grant', sprite='key_add', permissions=[ACLS_EDIT_ACL]) +acl_revoke = Link(text=_(u'revoke'), view='acl_multiple_revoke', sprite='key_delete', permissions=[ACLS_EDIT_ACL]) +acl_holder_new = Link(text=_(u'New holder'), view='acl_holder_new', args='access_object.gid', sprite='user', permissions=[ACLS_EDIT_ACL]) -acl_setup_valid_classes = {'text': _(u'Default ACLs'), 'view': 'acl_setup_valid_classes', 'icon': 'lock.png', 'permissions': [ACLS_CLASS_VIEW_ACL], 'children_view_regex': [r'^acl_class', r'^acl_setup']} -acl_class_list = {'text': _(u'List of classes'), 'view': 'acl_setup_valid_classes', 'famfam': 'package', 'permissions': [ACLS_CLASS_VIEW_ACL]} -acl_class_acl_list = {'text': _(u'ACLs for class'), 'view': 'acl_class_acl_list', 'args': 'object.gid', 'famfam': 'lock_go', 'permissions': [ACLS_CLASS_VIEW_ACL]} -acl_class_acl_detail = {'text': _(u'details'), 'view': 'acl_class_acl_detail', 'args': ['access_object_class.gid', 'object.gid'], 'famfam': 'key_go', 'permissions': [ACLS_CLASS_VIEW_ACL]} -acl_class_new_holder_for = {'text': _(u'New holder'), 'view': 'acl_class_new_holder_for', 'args': 'object.gid', 'famfam': 'user', 'permissions': [ACLS_CLASS_EDIT_ACL]} -acl_class_grant = {'text': _(u'grant'), 'view': 'acl_class_multiple_grant', 'famfam': 'key_add', 'permissions': [ACLS_CLASS_EDIT_ACL]} -acl_class_revoke = {'text': _(u'revoke'), 'view': 'acl_class_multiple_revoke', 'famfam': 'key_delete', 'permissions': [ACLS_CLASS_EDIT_ACL]} +acl_setup_valid_classes = Link(text=_(u'Default ACLs'), view='acl_setup_valid_classes', icon='lock.png', permissions=[ACLS_CLASS_VIEW_ACL])#, 'children_view_regex=[r'^acl_class', r'^acl_setup']} +acl_class_list = Link(text=_(u'List of classes'), view='acl_setup_valid_classes', sprite='package', permissions=[ACLS_CLASS_VIEW_ACL]) +acl_class_acl_list = Link(text=_(u'ACLs for class'), view='acl_class_acl_list', args='object.gid', sprite='lock_go', permissions=[ACLS_CLASS_VIEW_ACL]) +acl_class_acl_detail = Link(text=_(u'details'), view='acl_class_acl_detail', args=['access_object_class.gid', 'object.gid'], sprite='key_go', permissions=[ACLS_CLASS_VIEW_ACL]) +acl_class_new_holder_for = Link(text=_(u'New holder'), view='acl_class_new_holder_for', args='object.gid', sprite='user', permissions=[ACLS_CLASS_EDIT_ACL]) +acl_class_grant = Link(text=_(u'grant'), view='acl_class_multiple_grant', sprite='key_add', permissions=[ACLS_CLASS_EDIT_ACL]) +acl_class_revoke = Link(text=_(u'revoke'), view='acl_class_multiple_revoke', sprite='key_delete', permissions=[ACLS_CLASS_EDIT_ACL]) -register_links(AccessHolder, [acl_detail]) +bind_links([AccessHolder], [acl_detail]) register_multi_item_links(['acl_detail'], [acl_grant, acl_revoke]) -register_links([AccessObject], [acl_holder_new], menu_name='sidebar') +bind_links([AccessObject], [acl_holder_new], menu_name='sidebar') + +bind_links(['acl_setup_valid_classes', 'acl_class_acl_list', 'acl_class_new_holder_for', 'acl_class_acl_detail', 'acl_class_multiple_grant', 'acl_class_multiple_revoke'], [acl_class_list], menu_name='secondary_menu') + +bind_links([ClassAccessHolder], [acl_class_acl_detail]) + +bind_links([AccessObjectClass], [acl_class_acl_list, acl_class_new_holder_for]) +register_multi_item_links(['acl_class_acl_detail'], [acl_class_grant, acl_class_revoke]) register_setup(acl_setup_valid_classes) -register_links(['acl_setup_valid_classes', 'acl_class_acl_list', 'acl_class_new_holder_for', 'acl_class_acl_detail', 'acl_class_multiple_grant', 'acl_class_multiple_revoke'], [acl_class_list], menu_name='secondary_menu') - -register_links(ClassAccessHolder, [acl_class_acl_detail]) - -register_links(AccessObjectClass, [acl_class_acl_list, acl_class_new_holder_for]) -register_multi_item_links(['acl_class_acl_detail'], [acl_class_grant, acl_class_revoke]) diff --git a/apps/common/__init__.py b/apps/common/__init__.py index 77519a42d3..a92a834217 100644 --- a/apps/common/__init__.py +++ b/apps/common/__init__.py @@ -8,7 +8,7 @@ from django.contrib.auth.management import create_superuser from django.dispatch import receiver from django.db.models.signals import post_syncdb -from navigation.api import register_links, register_top_menu +from navigation.api import bind_links, register_top_menu, Link from .conf.settings import (AUTO_CREATE_ADMIN, AUTO_ADMIN_USERNAME, AUTO_ADMIN_PASSWORD, TEMPORARY_DIRECTORY) @@ -19,18 +19,16 @@ from .utils import validate_path def has_usable_password(context): return context['request'].user.has_usable_password -password_change_view = {'text': _(u'change password'), 'view': 'password_change_view', 'famfam': 'computer_key', 'condition': has_usable_password} -current_user_details = {'text': _(u'user details'), 'view': 'current_user_details', 'famfam': 'vcard'} -current_user_edit = {'text': _(u'edit details'), 'view': 'current_user_edit', 'famfam': 'vcard_edit'} +password_change_view = Link(text=_(u'change password'), view='password_change_view', sprite='computer_key', condition=has_usable_password) +current_user_details = Link(text=_(u'user details'), view='current_user_details', sprite='vcard') +current_user_edit = Link(text=_(u'edit details'), view='current_user_edit', sprite='vcard_edit') +about_view = Link(text=_('about'), view='about_view', sprite='information') +license_view = Link(text=_('license'), view='license_view', sprite='script') -register_links(['current_user_details', 'current_user_edit', 'password_change_view'], [current_user_details, current_user_edit, password_change_view], menu_name='secondary_menu') +bind_links(['about_view', 'license_view'], [about_view, license_view], menu_name='secondary_menu') +bind_links(['current_user_details', 'current_user_edit', 'password_change_view'], [current_user_details, current_user_edit, password_change_view], menu_name='secondary_menu') -about_view = {'text': _('about'), 'view': 'about_view', 'famfam': 'information'} -license_view = {'text': _('license'), 'view': 'license_view', 'famfam': 'script'} - -register_links(['about_view', 'license_view'], [about_view, license_view], menu_name='secondary_menu') - -register_top_menu('about', link={'text': _(u'about'), 'view': 'about_view', 'famfam': 'information'}, position=-1) +register_top_menu('about', link=Link(text=_(u'about'), view='about_view', sprite='information'), position=-1) @receiver(post_syncdb, dispatch_uid='create_superuser', sender=auth_models) diff --git a/apps/common/templates/generic_list_horizontal_subtemplate.html b/apps/common/templates/generic_list_horizontal_subtemplate.html index 8b62536db7..43b3211d89 100644 --- a/apps/common/templates/generic_list_horizontal_subtemplate.html +++ b/apps/common/templates/generic_list_horizontal_subtemplate.html @@ -38,7 +38,7 @@ @@ -62,7 +62,11 @@ @@ -77,7 +81,7 @@ diff --git a/apps/common/templates/generic_list_subtemplate.html b/apps/common/templates/generic_list_subtemplate.html index 1e0868a227..fd4076470f 100644 --- a/apps/common/templates/generic_list_subtemplate.html +++ b/apps/common/templates/generic_list_subtemplate.html @@ -38,10 +38,12 @@ {% if multi_select_as_buttons %} {% get_multi_item_links as multi_item_links %} {% else %} @@ -170,10 +172,12 @@ {% if multi_select_as_buttons %} {% get_multi_item_links as multi_item_links %} {% else %} diff --git a/apps/converter/__init__.py b/apps/converter/__init__.py index 29dcb978fe..83fe67b65c 100644 --- a/apps/converter/__init__.py +++ b/apps/converter/__init__.py @@ -3,7 +3,7 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ from django.core.exceptions import ImproperlyConfigured -from navigation.api import register_sidebar_template +from navigation.api import register_sidebar_template, Link from project_tools.api import register_tool from .utils import load_backend @@ -12,7 +12,7 @@ from .conf.settings import GRAPHICS_BACKEND def is_superuser(context): return context['request'].user.is_staff or context['request'].user.is_superuser -formats_list = {'text': _('file formats'), 'view': 'formats_list', 'famfam': 'pictures', 'icon': 'pictures.png', 'condition': is_superuser, 'children_view_regex': [r'formats_list']} +formats_list = Link(text=_('file formats'), view='formats_list', sprite='pictures', icon='pictures.png', condition=is_superuser, children_view_regex=[r'formats_list']) register_sidebar_template(['formats_list'], 'converter_file_formats_help.html') diff --git a/apps/django_gpg/__init__.py b/apps/django_gpg/__init__.py index a49c0f26b9..44e78fb81d 100644 --- a/apps/django_gpg/__init__.py +++ b/apps/django_gpg/__init__.py @@ -2,7 +2,7 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ -from navigation.api import register_links +from navigation.api import bind_links, Link from project_setup.api import register_setup from hkp import Key as KeyServerKey @@ -11,17 +11,17 @@ from .permissions import (PERMISSION_KEY_VIEW, PERMISSION_KEY_DELETE, PERMISSION_KEYSERVER_QUERY, PERMISSION_KEY_RECEIVE) # Setup views -private_keys = {'text': _(u'private keys'), 'view': 'key_private_list', 'args': 'object.pk', 'famfam': 'key', 'icon': 'key.png', 'permissions': [PERMISSION_KEY_VIEW]} -public_keys = {'text': _(u'public keys'), 'view': 'key_public_list', 'args': 'object.pk', 'famfam': 'key', 'icon': 'key.png', 'permissions': [PERMISSION_KEY_VIEW]} -key_delete = {'text': _(u'delete'), 'view': 'key_delete', 'args': ['object.fingerprint', 'object.type'], 'famfam': 'key_delete', 'permissions': [PERMISSION_KEY_DELETE]} -key_query = {'text': _(u'query keyservers'), 'view': 'key_query', 'famfam': 'zoom', 'permissions': [PERMISSION_KEYSERVER_QUERY]} -key_receive = {'text': _(u'import'), 'view': 'key_receive', 'args': 'object.keyid', 'famfam': 'key_add', 'keep_query': True, 'permissions': [PERMISSION_KEY_RECEIVE]} -key_setup = {'text': _(u'key management'), 'view': 'key_public_list', 'args': 'object.pk', 'famfam': 'key', 'icon': 'key.png', 'permissions': [PERMISSION_KEY_VIEW], 'children_view_regex': [r'^key_']} +private_keys = Link(text=_(u'private keys'), view='key_private_list', args='object.pk', sprite='key', icon='key.png', permissions=[PERMISSION_KEY_VIEW]) +public_keys = Link(text=_(u'public keys'), view='key_public_list', args='object.pk', sprite='key', icon='key.png', permissions=[PERMISSION_KEY_VIEW]) +key_delete = Link(text=_(u'delete'), view='key_delete', args=['object.fingerprint', 'object.type'], sprite='key_delete', permissions=[PERMISSION_KEY_DELETE]) +key_query = Link(text=_(u'query keyservers'), view='key_query', sprite='zoom', permissions=[PERMISSION_KEYSERVER_QUERY]) +key_receive = Link(text=_(u'import'), view='key_receive', args='object.keyid', sprite='key_add', keep_query=True, permissions=[PERMISSION_KEY_RECEIVE]) +key_setup = Link(text=_(u'key management'), view='key_public_list', args='object.pk', sprite='key', icon='key.png', permissions=[PERMISSION_KEY_VIEW], children_view_regex=[r'^key_']) -#register_links(['key_delete', 'key_private_list', 'key_public_list', 'key_query'], [private_keys, public_keys, key_query], menu_name='sidebar') -register_links(['key_delete', 'key_public_list', 'key_query'], [public_keys, key_query], menu_name='sidebar') +#bind_links(['key_delete', 'key_private_list', 'key_public_list', 'key_query'], [private_keys, public_keys, key_query], menu_name='sidebar') +bind_links(['key_delete', 'key_public_list', 'key_query'], [public_keys, key_query], menu_name='sidebar') -register_links(Key, [key_delete]) -register_links(KeyServerKey, [key_receive]) +bind_links([Key], [key_delete]) +bind_links([KeyServerKey], [key_receive]) register_setup(key_setup) diff --git a/apps/document_acls/__init__.py b/apps/document_acls/__init__.py index 376b048843..e14d021e20 100644 --- a/apps/document_acls/__init__.py +++ b/apps/document_acls/__init__.py @@ -1,13 +1,13 @@ from django.utils.translation import ugettext_lazy as _ from documents.models import Document -from navigation.api import register_links +from navigation.api import bind_links, Link from acls import ACLS_VIEW_ACL, ACLS_EDIT_ACL from acls.api import class_permissions -acl_list = {'text': _(u'ACLs'), 'view': 'document_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} +acl_list = Link(text=_(u'ACLs'), view='document_acl_list', args='object.pk', sprite='lock', permissions=[ACLS_VIEW_ACL]) -register_links(Document, [acl_list], menu_name='form_header') +bind_links([Document], [acl_list], menu_name='form_header') class_permissions(Document, [ ACLS_VIEW_ACL, diff --git a/apps/document_acls/views.py b/apps/document_acls/views.py index 5938fec434..16f5cd1ca7 100644 --- a/apps/document_acls/views.py +++ b/apps/document_acls/views.py @@ -10,7 +10,4 @@ def document_acl_list(request, document_id): return acl_list_for( request, document, - extra_context={ - 'object': document, - } ) diff --git a/apps/document_comments/__init__.py b/apps/document_comments/__init__.py index 2356f36885..2d8a304ebc 100644 --- a/apps/document_comments/__init__.py +++ b/apps/document_comments/__init__.py @@ -5,7 +5,7 @@ from django.conf import settings from django.contrib.comments.models import Comment from django.contrib.contenttypes import generic -from navigation.api import register_links, register_model_list_columns +from navigation.api import bind_links, register_model_list_columns, Link from common.utils import encapsulate from acls.api import class_permissions from documents.models import Document @@ -16,10 +16,10 @@ if 'django.contrib.comments' not in settings.INSTALLED_APPS: from .permissions import (PERMISSION_COMMENT_CREATE, PERMISSION_COMMENT_DELETE, PERMISSION_COMMENT_VIEW) -comment_delete = {'text': _('delete'), 'view': 'comment_delete', 'args': 'object.pk', 'famfam': 'comment_delete', 'permissions': [PERMISSION_COMMENT_DELETE]} -comment_multiple_delete = {'text': _('delete'), 'view': 'comment_multiple_delete', 'args': 'object.pk', 'famfam': 'comments_delete', 'permissions': [PERMISSION_COMMENT_DELETE]} -comment_add = {'text': _('add comment'), 'view': 'comment_add', 'args': 'object.pk', 'famfam': 'comment_add', 'permissions': [PERMISSION_COMMENT_CREATE]} -comments_for_document = {'text': _('comments'), 'view': 'comments_for_document', 'args': 'object.pk', 'famfam': 'comments', 'permissions': [PERMISSION_COMMENT_VIEW], 'children_view_regex': ['comment']} +comment_delete = Link(text=_('delete'), view='comment_delete', args='object.pk', sprite='comment_delete', permissions=[PERMISSION_COMMENT_DELETE]) +comment_multiple_delete = Link(text=_('delete'), view='comment_multiple_delete', args='object.pk', sprite='comments_delete', permissions=[PERMISSION_COMMENT_DELETE]) +comment_add = Link(text=_('add comment'), view='comment_add', args='object.pk', sprite='comment_add', permissions=[PERMISSION_COMMENT_CREATE]) +comments_for_document = Link(text=_('comments'), view='comments_for_document', args='object.pk', sprite='comments', permissions=[PERMISSION_COMMENT_VIEW], children_view_regex=['comment']) register_model_list_columns(Comment, [ { @@ -36,9 +36,9 @@ register_model_list_columns(Comment, [ } ]) -register_links(['comments_for_document', 'comment_add', 'comment_delete', 'comment_multiple_delete'], [comment_add], menu_name='sidebar') -register_links(Comment, [comment_delete]) -register_links(Document, [comments_for_document], menu_name='form_header') +bind_links(['comments_for_document', 'comment_add', 'comment_delete', 'comment_multiple_delete'], [comment_add], menu_name='sidebar') +bind_links([Comment], [comment_delete]) +bind_links([Document], [comments_for_document], menu_name='form_header') Document.add_to_class( 'comments', diff --git a/apps/document_indexing/__init__.py b/apps/document_indexing/__init__.py index 8c79a8f3f9..579facc80d 100644 --- a/apps/document_indexing/__init__.py +++ b/apps/document_indexing/__init__.py @@ -7,7 +7,7 @@ from django.db.models.signals import pre_save, post_save, pre_delete from django.dispatch import receiver from navigation.api import (register_top_menu, register_sidebar_template, - register_links) + bind_links, Link) from main.api import register_maintenance_links from documents.permissions import PERMISSION_DOCUMENT_VIEW @@ -34,42 +34,36 @@ def is_not_instance_root_node(context): logger = logging.getLogger(__name__) -index_setup = {'text': _(u'indexes'), 'view': 'index_setup_list', 'icon': 'tab.png', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP], 'children_view_regex': [r'^index_setup', r'^template_node']} -index_setup_list = {'text': _(u'index list'), 'view': 'index_setup_list', 'famfam': 'tab', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]} -index_setup_create = {'text': _(u'create index'), 'view': 'index_setup_create', 'famfam': 'tab_add', 'permissions': [PERMISSION_DOCUMENT_INDEXING_CREATE]} -index_setup_edit = {'text': _(u'edit'), 'view': 'index_setup_edit', 'args': 'index.pk', 'famfam': 'tab_edit', 'permissions': [PERMISSION_DOCUMENT_INDEXING_EDIT]} -index_setup_delete = {'text': _(u'delete'), 'view': 'index_setup_delete', 'args': 'index.pk', 'famfam': 'tab_delete', 'permissions': [PERMISSION_DOCUMENT_INDEXING_DELETE]} -index_setup_view = {'text': _(u'tree template'), 'view': 'index_setup_view', 'args': 'index.pk', 'famfam': 'textfield', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]} +index_setup = Link(text=_(u'indexes'), view='index_setup_list', icon='tab.png', permissions=[PERMISSION_DOCUMENT_INDEXING_SETUP])#, children_view_regex=[r'^index_setup', r'^template_node']) +index_setup_list = Link(text=_(u'index list'), view='index_setup_list', sprite='tab', permissions=[PERMISSION_DOCUMENT_INDEXING_SETUP]) +index_setup_create = Link(text=_(u'create index'), view='index_setup_create', sprite='tab_add', permissions=[PERMISSION_DOCUMENT_INDEXING_CREATE]) +index_setup_edit = Link(text=_(u'edit'), view='index_setup_edit', args='index.pk', sprite='tab_edit', permissions=[PERMISSION_DOCUMENT_INDEXING_EDIT]) +index_setup_delete = Link(text=_(u'delete'), view='index_setup_delete', args='index.pk', sprite='tab_delete', permissions=[PERMISSION_DOCUMENT_INDEXING_DELETE]) +index_setup_view = Link(text=_(u'tree template'), view='index_setup_view', args='index.pk', sprite='textfield', permissions=[PERMISSION_DOCUMENT_INDEXING_SETUP]) -template_node_create = {'text': _(u'new child node'), 'view': 'template_node_create', 'args': 'node.pk', 'famfam': 'textfield_add', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP]} -template_node_edit = {'text': _(u'edit'), 'view': 'template_node_edit', 'args': 'node.pk', 'famfam': 'textfield', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP], 'conditional_disable': is_root_node} -template_node_delete = {'text': _(u'delete'), 'view': 'template_node_delete', 'args': 'node.pk', 'famfam': 'textfield_delete', 'permissions': [PERMISSION_DOCUMENT_INDEXING_SETUP], 'conditional_disable': is_root_node} +template_node_create = Link(text=_(u'new child node'), view='template_node_create', args='node.pk', sprite='textfield_add', permissions=[PERMISSION_DOCUMENT_INDEXING_SETUP]) +template_node_edit = Link(text=_(u'edit'), view='template_node_edit', args='node.pk', sprite='textfield', permissions=[PERMISSION_DOCUMENT_INDEXING_SETUP], conditional_disable=is_root_node) +template_node_delete = Link(text=_(u'delete'), view='template_node_delete', args='node.pk', sprite='textfield_delete', permissions=[PERMISSION_DOCUMENT_INDEXING_SETUP], conditional_disable=is_root_node) -index_list = {'text': _(u'index list'), 'view': 'index_list', 'famfam': 'tab', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW]} +index_list = Link(text=_(u'index list'), view='index_list', sprite='tab', permissions=[PERMISSION_DOCUMENT_INDEXING_VIEW]) -index_parent = {'text': _(u'go up one level'), 'view': 'index_instance_node_view', 'args': 'object.parent.pk', 'famfam': 'arrow_up', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW], 'dont_mark_active': True, 'condition': is_not_instance_root_node} -document_index_list = {'text': _(u'indexes'), 'view': 'document_index_list', 'args': 'object.pk', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_VIEW]} +index_parent = Link(text=_(u'go up one level'), view='index_instance_node_view', args='object.parent.pk', sprite='arrow_up', permissions=[PERMISSION_DOCUMENT_INDEXING_VIEW], dont_mark_active=True, condition=is_not_instance_root_node) +document_index_list = Link(text= _(u'indexes'), view='document_index_list', args='object.pk', sprite='folder_page', permissions=[PERMISSION_DOCUMENT_INDEXING_VIEW, PERMISSION_DOCUMENT_VIEW]) -register_top_menu('indexes', link={'text': _('indexes'), 'famfam': 'tab', 'view': 'index_list', 'children_view_regex': [r'^index_[i,l]']}) - -rebuild_index_instances = {'text': _('rebuild indexes'), 'view': 'rebuild_index_instances', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES], 'description': _(u'Deletes and creates from scratch all the document indexes.')} +rebuild_index_instances = Link(text=_('rebuild indexes'), view='rebuild_index_instances', sprite='folder_page', permissions=[PERMISSION_DOCUMENT_INDEXING_REBUILD_INDEXES], description=_(u'Deletes and creates from scratch all the document indexes.')) +register_top_menu('indexes', link=Link(text=_('indexes'), sprite='tab', view='index_list', children_view_regex=[r'^index_[i,l]'])) register_maintenance_links([rebuild_index_instances], namespace='document_indexing', title=_(u'Indexes')) - register_sidebar_template(['index_instance_list'], 'indexing_help.html') -register_links(IndexInstanceNode, [index_parent]) - -register_links(Document, [document_index_list], menu_name='form_header') +bind_links([IndexInstanceNode], [index_parent]) +bind_links([Document], [document_index_list], menu_name='form_header') +bind_links([Index, 'index_setup_list', 'index_setup_create', 'template_node_edit', 'template_node_delete'], [index_setup_list, index_setup_create], menu_name='secondary_menu') +bind_links([Index], [index_setup_edit, index_setup_delete, index_setup_view]) +bind_links([IndexTemplateNode], [template_node_create, template_node_edit, template_node_delete]) register_setup(index_setup) -register_links([Index, 'index_setup_list', 'index_setup_create', 'template_node_edit', 'template_node_delete'], [index_setup_list, index_setup_create], menu_name='secondary_menu') - -register_links(Index, [index_setup_edit, index_setup_delete, index_setup_view]) - -register_links(IndexTemplateNode, [template_node_create, template_node_edit, template_node_delete]) - def delete_indexes_handler(sender, instance, **kwargs): if isinstance(instance, DocumentVersion): diff --git a/apps/document_signatures/__init__.py b/apps/document_signatures/__init__.py index d413453dc2..dcd4dbc7fd 100644 --- a/apps/document_signatures/__init__.py +++ b/apps/document_signatures/__init__.py @@ -12,7 +12,7 @@ from django.utils.translation import ugettext_lazy as _ #from django.dispatch import receiver from documents.models import Document, DocumentVersion -from navigation.api import register_links +from navigation.api import bind_links, Link from django_gpg.runtime import gpg from django_gpg.exceptions import GPGDecryptionError from acls.api import class_permissions @@ -79,13 +79,13 @@ def document_post_save_hook(instance): # if kwargs.get('created', False): # DocumentVersionSignature.objects.signature_state(instance.document) -document_signature_upload = {'text': _(u'upload signature'), 'view': 'document_signature_upload', 'args': 'object.pk', 'famfam': 'pencil_add', 'permissions': [PERMISSION_SIGNATURE_UPLOAD], 'conditional_disable': has_embedded_signature} -document_signature_download = {'text': _(u'download signature'), 'view': 'document_signature_download', 'args': 'object.pk', 'famfam': 'disk', 'permissions': [PERMISSION_SIGNATURE_DOWNLOAD], 'conditional_disable': doesnt_have_detached_signature} -document_signature_delete = {'text': _(u'delete signature'), 'view': 'document_signature_delete', 'args': 'object.pk', 'famfam': 'pencil_delete', 'permissions': [PERMISSION_SIGNATURE_DELETE], 'conditional_disable': doesnt_have_detached_signature} -document_verify = {'text': _(u'signatures'), 'view': 'document_verify', 'args': 'object.pk', 'famfam': 'text_signature', 'permissions': [PERMISSION_DOCUMENT_VERIFY]} +document_signature_upload = Link(text=_(u'upload signature'), view='document_signature_upload', args='object.pk', sprite='pencil_add', permissions=[PERMISSION_SIGNATURE_UPLOAD], conditional_disable=has_embedded_signature) +document_signature_download = Link(text=_(u'download signature'), view='document_signature_download', args='object.pk', sprite='disk', permissions=[PERMISSION_SIGNATURE_DOWNLOAD], conditional_disable=doesnt_have_detached_signature) +document_signature_delete = Link(text=_(u'delete signature'), view='document_signature_delete', args='object.pk', sprite='pencil_delete', permissions=[PERMISSION_SIGNATURE_DELETE], conditional_disable=doesnt_have_detached_signature) +document_verify = Link(text=_(u'signatures'), view='document_verify', args='object.pk', sprite='text_signature', permissions=[PERMISSION_DOCUMENT_VERIFY]) -register_links(Document, [document_verify], menu_name='form_header') -register_links(['document_verify', 'document_signature_upload', 'document_signature_download', 'document_signature_delete'], [document_signature_upload, document_signature_download, document_signature_delete], menu_name='sidebar') +bind_links([Document], [document_verify], menu_name='form_header') +bind_links(['document_verify', 'document_signature_upload', 'document_signature_download', 'document_signature_delete'], [document_signature_upload, document_signature_download, document_signature_delete], menu_name='sidebar') DocumentVersion.register_pre_open_hook(1, document_pre_open_hook) DocumentVersion.register_post_save_hook(1, document_post_save_hook) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index d3873ad600..8fba2a2c32 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -5,9 +5,9 @@ import tempfile from django.utils.translation import ugettext_lazy as _ from common.utils import validate_path, encapsulate -from navigation.api import (register_links, register_top_menu, +from navigation.api import (bind_links, register_top_menu, register_model_list_columns, register_multi_item_links, - register_sidebar_template) + register_sidebar_template, Link) from main.api import register_diagnostic, register_maintenance_links from history.api import register_history_type from history.permissions import PERMISSION_HISTORY_VIEW @@ -60,106 +60,107 @@ register_history_type(HISTORY_DOCUMENT_CREATED) register_history_type(HISTORY_DOCUMENT_EDITED) register_history_type(HISTORY_DOCUMENT_DELETED) -document_list = {'text': _(u'all documents'), 'view': 'document_list', 'famfam': 'page'} -document_list_recent = {'text': _(u'recent documents'), 'view': 'document_list_recent', 'famfam': 'page'} -document_create_multiple = {'text': _(u'upload new documents'), 'view': 'document_create_multiple', 'famfam': 'page_add', 'permissions': [PERMISSION_DOCUMENT_CREATE], 'children_view_regex': [r'upload_interactive']} -document_create_siblings = {'text': _(u'clone metadata'), 'view': 'document_create_siblings', 'args': 'object.id', 'famfam': 'page_copy', 'permissions': [PERMISSION_DOCUMENT_CREATE]} -document_view_simple = {'text': _(u'details'), 'view': 'document_view_simple', 'args': 'object.id', 'famfam': 'page', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -document_view_advanced = {'text': _(u'properties'), 'view': 'document_view_advanced', 'args': 'object.id', 'famfam': 'page_gear', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -document_delete = {'text': _(u'delete'), 'view': 'document_delete', 'args': 'object.id', 'famfam': 'page_delete', 'permissions': [PERMISSION_DOCUMENT_DELETE]} -document_multiple_delete = {'text': _(u'delete'), 'view': 'document_multiple_delete', 'famfam': 'page_delete', 'permissions': [PERMISSION_DOCUMENT_DELETE]} -document_edit = {'text': _(u'edit'), 'view': 'document_edit', 'args': 'object.id', 'famfam': 'page_edit', 'permissions': [PERMISSION_DOCUMENT_PROPERTIES_EDIT]} -document_preview = {'text': _(u'preview'), 'class': 'fancybox', 'view': 'document_preview', 'args': 'object.id', 'famfam': 'magnifier', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -document_download = {'text': _(u'download'), 'view': 'document_download', 'args': 'object.id', 'famfam': 'page_save', 'permissions': [PERMISSION_DOCUMENT_DOWNLOAD]} -document_multiple_download = {'text': _(u'download'), 'view': 'document_multiple_download', 'famfam': 'page_save', 'permissions': [PERMISSION_DOCUMENT_DOWNLOAD]} -document_version_download = {'text': _(u'download'), 'view': 'document_version_download', 'args': 'object.pk', 'famfam': 'page_save', 'permissions': [PERMISSION_DOCUMENT_DOWNLOAD]} -document_find_duplicates = {'text': _(u'find duplicates'), 'view': 'document_find_duplicates', 'args': 'object.id', 'famfam': 'page_white_copy', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -document_find_all_duplicates = {'text': _(u'find all duplicates'), 'view': 'document_find_all_duplicates', 'famfam': 'page_white_copy', 'permissions': [PERMISSION_DOCUMENT_VIEW], 'description': _(u'Search all the documents\' checksums and return a list of the exact matches.')} -document_update_page_count = {'text': _(u'update office documents\' page count'), 'view': 'document_update_page_count', 'famfam': 'page_white_csharp', 'permissions': [PERMISSION_DOCUMENT_TOOLS], 'description': _(u'Update the page count of the office type documents. This is useful when enabling office document support after there were already office type documents in the database.')} -document_clear_transformations = {'text': _(u'clear transformations'), 'view': 'document_clear_transformations', 'args': 'object.id', 'famfam': 'page_paintbrush', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]} -document_multiple_clear_transformations = {'text': _(u'clear transformations'), 'view': 'document_multiple_clear_transformations', 'famfam': 'page_paintbrush', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]} -document_print = {'text': _(u'print'), 'view': 'document_print', 'args': 'object.id', 'famfam': 'printer', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -document_history_view = {'text': _(u'history'), 'view': 'history_for_object', 'args': ['"documents"', '"document"', 'object.id'], 'famfam': 'book_go', 'permissions': [PERMISSION_HISTORY_VIEW]} -document_missing_list = {'text': _(u'Find missing document files'), 'view': 'document_missing_list', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_VIEW]} +document_list = Link(text=_(u'all documents'), view='document_list', sprite='page') +document_list_recent = Link(text=_(u'recent documents'), view='document_list_recent', sprite='page') +document_create_multiple = Link(text=_(u'upload new documents'), view='document_create_multiple', sprite='page_add', permissions=[PERMISSION_DOCUMENT_CREATE], children_view_regex=[r'upload_interactive']) +document_create_siblings = Link(text=_(u'clone metadata'), view='document_create_siblings', args='object.id', sprite='page_copy', permissions=[PERMISSION_DOCUMENT_CREATE]) +document_view_simple = Link(text=_(u'details'), view='document_view_simple', args='object.id', sprite='page', permissions=[PERMISSION_DOCUMENT_VIEW]) +document_view_advanced = Link(text=_(u'properties'), view='document_view_advanced', args='object.id', sprite='page_gear', permissions=[PERMISSION_DOCUMENT_VIEW]) +document_delete = Link(text=_(u'delete'), view='document_delete', args='object.id', sprite='page_delete', permissions=[PERMISSION_DOCUMENT_DELETE]) +document_multiple_delete = Link(text=_(u'delete'), view='document_multiple_delete', sprite='page_delete', permissions=[PERMISSION_DOCUMENT_DELETE]) +document_edit = Link(text=_(u'edit'), view='document_edit', args='object.id', sprite='page_edit', permissions=[PERMISSION_DOCUMENT_PROPERTIES_EDIT]) +document_preview = Link(text=_(u'preview'), klass='fancybox', view='document_preview', args='object.id', sprite='magnifier', permissions=[PERMISSION_DOCUMENT_VIEW]) +document_download = Link(text=_(u'download'), view='document_download', args='object.id', sprite='page_save', permissions=[PERMISSION_DOCUMENT_DOWNLOAD]) +document_multiple_download = Link(text=_(u'download'), view='document_multiple_download', sprite='page_save', permissions=[PERMISSION_DOCUMENT_DOWNLOAD]) +document_version_download = Link(text=_(u'download'), view='document_version_download', args='object.pk', sprite='page_save', permissions=[PERMISSION_DOCUMENT_DOWNLOAD]) +document_find_duplicates = Link(text=_(u'find duplicates'), view='document_find_duplicates', args='object.id', sprite='page_white_copy', permissions=[PERMISSION_DOCUMENT_VIEW]) +document_find_all_duplicates = Link(text=_(u'find all duplicates'), view='document_find_all_duplicates', sprite='page_white_copy', permissions=[PERMISSION_DOCUMENT_VIEW], description=_(u'Search all the documents\' checksums and return a list of the exact matches.')) +document_update_page_count = Link(text=_(u'update office documents\' page count'), view='document_update_page_count', sprite='page_white_csharp', permissions=[PERMISSION_DOCUMENT_TOOLS], description=_(u'Update the page count of the office type documents. This is useful when enabling office document support after there were already office type documents in the database.')) +document_clear_transformations = Link(text=_(u'clear transformations'), view='document_clear_transformations', args='object.id', sprite='page_paintbrush', permissions=[PERMISSION_DOCUMENT_TRANSFORM]) +document_multiple_clear_transformations = Link(text=_(u'clear transformations'), view='document_multiple_clear_transformations', sprite='page_paintbrush', permissions=[PERMISSION_DOCUMENT_TRANSFORM]) +document_print = Link(text=_(u'print'), view='document_print', args='object.id', sprite='printer', permissions=[PERMISSION_DOCUMENT_VIEW]) +document_history_view = Link(text=_(u'history'), view='history_for_object', args=['"documents"', '"document"', 'object.pk'], sprite='book_go', permissions=[PERMISSION_HISTORY_VIEW]) +document_missing_list = Link(text=_(u'Find missing document files'), view='document_missing_list', sprite='folder_page', permissions=[PERMISSION_DOCUMENT_VIEW]) # Tools -document_clear_image_cache = {'text': _(u'Clear the document image cache'), 'view': 'document_clear_image_cache', 'famfam': 'camera_delete', 'permissions': [PERMISSION_DOCUMENT_TOOLS], 'description': _(u'Clear the graphics representations used to speed up the documents\' display and interactive transformations results.')} +document_clear_image_cache = Link(text=_(u'Clear the document image cache'), view='document_clear_image_cache', sprite='camera_delete', permissions=[PERMISSION_DOCUMENT_TOOLS], description=_(u'Clear the graphics representations used to speed up the documents\' display and interactive transformations results.')) # Document pages -document_page_transformation_list = {'text': _(u'page transformations'), 'class': 'no-parent-history', 'view': 'document_page_transformation_list', 'args': 'page.pk', 'famfam': 'pencil_go', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]} -document_page_transformation_create = {'text': _(u'create new transformation'), 'class': 'no-parent-history', 'view': 'document_page_transformation_create', 'args': 'page.pk', 'famfam': 'pencil_add', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]} -document_page_transformation_edit = {'text': _(u'edit'), 'class': 'no-parent-history', 'view': 'document_page_transformation_edit', 'args': 'transformation.pk', 'famfam': 'pencil_go', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]} -document_page_transformation_delete = {'text': _(u'delete'), 'class': 'no-parent-history', 'view': 'document_page_transformation_delete', 'args': 'transformation.pk', 'famfam': 'pencil_delete', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]} +document_page_transformation_list = Link(text=_(u'page transformations'), klass='no-parent-history', view='document_page_transformation_list', args='page.pk', sprite='pencil_go', permissions=[PERMISSION_DOCUMENT_TRANSFORM]) +document_page_transformation_create = Link(text=_(u'create new transformation'), klass='no-parent-history', view='document_page_transformation_create', args='page.pk', sprite='pencil_add', permissions=[PERMISSION_DOCUMENT_TRANSFORM]) +document_page_transformation_edit = Link(text=_(u'edit'), klass='no-parent-history', view='document_page_transformation_edit', args='transformation.pk', sprite='pencil_go', permissions=[PERMISSION_DOCUMENT_TRANSFORM]) +document_page_transformation_delete = Link(text=_(u'delete'), klass='no-parent-history', view='document_page_transformation_delete', args='transformation.pk', sprite='pencil_delete', permissions=[PERMISSION_DOCUMENT_TRANSFORM]) -document_page_view = {'text': _(u'page image'), 'class': 'no-parent-history', 'view': 'document_page_view', 'args': 'page.pk', 'famfam': 'page_white_picture', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -document_page_text = {'text': _(u'page text'), 'class': 'no-parent-history', 'view': 'document_page_text', 'args': 'page.pk', 'famfam': 'page_white_text', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -document_page_edit = {'text': _(u'edit page text'), 'class': 'no-parent-history', 'view': 'document_page_edit', 'args': 'page.pk', 'famfam': 'page_white_edit', 'permissions': [PERMISSION_DOCUMENT_EDIT]} -document_page_navigation_next = {'text': _(u'next page'), 'class': 'no-parent-history', 'view': 'document_page_navigation_next', 'args': 'page.pk', 'famfam': 'resultset_next', 'permissions': [PERMISSION_DOCUMENT_VIEW], 'conditional_disable': is_last_page} -document_page_navigation_previous = {'text': _(u'previous page'), 'class': 'no-parent-history', 'view': 'document_page_navigation_previous', 'args': 'page.pk', 'famfam': 'resultset_previous', 'permissions': [PERMISSION_DOCUMENT_VIEW], 'conditional_disable': is_first_page} -document_page_navigation_first = {'text': _(u'first page'), 'class': 'no-parent-history', 'view': 'document_page_navigation_first', 'args': 'page.pk', 'famfam': 'resultset_first', 'permissions': [PERMISSION_DOCUMENT_VIEW], 'conditional_disable': is_first_page} -document_page_navigation_last = {'text': _(u'last page'), 'class': 'no-parent-history', 'view': 'document_page_navigation_last', 'args': 'page.pk', 'famfam': 'resultset_last', 'permissions': [PERMISSION_DOCUMENT_VIEW], 'conditional_disable': is_last_page} -document_page_zoom_in = {'text': _(u'zoom in'), 'class': 'no-parent-history', 'view': 'document_page_zoom_in', 'args': 'page.pk', 'famfam': 'zoom_in', 'permissions': [PERMISSION_DOCUMENT_VIEW], 'conditional_disable': is_max_zoom} -document_page_zoom_out = {'text': _(u'zoom out'), 'class': 'no-parent-history', 'view': 'document_page_zoom_out', 'args': 'page.pk', 'famfam': 'zoom_out', 'permissions': [PERMISSION_DOCUMENT_VIEW], 'conditional_disable': is_min_zoom} -document_page_rotate_right = {'text': _(u'rotate right'), 'class': 'no-parent-history', 'view': 'document_page_rotate_right', 'args': 'page.pk', 'famfam': 'arrow_turn_right', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -document_page_rotate_left = {'text': _(u'rotate left'), 'class': 'no-parent-history', 'view': 'document_page_rotate_left', 'args': 'page.pk', 'famfam': 'arrow_turn_left', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -document_page_view_reset = {'text': _(u'reset view'), 'class': 'no-parent-history', 'view': 'document_page_view_reset', 'args': 'page.pk', 'famfam': 'page_white', 'permissions': [PERMISSION_DOCUMENT_VIEW]} +document_page_view = Link(text=_(u'page image'), klass='no-parent-history', view='document_page_view', args='page.pk', sprite='page_white_picture', permissions=[PERMISSION_DOCUMENT_VIEW]) +document_page_text = Link(text=_(u'page text'), klass='no-parent-history', view='document_page_text', args='page.pk', sprite='page_white_text', permissions=[PERMISSION_DOCUMENT_VIEW]) +document_page_edit = Link(text=_(u'edit page text'), klass='no-parent-history', view='document_page_edit', args='page.pk', sprite='page_white_edit', permissions=[PERMISSION_DOCUMENT_EDIT]) +document_page_navigation_next = Link(text=_(u'next page'), klass='no-parent-history', view='document_page_navigation_next', args='page.pk', sprite='resultset_next', permissions=[PERMISSION_DOCUMENT_VIEW], conditional_disable=is_last_page) +document_page_navigation_previous = Link(text=_(u'previous page'), klass='no-parent-history', view='document_page_navigation_previous', args='page.pk', sprite='resultset_previous', permissions=[PERMISSION_DOCUMENT_VIEW], conditional_disable=is_first_page) +document_page_navigation_first = Link(text=_(u'first page'), klass='no-parent-history', view='document_page_navigation_first', args='page.pk', sprite='resultset_first', permissions=[PERMISSION_DOCUMENT_VIEW], conditional_disable=is_first_page) +document_page_navigation_last = Link(text=_(u'last page'), klass='no-parent-history', view='document_page_navigation_last', args='page.pk', sprite='resultset_last', permissions=[PERMISSION_DOCUMENT_VIEW], conditional_disable=is_last_page) +document_page_zoom_in = Link(text=_(u'zoom in'), klass='no-parent-history', view='document_page_zoom_in', args='page.pk', sprite='zoom_in', permissions=[PERMISSION_DOCUMENT_VIEW], conditional_disable=is_max_zoom) +document_page_zoom_out = Link(text=_(u'zoom out'), klass='no-parent-history', view='document_page_zoom_out', args='page.pk', sprite='zoom_out', permissions=[PERMISSION_DOCUMENT_VIEW], conditional_disable=is_min_zoom) +document_page_rotate_right = Link(text=_(u'rotate right'), klass='no-parent-history', view='document_page_rotate_right', args='page.pk', sprite='arrow_turn_right', permissions=[PERMISSION_DOCUMENT_VIEW]) +document_page_rotate_left = Link(text=_(u'rotate left'), klass='no-parent-history', view='document_page_rotate_left', args='page.pk', sprite='arrow_turn_left', permissions=[PERMISSION_DOCUMENT_VIEW]) +document_page_view_reset = Link(text=_(u'reset view'), klass='no-parent-history', view='document_page_view_reset', args='page.pk', sprite='page_white', permissions=[PERMISSION_DOCUMENT_VIEW]) # Document versions -document_version_list = {'text': _(u'versions'), 'view': 'document_version_list', 'args': 'object.pk', 'famfam': 'page_world', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -document_version_revert = {'text': _(u'revert'), 'view': 'document_version_revert', 'args': 'object.pk', 'famfam': 'page_refresh', 'permissions': [PERMISSION_DOCUMENT_VERSION_REVERT], 'conditional_disable': is_current_version} +document_version_list = Link(text=_(u'versions'), view='document_version_list', args='object.pk', sprite='page_world', permissions=[PERMISSION_DOCUMENT_VIEW]) +document_version_revert = Link(text=_(u'revert'), view='document_version_revert', args='object.pk', sprite='page_refresh', permissions=[PERMISSION_DOCUMENT_VERSION_REVERT], conditional_disable=is_current_version) # Document type related links -document_type_list = {'text': _(u'document type list'), 'view': 'document_type_list', 'famfam': 'layout', 'permissions': [PERMISSION_DOCUMENT_TYPE_VIEW]} -document_type_setup = {'text': _(u'document types'), 'view': 'document_type_list', 'famfam': 'layout', 'icon': 'layout.png', 'permissions': [PERMISSION_DOCUMENT_TYPE_VIEW], 'children_view_regex': [r'^document_type_']} -document_type_document_list = {'text': _(u'documents of this type'), 'view': 'document_type_document_list', 'args': 'document_type.id', 'famfam': 'page_go', 'permissions': [PERMISSION_DOCUMENT_TYPE_VIEW]} -document_type_edit = {'text': _(u'edit'), 'view': 'document_type_edit', 'args': 'document_type.id', 'famfam': 'layout_edit', 'permissions': [PERMISSION_DOCUMENT_TYPE_EDIT]} -document_type_delete = {'text': _(u'delete'), 'view': 'document_type_delete', 'args': 'document_type.id', 'famfam': 'layout_delete', 'permissions': [PERMISSION_DOCUMENT_TYPE_DELETE]} -document_type_create = {'text': _(u'create document type'), 'view': 'document_type_create', 'famfam': 'layout_add', 'permissions': [PERMISSION_DOCUMENT_TYPE_CREATE]} +document_type_list = Link(text=_(u'document type list'), view='document_type_list', sprite='layout', permissions=[PERMISSION_DOCUMENT_TYPE_VIEW]) +document_type_setup = Link(text=_(u'document types'), view='document_type_list', sprite='layout', icon='layout.png', permissions=[PERMISSION_DOCUMENT_TYPE_VIEW], children_view_regex=[r'^document_type_']) +document_type_document_list = Link(text=_(u'documents of this type'), view='document_type_document_list', args='document_type.id', sprite='page_go', permissions=[PERMISSION_DOCUMENT_TYPE_VIEW]) +document_type_edit = Link(text=_(u'edit'), view='document_type_edit', args='document_type.id', sprite='layout_edit', permissions=[PERMISSION_DOCUMENT_TYPE_EDIT]) +document_type_delete = Link(text=_(u'delete'), view='document_type_delete', args='document_type.id', sprite='layout_delete', permissions=[PERMISSION_DOCUMENT_TYPE_DELETE]) +document_type_create = Link(text=_(u'create document type'), view='document_type_create', sprite='layout_add', permissions=[PERMISSION_DOCUMENT_TYPE_CREATE]) -document_type_filename_list = {'text': _(u'filenames'), 'view': 'document_type_filename_list', 'args': 'document_type.id', 'famfam': 'database', 'permissions': [PERMISSION_DOCUMENT_TYPE_VIEW]} -document_type_filename_create = {'text': _(u'add filename to document type'), 'view': 'document_type_filename_create', 'args': 'document_type.id', 'famfam': 'database_add', 'permissions': [PERMISSION_DOCUMENT_TYPE_EDIT]} -document_type_filename_edit = {'text': _(u'edit'), 'view': 'document_type_filename_edit', 'args': 'filename.id', 'famfam': 'database_edit', 'permissions': [PERMISSION_DOCUMENT_TYPE_EDIT]} -document_type_filename_delete = {'text': _(u'delete'), 'view': 'document_type_filename_delete', 'args': 'filename.id', 'famfam': 'database_delete', 'permissions': [PERMISSION_DOCUMENT_TYPE_EDIT]} +document_type_filename_list = Link(text=_(u'filenames'), view='document_type_filename_list', args='document_type.id', sprite='database', permissions=[PERMISSION_DOCUMENT_TYPE_VIEW]) +document_type_filename_create = Link(text=_(u'add filename to document type'), view='document_type_filename_create', args='document_type.id', sprite='database_add', permissions=[PERMISSION_DOCUMENT_TYPE_EDIT]) +document_type_filename_edit = Link(text=_(u'edit'), view='document_type_filename_edit', args='filename.id', sprite='database_edit', permissions=[PERMISSION_DOCUMENT_TYPE_EDIT]) +document_type_filename_delete = Link(text=_(u'delete'), view='document_type_filename_delete', args='filename.id', sprite='database_delete', permissions=[PERMISSION_DOCUMENT_TYPE_EDIT]) -document_type_views = ['setup_document_type_metadata', 'document_type_list', 'document_type_document_list', 'document_type_edit', 'document_type_delete', 'document_type_create', 'document_type_filename_list', 'document_type_filename_create', 'document_type_filename_edit', 'document_type_filename_delete'] +# TODO: remove this +document_type_views=['setup_document_type_metadata', 'document_type_list', 'document_type_document_list', 'document_type_edit', 'document_type_delete', 'document_type_create', 'document_type_filename_list', 'document_type_filename_create', 'document_type_filename_edit', 'document_type_filename_delete'] # Register document type links -register_links(DocumentType, [document_type_document_list, document_type_filename_list, document_type_edit, document_type_delete]) -register_links(DocumentTypeFilename, [document_type_filename_edit, document_type_filename_delete]) +bind_links([DocumentType], [document_type_document_list, document_type_filename_list, document_type_edit, document_type_delete]) +bind_links([DocumentTypeFilename], [document_type_filename_edit, document_type_filename_delete]) -register_links(['setup_document_type_metadata', 'document_type_filename_delete', 'document_type_create', 'document_type_filename_create', 'document_type_filename_edit', 'document_type_filename_list', 'document_type_list', 'document_type_document_list', 'document_type_edit', 'document_type_delete'], [document_type_list, document_type_create], menu_name='sidebar') -register_links(['document_type_filename_create', 'document_type_filename_list', 'document_type_filename_edit', 'document_type_filename_delete'], [document_type_filename_create], menu_name='sidebar') +bind_links(['setup_document_type_metadata', 'document_type_filename_delete', 'document_type_create', 'document_type_filename_create', 'document_type_filename_edit', 'document_type_filename_list', 'document_type_list', 'document_type_document_list', 'document_type_edit', 'document_type_delete'], [document_type_list, document_type_create], menu_name='sidebar') +bind_links(['document_type_filename_create', 'document_type_filename_list', 'document_type_filename_edit', 'document_type_filename_delete'], [document_type_filename_create], menu_name='sidebar') # Register document links -register_links(Document, [document_view_simple, document_edit, document_print, document_delete, document_download, document_find_duplicates, document_clear_transformations, document_create_siblings]) +bind_links([Document], [document_view_simple, document_edit, document_print, document_delete, document_download, document_find_duplicates, document_clear_transformations, document_create_siblings]) register_multi_item_links(['document_find_duplicates', 'folder_view', 'index_instance_list', 'document_type_document_list', 'search', 'results', 'document_group_view', 'document_list', 'document_list_recent'], [document_multiple_clear_transformations, document_multiple_delete, document_multiple_download]) # Document Version links -register_links(DocumentVersion, [document_version_revert, document_version_download]) +bind_links([DocumentVersion], [document_version_revert, document_version_download]) secondary_menu_links = [document_list_recent, document_list, document_create_multiple] -register_links(['document_list_recent', 'document_list', 'document_create', 'document_create_multiple', 'upload_interactive', 'staging_file_delete'], secondary_menu_links, menu_name='secondary_menu') -register_links(Document, secondary_menu_links, menu_name='secondary_menu') +bind_links(['document_list_recent', 'document_list', 'document_create', 'document_create_multiple', 'upload_interactive', 'staging_file_delete'], secondary_menu_links, menu_name='secondary_menu') +bind_links([Document], secondary_menu_links, menu_name='secondary_menu') # Document page links -register_links(DocumentPage, [ +bind_links([DocumentPage], [ document_page_transformation_list, document_page_view, document_page_text, document_page_edit, ]) # Document page navigation links -register_links(DocumentPage, [ +bind_links([DocumentPage], [ document_page_navigation_first, document_page_navigation_previous, document_page_navigation_next, document_page_navigation_last -], menu_name='related') +], menu_name='sidebar') -register_links(['document_page_view'], [document_page_rotate_left, document_page_rotate_right, document_page_zoom_in, document_page_zoom_out, document_page_view_reset], menu_name='form_header') +bind_links(['document_page_view'], [document_page_rotate_left, document_page_rotate_right, document_page_zoom_in, document_page_zoom_out, document_page_view_reset], menu_name='form_header') -register_links(DocumentPageTransformation, [document_page_transformation_edit, document_page_transformation_delete]) -register_links('document_page_transformation_list', [document_page_transformation_create], menu_name='sidebar') -register_links('document_page_transformation_create', [document_page_transformation_create], menu_name='sidebar') -register_links(['document_page_transformation_edit', 'document_page_transformation_delete'], [document_page_transformation_create], menu_name='sidebar') +bind_links([DocumentPageTransformation], [document_page_transformation_edit, document_page_transformation_delete]) +bind_links('document_page_transformation_list', [document_page_transformation_create], menu_name='sidebar') +bind_links('document_page_transformation_create', [document_page_transformation_create], menu_name='sidebar') +bind_links(['document_page_transformation_edit', 'document_page_transformation_delete'], [document_page_transformation_create], menu_name='sidebar') register_diagnostic('documents', _(u'Documents'), document_missing_list) @@ -176,22 +177,20 @@ register_model_list_columns(Document, [ register_top_menu( 'documents', - link={'famfam': 'page', 'text': _(u'documents'), 'view': 'document_list_recent'}, - children_path_regex=[ - r'^documents/[^t]', r'^metadata/[^s]', r'comments', r'tags/document', r'grouping/[^s]', r'history/list/for_object/documents', - ], + link=Link(sprite='page', text=_(u'documents'), view='document_list_recent', + children_url_regex=[r'^documents/[^t]', r'^metadata/[^s]', r'comments', r'tags/document', r'grouping/[^s]', r'history/list/for_object/documents'], children_view_regex=[r'document_acl', r'smart_link_instance'], - children_views=['document_folder_list', 'folder_add_document', 'document_index_list', 'upload_version', ], + children_views=['document_folder_list', 'folder_add_document', 'document_index_list', 'upload_version', ]), position=1 ) register_sidebar_template(['document_list_recent'], 'recent_document_list_help.html') register_sidebar_template(['document_type_list'], 'document_types_help.html') -register_links(Document, [document_view_simple], menu_name='form_header', position=0) -register_links(Document, [document_view_advanced], menu_name='form_header', position=1) -register_links(Document, [document_history_view], menu_name='form_header') -register_links(Document, [document_version_list], menu_name='form_header') +bind_links([Document], [document_view_simple], menu_name='form_header', position=0) +bind_links([Document], [document_view_advanced], menu_name='form_header', position=1) +bind_links([Document], [document_history_view], menu_name='form_header') +bind_links([Document], [document_version_list], menu_name='form_header') if (validate_path(document_settings.CACHE_PATH) == False) or (not document_settings.CACHE_PATH): setattr(document_settings, 'CACHE_PATH', tempfile.mkdtemp()) diff --git a/apps/documents/views.py b/apps/documents/views.py index 70846628a6..17e6ff9950 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -259,8 +259,6 @@ def document_edit(request, document_id): else: new_filename = form.cleaned_data['new_filename'] - print 'new_filename', new_filename - document.filename = new_filename document.description = form.cleaned_data['description'] document.save() diff --git a/apps/dynamic_search/__init__.py b/apps/dynamic_search/__init__.py index cb35778be2..b2e441fa50 100644 --- a/apps/dynamic_search/__init__.py +++ b/apps/dynamic_search/__init__.py @@ -7,7 +7,7 @@ from django.dispatch import receiver from django.core.management import call_command -from navigation.api import register_sidebar_template, register_links +from navigation.api import register_sidebar_template, bind_links, Link from documents.models import Document from scheduler.runtime import scheduler from signaler.signals import post_update_index, pre_update_index @@ -19,7 +19,9 @@ from .conf.settings import INDEX_UPDATE_INTERVAL logger = logging.getLogger(__name__) -search = {'text': _(u'search'), 'view': 'search', 'famfam': 'zoom'} +search = Link(text=_(u'search'), view='search', sprite='zoom') +search_advanced = Link(text=_(u'advanced search'), view='search_advanced', sprite='zoom_in') +search_again = Link(text=_(u'search again'), view='search_again', sprite='arrow_undo') register_sidebar_template(['search'], 'search_help.html') @@ -59,5 +61,7 @@ def search_index_update(): lock.release() pass +bind_links(['search', 'search_advanced', 'results'], [search, search_advanced], menu_name='form_header') +bind_links(['results'], [search_again], menu_name='sidebar') register_interval_job('search_index_update', _(u'Update the search index with the most recent modified documents.'), search_index_update, seconds=INDEX_UPDATE_INTERVAL) diff --git a/apps/feedback/__init__.py b/apps/feedback/__init__.py index 8e6c005ae4..7229d895ae 100644 --- a/apps/feedback/__init__.py +++ b/apps/feedback/__init__.py @@ -2,10 +2,10 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ -from navigation.api import register_links +from navigation.api import bind_links, Link from common import about_view, license_view -form_view = {'text': _('Feedback'), 'view': 'form_view', 'famfam': 'telephone'} +form_view = Link(text=_('Feedback'), view='form_view', sprite='telephone') -register_links(['form_view'], [about_view, license_view], menu_name='secondary_menu') -register_links(['form_view', 'about_view', 'license_view'], [form_view], menu_name='secondary_menu') +bind_links(['form_view'], [about_view, license_view], menu_name='secondary_menu') +bind_links(['form_view', 'about_view', 'license_view'], [form_view], menu_name='secondary_menu') diff --git a/apps/folders/__init__.py b/apps/folders/__init__.py index 8bbc3126b2..f72c92fd4f 100644 --- a/apps/folders/__init__.py +++ b/apps/folders/__init__.py @@ -2,8 +2,8 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ -from navigation.api import (register_links, register_top_menu, - register_multi_item_links, register_sidebar_template) +from navigation.api import (bind_links, register_top_menu, + register_multi_item_links, register_sidebar_template, Link) from documents.models import Document from documents.permissions import PERMISSION_DOCUMENT_VIEW from acls.api import class_permissions @@ -15,30 +15,30 @@ from .permissions import (PERMISSION_FOLDER_CREATE, PERMISSION_FOLDER_REMOVE_DOCUMENT, PERMISSION_FOLDER_VIEW, PERMISSION_FOLDER_ADD_DOCUMENT) -folder_list = {'text': _(u'folder list'), 'view': 'folder_list', 'famfam': 'folder_user'} -folder_create = {'text': _('create folder'), 'view': 'folder_create', 'famfam': 'folder_add', 'permissions': [PERMISSION_FOLDER_CREATE]} -folder_edit = {'text': _('edit'), 'view': 'folder_edit', 'args': 'object.pk', 'famfam': 'folder_edit', 'permissions': [PERMISSION_FOLDER_EDIT]} -folder_delete = {'text': _('delete'), 'view': 'folder_delete', 'args': 'object.pk', 'famfam': 'folder_delete', 'permissions': [PERMISSION_FOLDER_DELETE]} -folder_document_multiple_remove = {'text': _('remove from folder'), 'view': 'folder_document_multiple_remove', 'args': 'object.pk', 'famfam': 'delete', 'permissions': [PERMISSION_FOLDER_REMOVE_DOCUMENT]} -folder_view = {'text': _(u'folder documents'), 'view': 'folder_view', 'args': 'object.pk', 'famfam': 'folder_go', 'permissions': [PERMISSION_FOLDER_VIEW]} -folder_add_document = {'text': _('add to a folder'), 'view': 'folder_add_document', 'args': 'object.pk', 'famfam': 'add', 'permissions': [PERMISSION_FOLDER_ADD_DOCUMENT]} -document_folder_list = {'text': _(u'folders'), 'view': 'document_folder_list', 'args': 'object.pk', 'famfam': 'folder_user', 'permissions': [PERMISSION_DOCUMENT_VIEW], 'children_view_regex': [r'folder']} +folder_list = Link(text=_(u'folder list'), view='folder_list', sprite='folder_user') +folder_create = Link(text=_('create folder'), view='folder_create', sprite='folder_add', permissions=[PERMISSION_FOLDER_CREATE]) +folder_edit = Link(text=_('edit'), view='folder_edit', args='object.pk', sprite='folder_edit', permissions=[PERMISSION_FOLDER_EDIT]) +folder_delete = Link(text=_('delete'), view='folder_delete', args='object.pk', sprite='folder_delete', permissions=[PERMISSION_FOLDER_DELETE]) +folder_document_multiple_remove = Link(text=_('remove from folder'), view='folder_document_multiple_remove', args='object.pk', sprite='delete', permissions=[PERMISSION_FOLDER_REMOVE_DOCUMENT]) +folder_view = Link(text=_(u'folder documents'), view='folder_view', args='object.pk', sprite='folder_go', permissions=[PERMISSION_FOLDER_VIEW]) +folder_add_document = Link(text=_('add to a folder'), view='folder_add_document', args='object.pk', sprite='add', permissions=[PERMISSION_FOLDER_ADD_DOCUMENT]) +document_folder_list = Link(text=_(u'folders'), view='document_folder_list', args='object.pk', sprite='folder_user', permissions=[PERMISSION_DOCUMENT_VIEW], children_view_regex=[r'folder']) -folder_acl_list = {'text': _(u'ACLs'), 'view': 'folder_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} +folder_acl_list = Link(text=_(u'ACLs'), view='folder_acl_list', args='object.pk', sprite='lock', permissions=[ACLS_VIEW_ACL]) register_multi_item_links(['folder_view'], [folder_document_multiple_remove]) -register_links(Folder, [folder_view, folder_edit, folder_delete, folder_acl_list]) +bind_links([Folder], [folder_view, folder_edit, folder_delete, folder_acl_list]) -register_links([Folder, 'folder_list', 'folder_create'], [folder_list, folder_create], menu_name='secondary_menu') +bind_links([Folder, 'folder_list', 'folder_create'], [folder_list, folder_create], menu_name='secondary_menu') -register_top_menu(name='folders', link={'text': _('folders'), 'famfam': 'folder_user', 'view': 'folder_list'}, children_views=['folder_list', 'folder_create', 'folder_edit', 'folder_delete', 'folder_view', 'folder_document_multiple_remove']) +register_top_menu(name='folders', link=Link(text=_('folders'), sprite='folder_user', view='folder_list', children_views=['folder_list', 'folder_create', 'folder_edit', 'folder_delete', 'folder_view', 'folder_document_multiple_remove'])) -register_links(Document, [document_folder_list], menu_name='form_header') +bind_links([Document], [document_folder_list], menu_name='form_header') register_sidebar_template(['folder_list'], 'folders_help.html') -register_links(['document_folder_list', 'folder_add_document'], [folder_add_document], menu_name="sidebar") +bind_links(['document_folder_list', 'folder_add_document'], [folder_add_document], menu_name="sidebar") class_permissions(Folder, [ PERMISSION_FOLDER_EDIT, diff --git a/apps/folders/views.py b/apps/folders/views.py index 3c4a494aa6..257a0ec886 100644 --- a/apps/folders/views.py +++ b/apps/folders/views.py @@ -32,7 +32,6 @@ logger = logging.getLogger(__name__) def folder_list(request, queryset=None, extra_context=None): context = { 'title': _(u'folders'), - 'multi_select_as_buttons': True, 'extra_columns': [ {'name': _(u'created'), 'attribute': 'datetime_created'}, {'name': _(u'documents'), 'attribute': encapsulate(lambda x: x.folderdocument_set.count())} diff --git a/apps/history/__init__.py b/apps/history/__init__.py index b0b4025a3e..1ecda16eea 100644 --- a/apps/history/__init__.py +++ b/apps/history/__init__.py @@ -3,10 +3,8 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ from project_tools.api import register_tool +from navigation.api import Link from .permissions import PERMISSION_HISTORY_VIEW - -history_list = {'text': _(u'history'), 'view': 'history_list', 'famfam': 'book', 'icon': 'book.png', 'permissions': [PERMISSION_HISTORY_VIEW], 'children_view_regex': [r'history_[l,v]']} - -register_tool(history_list) +register_tool(Link(text=_(u'history'), view='history_list', sprite='book', icon='book.png', permissions=[PERMISSION_HISTORY_VIEW], children_view_regex=[r'history_[l,v]'])) diff --git a/apps/linking/__init__.py b/apps/linking/__init__.py index b6608ca829..14caa3309b 100644 --- a/apps/linking/__init__.py +++ b/apps/linking/__init__.py @@ -2,7 +2,7 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ -from navigation.api import register_links, register_sidebar_template +from navigation.api import bind_links, register_sidebar_template, Link from project_setup.api import register_setup from documents.permissions import PERMISSION_DOCUMENT_VIEW from documents.models import Document @@ -14,29 +14,29 @@ from .permissions import (PERMISSION_SMART_LINK_VIEW, PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_DELETE, PERMISSION_SMART_LINK_EDIT) -smart_link_instance_view_link = {'text': _(u'smart links actions'), 'view': 'smart_link_instance_view', 'famfam': 'page_link', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -smart_link_instances_for_document = {'text': _(u'smart links'), 'view': 'smart_link_instances_for_document', 'args': 'object.pk', 'famfam': 'page_link', 'permissions': [PERMISSION_DOCUMENT_VIEW]} +smart_link_instance_view_link = Link(text=_(u'smart links actions'), view='smart_link_instance_view', sprite='page_link', permissions=[PERMISSION_DOCUMENT_VIEW]) +smart_link_instances_for_document = Link(text=_(u'smart links'), view='smart_link_instances_for_document', args='object.pk', sprite='page_link', permissions=[PERMISSION_DOCUMENT_VIEW]) -smart_link_setup = {'text': _(u'smart links'), 'view': 'smart_link_list', 'icon': 'link.png', 'permissions': [PERMISSION_SMART_LINK_CREATE], 'children_view_regex': [r'smart_link_list', 'smart_link_create', 'smart_link_delete', 'smart_link_edit', 'smart_link_condition_']} -smart_link_list = {'text': _(u'smart links list'), 'view': 'smart_link_list', 'famfam': 'link', 'permissions': [PERMISSION_SMART_LINK_CREATE]} -smart_link_create = {'text': _(u'create new smart link'), 'view': 'smart_link_create', 'famfam': 'link_add', 'permissions': [PERMISSION_SMART_LINK_CREATE]} -smart_link_edit = {'text': _(u'edit'), 'view': 'smart_link_edit', 'args': 'object.pk', 'famfam': 'link_edit', 'permissions': [PERMISSION_SMART_LINK_EDIT]} -smart_link_delete = {'text': _(u'delete'), 'view': 'smart_link_delete', 'args': 'object.pk', 'famfam': 'link_delete', 'permissions': [PERMISSION_SMART_LINK_DELETE]} +smart_link_setup = Link(text=_(u'smart links'), view='smart_link_list', icon='link.png', permissions=[PERMISSION_SMART_LINK_CREATE], children_view_regex=[r'smart_link_list', 'smart_link_create', 'smart_link_delete', 'smart_link_edit', 'smart_link_condition_']) +smart_link_list = Link(text=_(u'smart links list'), view='smart_link_list', sprite='link', permissions=[PERMISSION_SMART_LINK_CREATE]) +smart_link_create = Link(text=_(u'create new smart link'), view='smart_link_create', sprite='link_add', permissions=[PERMISSION_SMART_LINK_CREATE]) +smart_link_edit = Link(text=_(u'edit'), view='smart_link_edit', args='object.pk', sprite='link_edit', permissions=[PERMISSION_SMART_LINK_EDIT]) +smart_link_delete = Link(text=_(u'delete'), view='smart_link_delete', args='object.pk', sprite='link_delete', permissions=[PERMISSION_SMART_LINK_DELETE]) -smart_link_condition_list = {'text': _(u'conditions'), 'view': 'smart_link_condition_list', 'args': 'object.pk', 'famfam': 'cog', 'permissions': [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_CREATE]} -smart_link_condition_create = {'text': _(u'create condition'), 'view': 'smart_link_condition_create', 'args': 'object.pk', 'famfam': 'cog_add', 'permissions': [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]} -smart_link_condition_edit = {'text': _(u'edit'), 'view': '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': 'smart_link_condition_delete', 'args': 'condition.pk', 'famfam': 'cog_delete', 'permissions': [PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]} +smart_link_condition_list = Link(text=_(u'conditions'), view='smart_link_condition_list', args='object.pk', sprite='cog', permissions=[PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_CREATE]) +smart_link_condition_create = Link(text=_(u'create condition'), view='smart_link_condition_create', args='object.pk', sprite='cog_add', permissions=[PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) +smart_link_condition_edit = Link(text=_(u'edit'), view='smart_link_condition_edit', args='condition.pk', sprite='cog_edit', permissions=[PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) +smart_link_condition_delete = Link(text=_(u'delete'), view='smart_link_condition_delete', args='condition.pk', sprite='cog_delete', permissions=[PERMISSION_SMART_LINK_CREATE, PERMISSION_SMART_LINK_EDIT]) -smart_link_acl_list = {'text': _(u'ACLs'), 'view': 'smart_link_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} +smart_link_acl_list = Link(text=_(u'ACLs'), view='smart_link_acl_list', args='object.pk', sprite='lock', permissions=[ACLS_VIEW_ACL]) -register_links(Document, [smart_link_instances_for_document], menu_name='form_header') +bind_links([Document], [smart_link_instances_for_document], menu_name='form_header') -register_links(SmartLink, [smart_link_edit, smart_link_delete, smart_link_condition_list, smart_link_acl_list]) -register_links([SmartLink, 'smart_link_list', 'smart_link_create'], [smart_link_list, smart_link_create], menu_name='secondary_menu') +bind_links([SmartLink], [smart_link_edit, smart_link_delete, smart_link_condition_list, smart_link_acl_list]) +bind_links([SmartLink, 'smart_link_list', '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(['smart_link_condition_list', 'smart_link_condition_create', 'smart_link_condition_edit', 'smart_link_condition_delete'], [smart_link_condition_create], menu_name='sidebar') +bind_links([SmartLinkCondition], [smart_link_condition_edit, smart_link_condition_delete]) +bind_links(['smart_link_condition_list', 'smart_link_condition_create', 'smart_link_condition_edit', 'smart_link_condition_delete'], [smart_link_condition_create], menu_name='sidebar') register_setup(smart_link_setup) register_sidebar_template(['smart_link_list'], 'smart_links_help.html') diff --git a/apps/linking/forms.py b/apps/linking/forms.py index 16400ece57..419945a8d7 100644 --- a/apps/linking/forms.py +++ b/apps/linking/forms.py @@ -35,9 +35,9 @@ class SmartLinkImageWidget(forms.widgets.Widget): %(text)s ''' % { - 'famfam': link.get('famfam', u'link'), - 'text': capfirst(link['text']), - 'action': reverse(link.get('view'), args=[value['current_document'].pk, value['smart_link_instance'].pk]) + 'famfam': getattr(link, 'famfam', u'link'), + 'text': capfirst(link.text), + 'action': reverse(link.view, args=[value['current_document'].pk, value['smart_link_instance'].pk]) }) output.append(u'') diff --git a/apps/mailer/__init__.py b/apps/mailer/__init__.py index 5d6e967d51..9774bc887e 100644 --- a/apps/mailer/__init__.py +++ b/apps/mailer/__init__.py @@ -2,16 +2,16 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ -from navigation.api import register_links +from navigation.api import bind_links, Link from documents.models import Document from acls.api import class_permissions from .permissions import PERMISSION_MAILING_LINK, PERMISSION_MAILING_SEND_DOCUMENT -send_document_link = {'text': _(u'email link'), 'view': 'send_document_link', 'args': 'object.pk', 'famfam': 'email_link', 'permissions': [PERMISSION_MAILING_LINK]} -send_document = {'text': _(u'email document'), 'view': 'send_document', 'args': 'object.pk', 'famfam': 'email_open', 'permissions': [PERMISSION_MAILING_SEND_DOCUMENT]} +send_document_link = Link(text=_(u'email link'), view='send_document_link', args='object.pk', sprite='email_link', permissions=[PERMISSION_MAILING_LINK]) +send_document = Link(text=_(u'email document'), view='send_document', args='object.pk', sprite='email_open', permissions=[PERMISSION_MAILING_SEND_DOCUMENT]) -register_links(Document, [send_document_link, send_document]) +bind_links([Document], [send_document_link, send_document]) class_permissions(Document, [ PERMISSION_MAILING_LINK, diff --git a/apps/main/__init__.py b/apps/main/__init__.py index e057b7b219..6044c27fcc 100644 --- a/apps/main/__init__.py +++ b/apps/main/__init__.py @@ -3,8 +3,7 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ from django.conf import settings -from navigation.api import register_top_menu -from navigation.api import register_links +from navigation.api import bind_links, Link, register_top_menu from project_setup.api import register_setup from project_tools.api import register_tool @@ -30,16 +29,16 @@ __version_info__ = { def is_superuser(context): return context['request'].user.is_staff or context['request'].user.is_superuser -maintenance_menu = {'text': _(u'maintenance'), 'view': 'maintenance_menu', 'famfam': 'wrench', 'icon': 'wrench.png'} -statistics = {'text': _(u'statistics'), 'view': 'statistics', 'famfam': 'table', 'icon': 'blackboard_sum.png', 'condition': is_superuser, 'children_view_regex': [r'statistics']} -diagnostics = {'text': _(u'diagnostics'), 'view': 'diagnostics', 'famfam': 'pill', 'icon': 'pill.png'} -sentry = {'text': _(u'sentry'), 'view': 'sentry', 'famfam': 'bug', 'icon': 'bug.png', 'condition': is_superuser} -admin_site = {'text': _(u'admin site'), 'view': 'admin:index', 'famfam': 'keyboard', 'icon': 'keyboard.png', 'condition': is_superuser} +maintenance_menu = Link(text=_(u'maintenance'), view='maintenance_menu', sprite='wrench', icon='wrench.png') +statistics = Link(text=_(u'statistics'), view='statistics', sprite='table', icon='blackboard_sum.png', condition=is_superuser, children_view_regex=[r'statistics']) +diagnostics = Link(text=_(u'diagnostics'), view='diagnostics', sprite='pill', icon='pill.png') +sentry = Link(text=_(u'sentry'), view='sentry', sprite='bug', icon='bug.png', condition=is_superuser) +admin_site = Link(text=_(u'admin site'), view='admin:index', sprite='keyboard', icon='keyboard.png', condition=is_superuser) if not DISABLE_HOME_VIEW: - register_top_menu('home', link={'text': _(u'home'), 'view': 'home', 'famfam': 'house'}, position=0) + register_top_menu('home', link=Link(text=_(u'home'), view='home', sprite='house'), position=0) if not SIDE_BAR_SEARCH: - register_top_menu('search', link={'text': _(u'search'), 'view': 'search', 'famfam': 'zoom'}, children_path_regex=[r'^search/']) + register_top_menu('search', link=Link(text=_(u'search'), view='search', sprite='zoom', children_url_regex=[r'^search/'])) def get_version(): diff --git a/apps/main/api.py b/apps/main/api.py index f8a48ce78e..f22e0150c3 100644 --- a/apps/main/api.py +++ b/apps/main/api.py @@ -7,7 +7,7 @@ tools = {} def register_diagnostic(namespace, title, link): namespace_dict = diagnostics.get(namespace, {'title': None, 'links': []}) namespace_dict['title'] = title - link['url'] = link.get('url', reverse_lazy(link['view'])) + link.url = getattr(link, 'url', reverse_lazy(link.view)) namespace_dict['links'].append(link) diagnostics[namespace] = namespace_dict @@ -16,6 +16,6 @@ def register_maintenance_links(links, title=None, namespace=None): namespace_dict = tools.get(namespace, {'title': None, 'links': []}) namespace_dict['title'] = title for link in links: - link['url'] = link.get('url', reverse_lazy(link['view'])) + link.url = getattr(link, 'url', reverse_lazy(link.view)) namespace_dict['links'].append(link) tools[namespace] = namespace_dict diff --git a/apps/main/templates/base.html b/apps/main/templates/base.html index 86fa6495d1..aab2d8fb24 100644 --- a/apps/main/templates/base.html +++ b/apps/main/templates/base.html @@ -240,47 +240,27 @@ {% endblock %} {% block web_theme_secondary_navigation %} - {% if navigation_object_list %} - {% for navigation_object_dict in navigation_object_list %} - {% copy_variable navigation_object_dict.object as "navigation_object_name" %} - {% get_object_navigation_links "form_header" as form_navigation_links %} - {% if form_navigation_links %} -
- -
- {% endif %} - {% endfor %} - {% else %} - {% get_object_navigation_links "form_header" as form_navigation_links %} - {% if form_navigation_links %} + {% get_object_navigation_links "form_header" as form_header_navigation_links %} + {% if form_header_navigation_links %} +
+ {% for object_reference, object_links in form_header_navigation_links.items %}
-
- {% endif %} +
+ {% endfor %} + {% endif %} {% endblock %} @@ -298,106 +278,61 @@ {% endwith %} {% endif %} - {% get_object_navigation_links "secondary_menu" as object_navigation_links %} - {% if object_navigation_links %} + {% get_object_navigation_links "secondary_menu" as secondary_menu_navigation_links %} + {% if secondary_menu_navigation_links %}

{% trans "Secondary menu" %}

{% endif %} - {% if navigation_object_list %} - {% for navigation_object_dict in navigation_object_list %} - {% copy_variable navigation_object_dict.object as "navigation_object_name" %} - {% get_object_navigation_links as object_navigation_links %} - {% if object_navigation_links %} -
- {% if navigation_object %} - {% if navigation_object_dict.name %} -

{% blocktrans with navigation_object_dict.name as name %}Actions for {{ name }}: {{ navigation_object }}{% endblocktrans %}

- {% else %} -

{% blocktrans %}Actions for: {{ navigation_object }}{% endblocktrans %}

- {% endif %} + + {% get_object_navigation_links as secondary_menu_navigation_links %} + {% if secondary_menu_navigation_links %} +
+ {% for object_reference, object_links in secondary_menu_navigation_links.items %} + {% if object_reference %} + {% if navigation_object_dict.name %} +

{% blocktrans with navigation_object_dict.name as name %}Actions for {{ name }}: {{ object_reference }}{% endblocktrans %}

{% else %} -

{% trans "Available actions" %}

- {% endif %} - -
- {% endif %} - {% get_object_navigation_links "related" as object_navigation_links %} - {% if object_navigation_links %} -
-

{% trans "Related actions" %}

- -
- {% endif %} - {% get_object_navigation_links "sidebar" as object_navigation_links %} - {% if object_navigation_links %} -
-

{% trans "Other available actions" %}

- -
- {% endif %} - {% endfor %} - {% else %} - {% get_object_navigation_links as object_navigation_links %} - {% if object_navigation_links %} -
- {% if navigation_object %} - {% if object_name %} -

{% blocktrans %}Actions for {{ object_name }}: {{ navigation_object }}{% endblocktrans %}

- {% else %} -

{% blocktrans %}Actions for: {{ navigation_object }}{% endblocktrans %}

+

{% blocktrans %}Actions for: {{ object_reference }}{% endblocktrans %}

{% endif %} {% else %} -

{% trans "Actions" %}

- {% endif %} +

{% trans "Available actions" %}

+ {% endif %} -
- {% endif %} - {% get_object_navigation_links "related" as object_navigation_links %} - {% if object_navigation_links %} -
-

{% trans "Related actions" %}

- -
- {% endif %} + {% endfor %} +
{% endif %} - {% get_object_navigation_links "sidebar" as object_navigation_links %} - {% if object_navigation_links %} + {% get_object_navigation_links "sidebar" as sidebar_navigation_links %} + {% if sidebar_navigation_links %}

{% trans "Other available actions" %}

- {% endif %} + {% endif %} {% get_sidebar_templates as sidebar_templates %} {% for template in sidebar_templates %} diff --git a/apps/main/views.py b/apps/main/views.py index 12aabda9e5..75d04971ff 100644 --- a/apps/main/views.py +++ b/apps/main/views.py @@ -32,7 +32,7 @@ def maintenance_menu(request): user_tools[namespace].setdefault('links', []) for link in values['links']: try: - permissions = link.get('permissions', []) + permissions = link.permissions Permission.objects.check_permissions(request.user, permissions) user_tools[namespace]['links'].append(link) except PermissionDenied: diff --git a/apps/metadata/__init__.py b/apps/metadata/__init__.py index 9f7ea6bb6e..6510383601 100644 --- a/apps/metadata/__init__.py +++ b/apps/metadata/__init__.py @@ -2,8 +2,8 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ -from navigation.api import (register_links, register_multi_item_links, - register_sidebar_template) +from navigation.api import (bind_links, register_multi_item_links, + register_sidebar_template, Link) from documents.models import Document, DocumentType from documents.permissions import PERMISSION_DOCUMENT_TYPE_EDIT from project_setup.api import register_setup @@ -18,37 +18,37 @@ from .permissions import (PERMISSION_METADATA_DOCUMENT_EDIT, PERMISSION_METADATA_SET_CREATE, PERMISSION_METADATA_SET_DELETE, PERMISSION_METADATA_SET_VIEW) -metadata_edit = {'text': _(u'edit metadata'), 'view': 'metadata_edit', 'args': 'object.pk', 'famfam': 'xhtml_go', 'permissions': [PERMISSION_METADATA_DOCUMENT_EDIT]} -metadata_view = {'text': _(u'metadata'), 'view': 'metadata_view', 'args': 'object.pk', 'famfam': 'xhtml_go', 'permissions': [PERMISSION_METADATA_DOCUMENT_VIEW], 'children_view_regex': ['metadata']} -metadata_multiple_edit = {'text': _(u'edit metadata'), 'view': 'metadata_multiple_edit', 'famfam': 'xhtml_go', 'permissions': [PERMISSION_METADATA_DOCUMENT_EDIT]} -metadata_add = {'text': _(u'add metadata'), 'view': 'metadata_add', 'args': 'object.pk', 'famfam': 'xhtml_add', 'permissions': [PERMISSION_METADATA_DOCUMENT_ADD]} -metadata_multiple_add = {'text': _(u'add metadata'), 'view': 'metadata_multiple_add', 'famfam': 'xhtml_add', 'permissions': [PERMISSION_METADATA_DOCUMENT_ADD]} -metadata_remove = {'text': _(u'remove metadata'), 'view': 'metadata_remove', 'args': 'object.pk', 'famfam': 'xhtml_delete', 'permissions': [PERMISSION_METADATA_DOCUMENT_REMOVE]} -metadata_multiple_remove = {'text': _(u'remove metadata'), 'view': 'metadata_multiple_remove', 'famfam': 'xhtml_delete', 'permissions': [PERMISSION_METADATA_DOCUMENT_REMOVE]} +metadata_edit = Link(text=_(u'edit metadata'), view='metadata_edit', args='object.pk', sprite='xhtml_go', permissions=[PERMISSION_METADATA_DOCUMENT_EDIT]) +metadata_view = Link(text=_(u'metadata'), view='metadata_view', args='object.pk', sprite='xhtml_go', permissions=[PERMISSION_METADATA_DOCUMENT_VIEW])#, children_view_regex=['metadata']) +metadata_multiple_edit = Link(text=_(u'edit metadata'), view='metadata_multiple_edit', sprite='xhtml_go', permissions=[PERMISSION_METADATA_DOCUMENT_EDIT]) +metadata_add = Link(text=_(u'add metadata'), view='metadata_add', args='object.pk', sprite='xhtml_add', permissions=[PERMISSION_METADATA_DOCUMENT_ADD]) +metadata_multiple_add = Link(text=_(u'add metadata'), view='metadata_multiple_add', sprite='xhtml_add', permissions=[PERMISSION_METADATA_DOCUMENT_ADD]) +metadata_remove = Link(text=_(u'remove metadata'), view='metadata_remove', args='object.pk', sprite='xhtml_delete', permissions=[PERMISSION_METADATA_DOCUMENT_REMOVE]) +metadata_multiple_remove = Link(text=_(u'remove metadata'), view='metadata_multiple_remove', sprite='xhtml_delete', permissions=[PERMISSION_METADATA_DOCUMENT_REMOVE]) -setup_metadata_type_list = {'text': _(u'metadata types'), 'view': 'setup_metadata_type_list', 'famfam': 'xhtml_go', 'icon': 'xhtml.png', 'permissions': [PERMISSION_METADATA_TYPE_VIEW], 'children_view_regex': [r'setup_metadata_type']} -setup_metadata_type_edit = {'text': _(u'edit'), 'view': 'setup_metadata_type_edit', 'args': 'object.pk', 'famfam': 'xhtml', 'permissions': [PERMISSION_METADATA_TYPE_EDIT]} -setup_metadata_type_delete = {'text': _(u'delete'), 'view': 'setup_metadata_type_delete', 'args': 'object.pk', 'famfam': 'xhtml_delete', 'permissions': [PERMISSION_METADATA_TYPE_DELETE]} -setup_metadata_type_create = {'text': _(u'create new'), 'view': 'setup_metadata_type_create', 'famfam': 'xhtml_add', 'permissions': [PERMISSION_METADATA_TYPE_CREATE]} +setup_metadata_type_list = Link(text=_(u'metadata types'), view='setup_metadata_type_list', sprite='xhtml_go', icon='xhtml.png', permissions=[PERMISSION_METADATA_TYPE_VIEW])#, children_view_regex=[r'setup_metadata_type']) +setup_metadata_type_edit = Link(text=_(u'edit'), view='setup_metadata_type_edit', args='object.pk', sprite='xhtml', permissions=[PERMISSION_METADATA_TYPE_EDIT]) +setup_metadata_type_delete = Link(text=_(u'delete'), view='setup_metadata_type_delete', args='object.pk', sprite='xhtml_delete', permissions=[PERMISSION_METADATA_TYPE_DELETE]) +setup_metadata_type_create = Link(text=_(u'create new'), view='setup_metadata_type_create', sprite='xhtml_add', permissions=[PERMISSION_METADATA_TYPE_CREATE]) -setup_metadata_set_list = {'text': _(u'metadata sets'), 'view': 'setup_metadata_set_list', 'famfam': 'table', 'icon': 'table.png', 'permissions': [PERMISSION_METADATA_SET_VIEW], 'children_view_regex': [r'setup_metadata_set']} -setup_metadata_set_edit = {'text': _(u'edit'), 'view': 'setup_metadata_set_edit', 'args': 'object.pk', 'famfam': 'table_edit', 'permissions': [PERMISSION_METADATA_SET_EDIT]} -setup_metadata_set_delete = {'text': _(u'delete'), 'view': 'setup_metadata_set_delete', 'args': 'object.pk', 'famfam': 'table_delete', 'permissions': [PERMISSION_METADATA_SET_DELETE]} -setup_metadata_set_create = {'text': _(u'create new'), 'view': 'setup_metadata_set_create', 'famfam': 'table_add', 'permissions': [PERMISSION_METADATA_SET_CREATE]} +setup_metadata_set_list = Link(text=_(u'metadata sets'), view='setup_metadata_set_list', sprite='table', icon='table.png', permissions=[PERMISSION_METADATA_SET_VIEW])#, children_view_regex=[r'setup_metadata_set']) +setup_metadata_set_edit = Link(text=_(u'edit'), view='setup_metadata_set_edit', args='object.pk', sprite='table_edit', permissions=[PERMISSION_METADATA_SET_EDIT]) +setup_metadata_set_delete = Link(text=_(u'delete'), view='setup_metadata_set_delete', args='object.pk', sprite='table_delete', permissions=[PERMISSION_METADATA_SET_DELETE]) +setup_metadata_set_create = Link(text=_(u'create new'), view='setup_metadata_set_create', sprite='table_add', permissions=[PERMISSION_METADATA_SET_CREATE]) -setup_document_type_metadata = {'text': _(u'default metadata'), 'view': 'setup_document_type_metadata', 'args': 'document_type.pk', 'famfam': 'xhtml', 'permissions': [PERMISSION_DOCUMENT_TYPE_EDIT]} +setup_document_type_metadata = Link(text=_(u'default metadata'), view='setup_document_type_metadata', args='document_type.pk', sprite='xhtml', permissions=[PERMISSION_DOCUMENT_TYPE_EDIT]) -register_links(['metadata_add', 'metadata_edit', 'metadata_remove', 'metadata_view'], [metadata_add, metadata_edit, metadata_remove], menu_name='sidebar') -register_links(Document, [metadata_view], menu_name='form_header') +bind_links(['metadata_add', 'metadata_edit', 'metadata_remove', 'metadata_view'], [metadata_add, metadata_edit, metadata_remove], menu_name='sidebar') +bind_links([Document], [metadata_view], menu_name='form_header') register_multi_item_links(['document_find_duplicates', 'folder_view', 'index_instance_list', 'document_type_document_list', 'search', 'results', 'document_group_view', 'document_list', 'document_list_recent'], [metadata_multiple_add, metadata_multiple_edit, metadata_multiple_remove]) -register_links(MetadataType, [setup_metadata_type_edit, setup_metadata_type_delete]) -register_links([MetadataType, 'setup_metadata_type_list', 'setup_metadata_type_create'], [setup_metadata_type_list, setup_metadata_type_create], menu_name='secondary_menu') +bind_links([MetadataType], [setup_metadata_type_edit, setup_metadata_type_delete]) +bind_links([MetadataType, 'setup_metadata_type_list', 'setup_metadata_type_create'], [setup_metadata_type_list, setup_metadata_type_create], menu_name='secondary_menu') -register_links(MetadataSet, [setup_metadata_set_edit, setup_metadata_set_delete]) -register_links([MetadataSet, 'setup_metadata_set_list', 'setup_metadata_set_create'], [setup_metadata_set_list, setup_metadata_set_create], menu_name='secondary_menu') +bind_links([MetadataSet], [setup_metadata_set_edit, setup_metadata_set_delete]) +bind_links([MetadataSet, 'setup_metadata_set_list', 'setup_metadata_set_create'], [setup_metadata_set_list, setup_metadata_set_create], menu_name='secondary_menu') -register_links(DocumentType, [setup_document_type_metadata]) +bind_links([DocumentType], [setup_document_type_metadata]) metadata_type_setup_views = ['setup_metadata_type_list', 'setup_metadata_type_edit', 'setup_metadata_type_delete', 'setup_metadata_type_create'] metadata_set_setup_views = ['setup_metadata_set_list', 'setup_metadata_set_edit', 'setup_metadata_set_delete', 'setup_metadata_set_create'] diff --git a/apps/navigation/__init__.py b/apps/navigation/__init__.py index e69de29bb2..5b5faffadc 100644 --- a/apps/navigation/__init__.py +++ b/apps/navigation/__init__.py @@ -0,0 +1,5 @@ +from __future__ import absolute_import + +from elementtree.ElementTree import Element + +main_menu = Element('root') diff --git a/apps/navigation/api.py b/apps/navigation/api.py index 56bb037245..efdc441cfa 100644 --- a/apps/navigation/api.py +++ b/apps/navigation/api.py @@ -1,80 +1,180 @@ -object_navigation = {} +from __future__ import absolute_import + +import urlparse +import urllib +import logging +import re + +from django.template import (VariableDoesNotExist, Variable) +from django.utils.encoding import smart_str, smart_unicode +from django.core.urlresolvers import reverse, NoReverseMatch +from django.utils.http import urlquote, urlencode +from django.utils.translation import ugettext_lazy as _ + +from elementtree.ElementTree import SubElement + +from .utils import (resolve_to_name, resolve_arguments, + get_navigation_objects) +from . import main_menu + multi_object_navigation = {} model_list_columns = {} sidebar_templates = {} -top_menu_entries = [] + +link_binding = {} + +logger = logging.getLogger(__name__) -def register_multi_item_links(src, links, menu_name=None): - """ - Register a multiple item action action to be displayed in the - generic list template - """ - - multi_object_navigation.setdefault(menu_name, {}) - if hasattr(src, '__iter__'): - for one_src in src: - multi_object_navigation[menu_name].setdefault(one_src, {'links': []}) - multi_object_navigation[menu_name][one_src]['links'].extend(links) - else: - multi_object_navigation[menu_name].setdefault(src, {'links': []}) - multi_object_navigation[menu_name][src]['links'].extend(links) +class ResolvedLink(object): + active = False + url = '#' + text = _('Unnamed link') -def register_links(src, links, menu_name=None, position=None): - """ - Associate a link to a model a view, or an url - """ +class Link(object): + def __init__(self, text, view, klass=None, args=None, sprite=None, + icon=None, permissions=None, condition=None, conditional_disable=None, + description=None, dont_mark_active=False, children_view_regex=None, + keep_query=False, children_classes=None, children_url_regex=None, + children_views=None, conditional_highlight=None): - object_navigation.setdefault(menu_name, {}) - if hasattr(src, '__iter__'): - for one_src in src: - object_navigation[menu_name].setdefault(one_src, {'links': []}) - if position is not None: - for link in reversed(links): - object_navigation[menu_name][one_src]['links'].insert(position, link) - else: - object_navigation[menu_name][one_src]['links'].extend(links) - else: - object_navigation[menu_name].setdefault(src, {'links': []}) - if position is not None: - for link in reversed(links): - object_navigation[menu_name][src]['links'].insert(position, link) + self.text = text + self.view = view + self.args = args or {} + #self.kwargs = kwargs or {} + self.sprite = sprite + self.icon = icon + self.permissions = permissions or [] + self.condition = condition + self.conditional_disable = conditional_disable + self.description = description + self.dont_mark_active = dont_mark_active + self.klass = klass + self.keep_query = keep_query + self.conditional_highlight = conditional_highlight # Used by dynamic sources + self.children_views = children_views or [] + self.children_classes = children_classes or [] + self.children_url_regex = children_url_regex or [] + self.children_view_regex = children_view_regex or [] + + def resolve(self, context): + # TODO: don't calculate these if passed in an argument + request = Variable('request').resolve(context) + current_path = request.META['PATH_INFO'] + current_view = resolve_to_name(current_path) + + # 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', u'/')))) + query_string = urlparse.urlparse(previous_path).query + parsed_query_string = urlparse.parse_qs(query_string) + + logger.debug('condition: %s', self.condition) + + # Check to see if link has conditional display + if self.condition: + condition_result = self.condition(context) else: - object_navigation[menu_name][src]['links'].extend(links) + condition_result = True + + logger.debug('condition_result: %s', condition_result) + + if condition_result: + resolved_link = ResolvedLink() + resolved_link.text = self.text + resolved_link.sprite = self.sprite + resolved_link.icon = self.icon + resolved_link.permissions = self.permissions + + try: + #args, kwargs = resolve_arguments(context, self.get('args', {})) + args, kwargs = 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 = u'%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 = u'%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 + + if current_view in self.children_views: + resolved_link.active = True + + # TODO: eliminate url_regexes and use new tree base main menu + for child_url_regex in self.children_url_regex: + if re.compile(child_url_regex).match(current_path.lstrip('/')): + resolved_link.active = True + + for children_view_regex in self.children_view_regex: + if re.compile(children_view_regex).match(current_view): + resolved_link.active = True + + for cls in self.children_classes: + object_list = get_navigation_objects(context) + if object_list: + if type(object_list[0]['object']) == cls or object_list[0]['object'] == cls: + #new_link['active'] = True + resolved_link.active = True + + return resolved_link -def register_top_menu(name, link, children_views=None, - children_path_regex=None, children_view_regex=None, - position=None): +def bind_links(sources, links, menu_name=None, position=0): + """ + Associate a link to a model, a view, or an url + """ + link_binding.setdefault(menu_name, {}) + for source in sources: + link_binding[menu_name].setdefault(source, {'links': []}) + link_binding[menu_name][source]['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 """ + new_menu = SubElement(main_menu, name, link=link, position=position) - entry = {'link': link, 'name': name} - if children_views: - entry['children_views'] = children_views - if children_path_regex: - entry['children_path_regex'] = children_path_regex - if children_view_regex: - entry['children_view_regex'] = children_view_regex - 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) + sorted_menus = sorted(main_menu.getchildren(), key=lambda k: (k.get('position') < 0, k.get('position'))) + main_menu.clear() - sort_menu_entries() - - return entry + for menu in sorted_menus: + main_menu.append(menu) - -def sort_menu_entries(): - global top_menu_entries - top_menu_entries = sorted(top_menu_entries, key=lambda k: (k['position'] < 0, k['position'])) + return new_menu def register_model_list_columns(model, columns): @@ -91,3 +191,75 @@ def register_sidebar_template(source_list, template_name): for source in source_list: sidebar_templates.setdefault(source, []) sidebar_templates[source].append(template_name) + + +def register_multi_item_links(sources, links, menu_name=None): + """ + Register a multiple item action action to be displayed in the + generic list template + """ + multi_object_navigation.setdefault(menu_name, {}) + for source in sources: + multi_object_navigation[menu_name].setdefault(source, {'links': []}) + multi_object_navigation[menu_name][source]['links'].extend(links) + + +def get_context_navigation_links(context, menu_name=None, links_dict=link_binding): + request = Variable('request').resolve(context) + current_path = request.META['PATH_INFO'] + current_view = resolve_to_name(current_path) + context_links = {} + + # Don't fudge with the original global dictionary + # TODO: fix this + links_dict = links_dict.copy() + + # TODO: doesn't appear to be used + ''' + try: + """ + Override the navigation links dictionary with the provided + link list + """ + navigation_object_links = Variable('overrided_object_links').resolve(context) + if navigation_object_links: + return [link.resolve(context) for link in navigation_object_links] + except VariableDoesNotExist: + pass + ''' + # TODO: who uses this? Remove if no one. + # Dynamic sources + # TODO: improve name to 'injected...' + try: + """ + Check for and inject a temporary navigation dictionary + """ + temp_navigation_links = Variable('temporary_navigation_links').resolve(context) + if temp_navigation_links: + links_dict.update(temp_navigation_links) + except VariableDoesNotExist: + pass + + try: + view_links = links_dict[menu_name][current_view]['links'] + if view_links: + context_links.setdefault(None, []) + + for link in view_links: + context_links[None].append(link.resolve(context)) + except KeyError: + pass + + for resolved_object, object_properties in get_navigation_objects(context).items(): + try: + resolved_object_reference = resolved_object + object_links = links_dict[menu_name][type(resolved_object_reference)]['links'] + if object_links: + context_links.setdefault(resolved_object_reference, []) + + for link in object_links: + context_links[resolved_object_reference].append(link.resolve(context)) + except KeyError: + pass + + return context_links diff --git a/apps/navigation/templates/generic_link_instance.html b/apps/navigation/templates/generic_link_instance.html index 098810ee13..a1f18baf8b 100644 --- a/apps/navigation/templates/generic_link_instance.html +++ b/apps/navigation/templates/generic_link_instance.html @@ -3,7 +3,7 @@ {% get_main_setting "DISABLE_ICONS" as disable_icons %} {% if link.disabled %} - {% if link.famfam and not disable_icons %}{% endif %}{{ link.text|capfirst }}{% if link.error %} - {{ link.error }}{% endif %}{% if link.active and not hide_active_anchor %}{% endif %}{% if horizontal %}{% if not forloop.last %} | {% endif %}{% endif %} + {% if link.sprite and not disable_icons %}{% endif %}{{ link.text|capfirst }}{% if link.error %} - {{ link.error }}{% endif %}{% if link.active and not hide_active_anchor %}{% endif %}{% if horizontal %}{% if not forloop.last %} | {% endif %}{% endif %} {% else %} - {% if link.famfam and not disable_icons %}{% endif %}{{ link.text|capfirst }}{% if link.error %} - {{ link.error }}{% endif %}{% if link.active and not hide_active_anchor %}{% endif %}{% if horizontal %}{% if not forloop.last %} | {% endif %}{% endif %} + {% if link.sprite and not disable_icons %}{% endif %}{{ link.text|capfirst }}{% if link.error %} - {{ link.error }}{% endif %}{% if link.active and not hide_active_anchor %}{% endif %}{% if horizontal %}{% if not forloop.last %} | {% endif %}{% endif %} {% endif %} diff --git a/apps/navigation/templates/generic_navigation.html b/apps/navigation/templates/generic_navigation.html index bff532fbee..722d3e6857 100644 --- a/apps/navigation/templates/generic_navigation.html +++ b/apps/navigation/templates/generic_navigation.html @@ -1,5 +1,5 @@ - {% for link in object_navigation_links %} + {% for link in links %} {% include "generic_subnavigation.html" %} {% endfor %} diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index d4533c09a3..aefcef42af 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -1,49 +1,27 @@ -from __future__ import absolute_import +from __future__ import absolute_import import copy import re -import urlparse -import urllib +import logging -from django.core.urlresolvers import reverse, NoReverseMatch +from django.core.urlresolvers import reverse from django.template import (TemplateSyntaxError, Library, - VariableDoesNotExist, Node, Variable) -from django.utils.text import unescape_string_literal + Node, Variable, VariableDoesNotExist) from django.utils.translation import ugettext as _ -from django.utils.encoding import smart_str, force_unicode, smart_unicode -from common.utils import urlquote - -from ..api import (object_navigation, multi_object_navigation, - top_menu_entries, sidebar_templates) +from ..api import (link_binding, multi_object_navigation, + sidebar_templates, get_context_navigation_links) from ..forms import MultiItemForm -from ..utils import resolve_to_name +from ..utils import resolve_to_name, resolve_template_variable +from .. import main_menu register = Library() +logger = logging.getLogger(__name__) class TopMenuNavigationNode(Node): def render(self, context): - request = Variable('request').resolve(context) - current_path = request.META['PATH_INFO'] - current_view = resolve_to_name(current_path) - - all_menu_links = [entry.get('link', {}) for entry in top_menu_entries] - menu_links = resolve_links(context, all_menu_links, current_view, current_path) - - for index, link in enumerate(top_menu_entries): - if current_view in link.get('children_views', []): - menu_links[index]['active'] = True - - for child_path_regex in link.get('children_path_regex', []): - if re.compile(child_path_regex).match(current_path.lstrip('/')): - menu_links[index]['active'] = True - - for children_view_regex in link.get('children_view_regex', []): - if re.compile(children_view_regex).match(current_view): - menu_links[index]['active'] = True - - context['menu_links'] = menu_links + context['menu_links'] = [menu.get('link').resolve(context) for menu in main_menu.getchildren()] return '' @@ -52,198 +30,22 @@ def get_top_menu_links(parser, token): return TopMenuNavigationNode() -def resolve_arguments(context, src_args): - args = [] - kwargs = {} - if type(src_args) == type([]): - for i in src_args: - val = resolve_template_variable(context, i) - if val: - args.append(val) - elif type(src_args) == type({}): - 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 - - -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): - print 'parsed_query_string', parsed_query_string - new_link['url'] = urlquote(new_link['url'], parsed_query_string) - except NoReverseMatch, err: - new_link['url'] = '#' - new_link['error'] = err - 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): - 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 - - if current_view in link.get('children_views', []): - new_link['active'] = True - - for child_url_regex in link.get('children_url_regex', []): - if re.compile(child_url_regex).match(current_path.lstrip('/')): - new_link['active'] = True - - for children_view_regex in link.get('children_view_regex', []): - if re.compile(children_view_regex).match(current_view): - new_link['active'] = True - - for cls in link.get('children_classes', []): - obj, object_name = get_navigation_object(context) - if type(obj) == cls or obj == cls: - new_link['active'] = True - - context_links.append(new_link) - return context_links - - -def get_navigation_object(context): - 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): - request = Variable('request').resolve(context) - current_path = request.META['PATH_INFO'] - current_view = resolve_to_name(current_path) - 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', u'/')))) - query_string = urlparse.urlparse(previous_path).query - parsed_query_string = urlparse.parse_qs(query_string) - - try: - """ - Override the navigation links dictionary with the provided - link list - """ - navigation_object_links = Variable('overrided_object_links').resolve(context) - if navigation_object_links: - return [link for link in resolve_links(context, navigation_object_links, current_view, current_path, parsed_query_string)] - except VariableDoesNotExist: - pass - - try: - """ - Check for and inject a temporary navigation dictionary - """ - temp_navigation_links = Variable('temporary_navigation_links').resolve(context) - if temp_navigation_links: - links_dict.update(temp_navigation_links) - except VariableDoesNotExist: - pass - - 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 - - obj, object_name = get_navigation_object(context) - - try: - links = links_dict[menu_name][type(obj)]['links'] - for link in resolve_links(context, links, current_view, current_path, parsed_query_string): - context_links.append(link) - except KeyError: - pass - - 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'): + def __init__(self, menu_name=None, links_dict=link_binding, var_name='object_navigation_links'): self.menu_name = menu_name self.links_dict = links_dict self.var_name = var_name + logger.debug('menu_name: %s' % menu_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 + context[self.var_name] = get_context_navigation_links(context, menu_name, links_dict=self.links_dict) return '' -@register.tag -def get_object_navigation_links(parser, token): +@register.tag(name='get_object_navigation_links') +def get_context_navigation_links_tag(parser, token): + logger.debug('getting links') tag_name, arg = token.contents.split(None, 1) m = re.search(r'("?\w+"?)?.?as (\w+)', arg) @@ -256,14 +58,28 @@ def get_object_navigation_links(parser, token): @register.inclusion_tag('generic_navigation.html', takes_context=True) def object_navigation_template(context): + # Used by list subtemplate new_context = copy.copy(context) - new_context.update({ - 'horizontal': True, - 'object_navigation_links': _get_object_navigation_links(context) - }) + try: + object_variable_name = Variable('navigation_object_name').resolve(context) + except VariableDoesNotExist: + object_variable_name = 'object' + finally: + logger.debug('object_variable_name: %s' % object_variable_name) + + try: + object_reference = Variable(object_variable_name).resolve(context) + except VariableDoesNotExist: + pass + else: + new_context.update({ + 'horizontal': True, + 'links': get_context_navigation_links(context).get(object_reference) + }) + return new_context - - + + @register.tag def get_multi_item_links(parser, token): tag_name, arg = token.contents.split(None, 1) @@ -277,9 +93,14 @@ def get_multi_item_links(parser, token): @register.inclusion_tag('generic_form_instance.html', takes_context=True) def get_multi_item_links_form(context): + logger.debug('starting') + links = [] + for object_reference, object_links in get_context_object_navigation_links(context, links_dict=multi_object_navigation).items(): + links.extend(object_links) + new_context = copy.copy(context) new_context.update({ - 'form': MultiItemForm(actions=[(link['url'], link['text']) for link in _get_object_navigation_links(context, links_dict=multi_object_navigation)]), + 'form': MultiItemForm(actions=[(link.url, link.text) for link in links]), 'title': _(u'Selected item actions:'), 'form_action': reverse('multi_object_action_view'), 'submit_method': 'get', diff --git a/apps/navigation/utils.py b/apps/navigation/utils.py index 6c008e5576..89cd9ec9a2 100644 --- a/apps/navigation/utils.py +++ b/apps/navigation/utils.py @@ -1,11 +1,122 @@ -#http://www.djangosnippets.org/snippets/1378/ +from __future__ import absolute_import + +import logging from django.core.urlresolvers import RegexURLResolver, RegexURLPattern, Resolver404, get_resolver +from django.template import (VariableDoesNotExist, Variable) +from django.utils.text import unescape_string_literal -__all__ = ('resolve_to_name',) +logger = logging.getLogger(__name__) +def get_navigation_objects(context): + objects = {} + + try: + indirect_reference_list = Variable('navigation_object_list').resolve(context) + except VariableDoesNotExist: + pass + else: + logger.debug('found: navigation_object_list') + for indirect_reference in indirect_reference_list: + try: + resolved_object = Variable(indirect_reference['object']).resolve(context) + except VariableDoesNotExist: + resolved_object = None + else: + objects.setdefault(resolved_object, {}) + objects[resolved_object]['label'] = indirect_reference.get('object_name') + + try: + indirect_reference = Variable('navigation_object_name').resolve(context) + except VariableDoesNotExist: + pass + else: + logger.debug('found: navigation_object_name') + try: + object_label = Variable('object_name').resolve(context) + except VariableDoesNotExist: + object_label = None + finally: + try: + resolved_object = Variable(indirect_reference).resolve(context) + except VariableDoesNotExist: + resolved_object = None + + objects.setdefault(resolved_object, {}) + objects[resolved_object]['label'] = object_label + + try: + indirect_reference = Variable('list_object_variable_name').resolve(context) + except VariableDoesNotExist: + pass + else: + logger.debug('found renamed list object') + try: + object_label = Variable('object_name').resolve(context) + except VariableDoesNotExist: + object_label = None + finally: + try: + resolved_object = Variable(indirect_reference).resolve(context) + except VariableDoesNotExist: + resolved_object = None + else: + objects.setdefault(resolved_object, {}) + objects[resolved_object]['label'] = object_label + + try: + resolved_object = Variable('object').resolve(context) + except VariableDoesNotExist: + pass + else: + logger.debug('found single object') + try: + object_label = Variable('object_name').resolve(context) + except VariableDoesNotExist: + object_label = None + finally: + objects.setdefault(resolved_object, {}) + objects[resolved_object]['label'] = object_label + + logger.debug('objects: %s' % objects) + return objects + + +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 + + +def resolve_arguments(context, src_args): + args = [] + kwargs = {} + if type(src_args) == type([]): + for i in src_args: + val = resolve_template_variable(context, i) + if val: + args.append(val) + elif type(src_args) == type({}): + 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 + + +#http://www.djangosnippets.org/snippets/1378/ def _pattern_resolve_to_name(self, path): match = self.regex.search(path) if match: diff --git a/apps/navigation/widgets.py b/apps/navigation/widgets.py index f587fc6ebb..361daf77e7 100644 --- a/apps/navigation/widgets.py +++ b/apps/navigation/widgets.py @@ -1,25 +1,19 @@ -from __future__ import absolute_import - -import urlparse +from __future__ import absolute_import from django.utils.safestring import mark_safe from django.conf import settings from django.utils.translation import ugettext_lazy as _ -from django.core.urlresolvers import reverse from django.template.defaultfilters import capfirst from django.core.exceptions import PermissionDenied -from django.template import RequestContext, Variable +from django.template import RequestContext from permissions.models import Permission -from .templatetags.navigation_tags import resolve_links -from .utils import resolve_to_name - def button_navigation_widget(request, link): - if 'permissions' in link: + if link.permissions: try: - Permission.objects.check_permissions(request.user, link['permissions']) + Permission.objects.check_permissions(request.user, link.permissions) return render_widget(request, link) except PermissionDenied: return u'' @@ -29,22 +23,13 @@ def button_navigation_widget(request, link): def render_widget(request, link): context = RequestContext(request) - - request = Variable('request').resolve(context) - current_path = request.META['PATH_INFO'] - current_view = resolve_to_name(current_path) - - query_string = urlparse.urlparse(request.get_full_path()).query or urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).query - parsed_query_string = urlparse.parse_qs(query_string) - - links = resolve_links(context, [link], current_view, current_path, parsed_query_string) - if links: - link = links[0] + resolved_link = link.resolve(context) + if resolved_link: return mark_safe(u'' % { - 'url': reverse(link['view']) if 'view' in link else link['url'], - 'icon': link.get('icon', 'link_button.png'), + 'url': resolved_link.url, + 'icon': getattr(resolved_link, 'icon', 'link_button.png'), 'static_url': settings.STATIC_URL, - 'string': capfirst(link['text']), + 'string': capfirst(resolved_link.text), 'image_alt': _(u'icon'), }) else: diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py index 3a3b0ac7c9..a1141f19c7 100644 --- a/apps/ocr/__init__.py +++ b/apps/ocr/__init__.py @@ -9,7 +9,7 @@ from django.db.models.signals import post_save, post_syncdb from django.dispatch import receiver from django.db.utils import DatabaseError -from navigation.api import register_links, register_multi_item_links +from navigation.api import bind_links, register_multi_item_links, Link from documents.models import Document, DocumentVersion from main.api import register_maintenance_links from project_tools.api import register_tool @@ -29,36 +29,36 @@ from . import models as ocr_models logger = logging.getLogger(__name__) #Links -submit_document = {'text': _('submit to OCR queue'), 'view': 'submit_document', 'args': 'object.id', 'famfam': 'hourglass_add', 'permissions': [PERMISSION_OCR_DOCUMENT]} -submit_document_multiple = {'text': _('submit to OCR queue'), 'view': 'submit_document_multiple', 'famfam': 'hourglass_add', 'permissions': [PERMISSION_OCR_DOCUMENT]} -re_queue_document = {'text': _('re-queue'), 'view': 're_queue_document', 'args': 'object.id', 'famfam': 'hourglass_add', 'permissions': [PERMISSION_OCR_DOCUMENT]} -re_queue_multiple_document = {'text': _('re-queue'), 'view': 're_queue_multiple_document', 'famfam': 'hourglass_add', 'permissions': [PERMISSION_OCR_DOCUMENT]} -queue_document_delete = {'text': _(u'delete'), 'view': 'queue_document_delete', 'args': 'object.id', 'famfam': 'hourglass_delete', 'permissions': [PERMISSION_OCR_DOCUMENT_DELETE]} -queue_document_multiple_delete = {'text': _(u'delete'), 'view': 'queue_document_multiple_delete', 'famfam': 'hourglass_delete', 'permissions': [PERMISSION_OCR_DOCUMENT_DELETE]} +submit_document = Link(text=_('submit to OCR queue'),view='submit_document',args='object.id',sprite='hourglass_add',permissions=[PERMISSION_OCR_DOCUMENT]) +submit_document_multiple = Link(text=_('submit to OCR queue'),view='submit_document_multiple',sprite='hourglass_add',permissions=[PERMISSION_OCR_DOCUMENT]) +re_queue_document = Link(text=_('re-queue'),view='re_queue_document',args='object.id',sprite='hourglass_add',permissions=[PERMISSION_OCR_DOCUMENT]) +re_queue_multiple_document = Link(text=_('re-queue'),view='re_queue_multiple_document',sprite='hourglass_add',permissions=[PERMISSION_OCR_DOCUMENT]) +queue_document_delete = Link(text=_(u'delete'),view='queue_document_delete',args='object.id',sprite='hourglass_delete',permissions=[PERMISSION_OCR_DOCUMENT_DELETE]) +queue_document_multiple_delete = Link(text=_(u'delete'),view='queue_document_multiple_delete',sprite='hourglass_delete',permissions=[PERMISSION_OCR_DOCUMENT_DELETE]) -document_queue_disable = {'text': _(u'stop queue'), 'view': 'document_queue_disable', 'args': 'queue.id', 'famfam': 'control_stop_blue', 'permissions': [PERMISSION_OCR_QUEUE_ENABLE_DISABLE]} -document_queue_enable = {'text': _(u'activate queue'), 'view': 'document_queue_enable', 'args': 'queue.id', 'famfam': 'control_play_blue', 'permissions': [PERMISSION_OCR_QUEUE_ENABLE_DISABLE]} +document_queue_disable = Link(text=_(u'stop queue'),view='document_queue_disable',args='queue.id',sprite='control_stop_blue',permissions=[PERMISSION_OCR_QUEUE_ENABLE_DISABLE]) +document_queue_enable = Link(text=_(u'activate queue'),view='document_queue_enable',args='queue.id',sprite='control_play_blue',permissions=[PERMISSION_OCR_QUEUE_ENABLE_DISABLE]) -all_document_ocr_cleanup = {'text': _(u'clean up pages content'), 'view': 'all_document_ocr_cleanup', 'famfam': 'text_strikethrough', 'permissions': [PERMISSION_OCR_CLEAN_ALL_PAGES], 'description': _(u'Runs a language filter to remove common OCR mistakes from document pages content.')} +all_document_ocr_cleanup = Link(text=_(u'clean up pages content'),view='all_document_ocr_cleanup',sprite='text_strikethrough',permissions=[PERMISSION_OCR_CLEAN_ALL_PAGES],description=_(u'Runs a language filter to remove common OCR mistakes from document pages content.')) -queue_document_list = {'text': _(u'queue document list'), 'view': 'queue_document_list', 'famfam': 'hourglass', 'permissions': [PERMISSION_OCR_DOCUMENT]} -ocr_tool_link = {'text': _(u'OCR'), 'view': 'queue_document_list', 'famfam': 'hourglass', 'icon': 'text.png', 'permissions': [PERMISSION_OCR_DOCUMENT], 'children_view_regex': [r'queue_', r'document_queue']} +queue_document_list = Link(text=_(u'queue document list'),view='queue_document_list',sprite='hourglass',permissions=[PERMISSION_OCR_DOCUMENT]) +ocr_tool_link = Link(text=_(u'OCR'),view='queue_document_list',sprite='hourglass',icon='text.png',permissions=[PERMISSION_OCR_DOCUMENT],children_view_regex=[r'queue_', r'document_queue']) -setup_queue_transformation_list = {'text': _(u'transformations'), 'view': 'setup_queue_transformation_list', 'args': 'queue.pk', 'famfam': 'shape_move_front'} -setup_queue_transformation_create = {'text': _(u'add transformation'), 'view': 'setup_queue_transformation_create', 'args': 'queue.pk', 'famfam': 'shape_square_add'} -setup_queue_transformation_edit = {'text': _(u'edit'), 'view': 'setup_queue_transformation_edit', 'args': 'transformation.pk', 'famfam': 'shape_square_edit'} -setup_queue_transformation_delete = {'text': _(u'delete'), 'view': 'setup_queue_transformation_delete', 'args': 'transformation.pk', 'famfam': 'shape_square_delete'} +setup_queue_transformation_list = Link(text=_(u'transformations'),view='setup_queue_transformation_list',args='queue.pk',sprite='shape_move_front') +setup_queue_transformation_create = Link(text=_(u'add transformation'),view='setup_queue_transformation_create',args='queue.pk',sprite='shape_square_add') +setup_queue_transformation_edit = Link(text=_(u'edit'),view='setup_queue_transformation_edit',args='transformation.pk',sprite='shape_square_edit') +setup_queue_transformation_delete = Link(text=_(u'delete'),view='setup_queue_transformation_delete',args='transformation.pk',sprite='shape_square_delete') -register_links(Document, [submit_document]) +bind_links([Document], [submit_document]) register_multi_item_links(['document_find_duplicates', 'folder_view', 'index_instance_list', 'document_type_document_list', 'search', 'results', 'document_group_view', 'document_list', 'document_list_recent'], [submit_document_multiple]) -register_links(DocumentQueue, [document_queue_disable, document_queue_enable, setup_queue_transformation_list]) -register_links(QueueTransformation, [setup_queue_transformation_edit, setup_queue_transformation_delete]) +bind_links([DocumentQueue], [document_queue_disable, document_queue_enable, setup_queue_transformation_list]) +bind_links([QueueTransformation], [setup_queue_transformation_edit, setup_queue_transformation_delete]) register_multi_item_links(['queue_document_list'], [re_queue_multiple_document, queue_document_multiple_delete]) -register_links(['setup_queue_transformation_create', 'setup_queue_transformation_edit', 'setup_queue_transformation_delete', 'document_queue_disable', 'document_queue_enable', 'queue_document_list', 'setup_queue_transformation_list'], [queue_document_list], menu_name='secondary_menu') -register_links(['setup_queue_transformation_edit', 'setup_queue_transformation_delete', 'setup_queue_transformation_list', 'setup_queue_transformation_create'], [setup_queue_transformation_create], menu_name='sidebar') +bind_links(['setup_queue_transformation_create', 'setup_queue_transformation_edit', 'setup_queue_transformation_delete', 'document_queue_disable', 'document_queue_enable', 'queue_document_list', 'setup_queue_transformation_list'], [queue_document_list], menu_name='secondary_menu') +bind_links(['setup_queue_transformation_edit', 'setup_queue_transformation_delete', 'setup_queue_transformation_list', 'setup_queue_transformation_create'], [setup_queue_transformation_create], menu_name='sidebar') register_maintenance_links([all_document_ocr_cleanup], namespace='ocr', title=_(u'OCR')) diff --git a/apps/permissions/__init__.py b/apps/permissions/__init__.py index 73731a97db..d70a1e27ec 100644 --- a/apps/permissions/__init__.py +++ b/apps/permissions/__init__.py @@ -5,7 +5,7 @@ from django.db.models.signals import post_save from django.core.exceptions import ObjectDoesNotExist from django.utils.translation import ugettext_lazy as _ -from navigation.api import register_links, register_multi_item_links +from navigation.api import bind_links, register_multi_item_links, Link from project_setup.api import register_setup from .conf.settings import DEFAULT_ROLES @@ -14,20 +14,21 @@ from .permissions import (PERMISSION_ROLE_VIEW, PERMISSION_ROLE_EDIT, PERMISSION_ROLE_CREATE, PERMISSION_ROLE_DELETE, PERMISSION_PERMISSION_GRANT, PERMISSION_PERMISSION_REVOKE) -role_list = {'text': _(u'roles'), 'view': 'role_list', 'famfam': 'medal_gold_1', 'icon': 'medal_gold_1.png', 'permissions': [PERMISSION_ROLE_VIEW], 'children_view_regex': [r'^permission_', r'^role_']} -role_create = {'text': _(u'create new role'), 'view': 'role_create', 'famfam': 'medal_gold_add', 'permissions': [PERMISSION_ROLE_CREATE]} -role_edit = {'text': _(u'edit'), 'view': 'role_edit', 'args': 'object.id', 'famfam': 'medal_gold_1', 'permissions': [PERMISSION_ROLE_EDIT]} -role_members = {'text': _(u'members'), 'view': 'role_members', 'args': 'object.id', 'famfam': 'group_key', 'permissions': [PERMISSION_ROLE_EDIT]} -role_permissions = {'text': _(u'role permissions'), 'view': 'role_permissions', 'args': 'object.id', 'famfam': 'key_go', 'permissions': [PERMISSION_PERMISSION_GRANT, PERMISSION_PERMISSION_REVOKE]} -role_delete = {'text': _(u'delete'), 'view': 'role_delete', 'args': 'object.id', 'famfam': 'medal_gold_delete', 'permissions': [PERMISSION_ROLE_DELETE]} +role_list = Link(text=_(u'roles'), view='role_list', sprite='medal_gold_1', icon='medal_gold_1.png', permissions=[PERMISSION_ROLE_VIEW])#, 'children_view_regex': [r'^permission_', r'^role_']) +role_create = Link(text=_(u'create new role'), view='role_create', sprite='medal_gold_add', permissions=[PERMISSION_ROLE_CREATE]) +role_edit = Link(text=_(u'edit'), view='role_edit', args='object.id', sprite='medal_gold_1', permissions=[PERMISSION_ROLE_EDIT]) +role_members = Link(text=_(u'members'), view='role_members', args='object.id', sprite='group_key', permissions=[PERMISSION_ROLE_EDIT]) +role_permissions = Link(text=_(u'role permissions'), view='role_permissions', args='object.id', sprite='key_go', permissions=[PERMISSION_PERMISSION_GRANT, PERMISSION_PERMISSION_REVOKE]) +role_delete = Link(text=_(u'delete'), view='role_delete', args='object.id', sprite='medal_gold_delete', permissions=[PERMISSION_ROLE_DELETE]) -permission_grant = {'text': _(u'grant'), 'view': 'permission_multiple_grant', 'famfam': 'key_add', 'permissions': [PERMISSION_PERMISSION_GRANT]} -permission_revoke = {'text': _(u'revoke'), 'view': 'permission_multiple_revoke', 'famfam': 'key_delete', 'permissions': [PERMISSION_PERMISSION_REVOKE]} +permission_grant = Link(text=_(u'grant'), view='permission_multiple_grant', sprite='key_add', permissions=[PERMISSION_PERMISSION_GRANT]) +permission_revoke = Link(text=_(u'revoke'), view='permission_multiple_revoke', sprite='key_delete', permissions=[PERMISSION_PERMISSION_REVOKE]) -register_links(Role, [role_edit, role_delete, role_permissions, role_members]) -register_links([Role, 'role_list', 'role_create'], [role_list, role_create], menu_name='secondary_menu') +bind_links([Role], [role_edit, role_delete, role_permissions, role_members]) +bind_links([Role, 'role_list', 'role_create'], [role_list, role_create], menu_name='secondary_menu') register_multi_item_links(['role_permissions'], [permission_grant, permission_revoke]) +# TODO: eliminate this permission_views = ['role_list', 'role_create', 'role_edit', 'role_members', 'role_permissions', 'role_delete'] diff --git a/apps/permissions/models.py b/apps/permissions/models.py index ff7dfd957f..6c559a5ecb 100644 --- a/apps/permissions/models.py +++ b/apps/permissions/models.py @@ -232,7 +232,7 @@ class Role(models.Model): def members(self, filter_dict=None): filter_dict = filter_dict or {} - return [member.member_object for member in self.rolemember_set.filter(**filter_dict)] + return [member.member_object for member in self.rolemember_set.filter(**filter_dict) if member is None] class RoleMember(models.Model): diff --git a/apps/project_setup/__init__.py b/apps/project_setup/__init__.py index c8eca31d1f..fd543290ed 100644 --- a/apps/project_setup/__init__.py +++ b/apps/project_setup/__init__.py @@ -1,5 +1,5 @@ from django.utils.translation import ugettext_lazy as _ -from navigation.api import register_top_menu +from navigation.api import register_top_menu, Link -setup_link = register_top_menu('setup_menu', link={'text': _(u'setup'), 'view': 'setup_list', 'famfam': 'cog'}, position=-2) +setup_menu = register_top_menu('setup_menu', link=Link(text=_(u'setup'), view='setup_list', sprite='cog'), position=-2) diff --git a/apps/project_setup/api.py b/apps/project_setup/api.py index 1d11179701..7535981277 100644 --- a/apps/project_setup/api.py +++ b/apps/project_setup/api.py @@ -1,13 +1,9 @@ from __future__ import absolute_import -from . import setup_link +from elementtree.ElementTree import Element, SubElement -setup_items = [] +from . import setup_menu def register_setup(link): - setup_items.append(link) - - # Append the link's children_view_regex to the setup main menu children view regex - setup_link.setdefault('children_view_regex', []) - setup_link['children_view_regex'].extend(link.get('children_view_regex', [])) + SubElement(setup_menu, 'setup_link', link=link) diff --git a/apps/project_setup/views.py b/apps/project_setup/views.py index 8ab0426572..cdb8d780ad 100644 --- a/apps/project_setup/views.py +++ b/apps/project_setup/views.py @@ -6,14 +6,17 @@ from django.utils.translation import ugettext_lazy as _ from navigation.widgets import button_navigation_widget -from .api import setup_items +from . import setup_menu def setup_list(request): context = { - 'object_list': [button_navigation_widget(request, item) for item in setup_items], + 'object_list': [button_navigation_widget(request, item.get('link')) for item in setup_menu.getchildren()], 'title': _(u'setup items'), } + # Remove unresolved links form list + context['object_list'] = [obj for obj in context['object_list'] if obj] + return render_to_response('generic_list_horizontal.html', context, context_instance=RequestContext(request)) diff --git a/apps/project_tools/__init__.py b/apps/project_tools/__init__.py index 3fc34151c1..f5bc1dd0e3 100644 --- a/apps/project_tools/__init__.py +++ b/apps/project_tools/__init__.py @@ -1,5 +1,5 @@ from django.utils.translation import ugettext_lazy as _ -from navigation.api import register_top_menu +from navigation.api import register_top_menu, Link -tool_link = register_top_menu('tools', link={'text': _(u'tools'), 'view': 'tools_list', 'famfam': 'wrench'}, position=-3) +tool_menu = register_top_menu('tools', link=Link(text=_(u'tools'), view='tools_list', sprite='wrench'), position=-3) diff --git a/apps/project_tools/api.py b/apps/project_tools/api.py index d8e66ab7d0..634d6590d9 100644 --- a/apps/project_tools/api.py +++ b/apps/project_tools/api.py @@ -1,12 +1,9 @@ from __future__ import absolute_import -from . import tool_link +from elementtree.ElementTree import Element, SubElement + +from . import tool_menu -tool_items = [] def register_tool(link): - tool_items.append(link) - - # Append the link's children_view_regex to the tool main menu children view regex - tool_link.setdefault('children_view_regex', []) - tool_link['children_view_regex'].extend(link.get('children_view_regex', [])) + SubElement(tool_menu, 'tool_link', link=link) diff --git a/apps/project_tools/views.py b/apps/project_tools/views.py index 61693a100c..033049b50d 100644 --- a/apps/project_tools/views.py +++ b/apps/project_tools/views.py @@ -6,14 +6,17 @@ from django.utils.translation import ugettext_lazy as _ from navigation.widgets import button_navigation_widget -from .api import tool_items +from . import tool_menu def tools_list(request): context = { - 'object_list': [button_navigation_widget(request, item) for item in tool_items], + 'object_list': [button_navigation_widget(request, item.get('link')) for item in tool_menu.getchildren()], 'title': _(u'tools'), } + # Remove unresolved links form list + context['object_list'] = [obj for obj in context['object_list'] if obj] + return render_to_response('generic_list_horizontal.html', context, context_instance=RequestContext(request)) diff --git a/apps/smart_settings/__init__.py b/apps/smart_settings/__init__.py index bfc495e54d..1f1f71071e 100644 --- a/apps/smart_settings/__init__.py +++ b/apps/smart_settings/__init__.py @@ -1,11 +1,12 @@ from django.utils.translation import ugettext_lazy as _ from project_setup.api import register_setup +from navigation.api import Link def is_superuser(context): return context['request'].user.is_staff or context['request'].user.is_superuser -check_settings = {'text': _(u'settings'), 'view': 'setting_list', 'famfam': 'cog', 'icon': 'cog.png', 'condition': is_superuser, 'children_view_regex': [r'^setting_']} +check_settings = Link(text=_(u'settings'), view='setting_list', sprite='cog', icon='cog.png', condition=is_superuser, children_view_regex=[r'^setting_']) register_setup(check_settings) diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index aad255b28d..196f8cd02b 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -2,8 +2,8 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ -from navigation.api import (register_links, - register_model_list_columns) +from navigation.api import (bind_links, + register_model_list_columns, Link) from common.utils import encapsulate from project_setup.api import register_setup from documents.permissions import (PERMISSION_DOCUMENT_NEW_VERSION, @@ -20,58 +20,58 @@ from .permissions import (PERMISSION_SOURCES_SETUP_VIEW, from .tasks import task_fetch_pop3_emails, task_fetch_imap_emails from .conf.settings import EMAIL_PROCESSING_INTERVAL -staging_file_preview = {'text': _(u'preview'), 'class': 'fancybox-noscaling', 'view': 'staging_file_preview', 'args': ['source.source_type', 'source.pk', 'object.id'], 'famfam': 'zoom', 'permissions': [PERMISSION_DOCUMENT_NEW_VERSION, PERMISSION_DOCUMENT_CREATE]} -staging_file_delete = {'text': _(u'delete'), 'view': 'staging_file_delete', 'args': ['source.source_type', 'source.pk', 'object.id'], 'famfam': 'delete', 'keep_query': True, 'permissions': [PERMISSION_DOCUMENT_NEW_VERSION, PERMISSION_DOCUMENT_CREATE]} +staging_file_preview = Link(text=_(u'preview'), klass='fancybox-noscaling', view='staging_file_preview', args=['source.source_type', 'source.pk', 'object.pk'], sprite='zoom', permissions=[PERMISSION_DOCUMENT_NEW_VERSION, PERMISSION_DOCUMENT_CREATE]) +staging_file_delete = Link(text=_(u'delete'), view='staging_file_delete', args=['source.source_type', 'source.pk', 'object.pk'], sprite='delete', keep_query=True, permissions=[PERMISSION_DOCUMENT_NEW_VERSION, PERMISSION_DOCUMENT_CREATE]) -setup_sources = {'text': _(u'sources'), 'view': 'setup_web_form_list', 'famfam': 'application_form', 'icon': 'application_form.png', 'children_classes': [WebForm], 'permissions': [PERMISSION_SOURCES_SETUP_VIEW], 'children_view_regex': [r'setup_web_form', r'setup_staging_folder', r'setup_source_', r'setup_pop3', r'setup_imap']} -setup_web_form_list = {'text': _(u'web forms'), 'view': 'setup_web_form_list', 'famfam': 'application_form', 'icon': 'application_form.png', 'children_classes': [WebForm], 'permissions': [PERMISSION_SOURCES_SETUP_VIEW]} -setup_staging_folder_list = {'text': _(u'staging folders'), 'view': 'setup_staging_folder_list', 'famfam': 'folder_camera', 'children_classes': [StagingFolder], 'permissions': [PERMISSION_SOURCES_SETUP_VIEW]} -setup_watch_folder_list = {'text': _(u'watch folders'), 'view': 'setup_watch_folder_list', 'famfam': 'folder_magnify', 'children_classes': [WatchFolder], 'permissions': [PERMISSION_SOURCES_SETUP_VIEW]} -setup_pop3_email_list = {'text': _(u'POP3 email'), 'view': 'setup_pop3_email_list', 'famfam': 'email', 'children_classes': [POP3Email], 'permissions': [PERMISSION_SOURCES_SETUP_VIEW]} -setup_imap_email_list = {'text': _(u'IMAP email'), 'view': 'setup_imap_email_list', 'famfam': 'email', 'children_classes': [IMAPEmail], 'permissions': [PERMISSION_SOURCES_SETUP_VIEW]} +setup_sources = Link(text=_(u'sources'), view='setup_web_form_list', sprite='application_form', icon='application_form.png', children_classes=[WebForm], permissions=[PERMISSION_SOURCES_SETUP_VIEW], children_view_regex=[r'setup_web_form', r'setup_staging_folder', r'setup_source_', r'setup_pop3', r'setup_imap']) +setup_web_form_list = Link(text=_(u'web forms'), view='setup_web_form_list', sprite='application_form', icon='application_form.png', children_classes=[WebForm], permissions=[PERMISSION_SOURCES_SETUP_VIEW]) +setup_staging_folder_list = Link(text=_(u'staging folders'), view='setup_staging_folder_list', sprite='folder_camera', children_classes=[StagingFolder], permissions=[PERMISSION_SOURCES_SETUP_VIEW]) +setup_watch_folder_list = Link(text=_(u'watch folders'), view='setup_watch_folder_list', sprite='folder_magnify', children_classes=[WatchFolder], permissions=[PERMISSION_SOURCES_SETUP_VIEW]) +setup_pop3_email_list = Link(text=_(u'POP3 email'), view='setup_pop3_email_list', sprite='email', children_classes=[POP3Email], permissions=[PERMISSION_SOURCES_SETUP_VIEW]) +setup_imap_email_list = Link(text=_(u'IMAP email'), view='setup_imap_email_list', sprite='email', children_classes=[IMAPEmail], permissions=[PERMISSION_SOURCES_SETUP_VIEW]) -setup_source_edit = {'text': _(u'edit'), 'view': 'setup_source_edit', 'args': ['source.source_type', 'source.pk'], 'famfam': 'application_form_edit', 'permissions': [PERMISSION_SOURCES_SETUP_EDIT]} -setup_source_delete = {'text': _(u'delete'), 'view': 'setup_source_delete', 'args': ['source.source_type', 'source.pk'], 'famfam': 'application_form_delete', 'permissions': [PERMISSION_SOURCES_SETUP_DELETE]} -setup_source_create = {'text': _(u'add new source'), 'view': 'setup_source_create', 'args': 'source_type', 'famfam': 'application_form_add', 'permissions': [PERMISSION_SOURCES_SETUP_CREATE]} -setup_source_log_list = {'text': _(u'logs'), 'view': 'setup_source_log_list', 'args': ['source.source_type', 'source.pk'], 'famfam': 'book', 'permissions': [PERMISSION_SOURCES_SETUP_EDIT]} +setup_source_edit = Link(text=_(u'edit'), view='setup_source_edit', args=['source.source_type', 'source.pk'], sprite='application_form_edit', permissions=[PERMISSION_SOURCES_SETUP_EDIT]) +setup_source_delete = Link(text=_(u'delete'), view='setup_source_delete', args=['source.source_type', 'source.pk'], sprite='application_form_delete', permissions=[PERMISSION_SOURCES_SETUP_DELETE]) +setup_source_create = Link(text=_(u'add new source'), view='setup_source_create', args='source_type', sprite='application_form_add', permissions=[PERMISSION_SOURCES_SETUP_CREATE]) +setup_source_log_list = Link(text=_(u'logs'), view='setup_source_log_list', args=['source.source_type', 'source.pk'], sprite='book', permissions=[PERMISSION_SOURCES_SETUP_EDIT]) -setup_source_transformation_list = {'text': _(u'transformations'), 'view': 'setup_source_transformation_list', 'args': ['source.source_type', 'source.pk'], 'famfam': 'shape_move_front', 'permissions': [PERMISSION_SOURCES_SETUP_EDIT]} -setup_source_transformation_create = {'text': _(u'add transformation'), 'view': 'setup_source_transformation_create', 'args': ['source.source_type', 'source.pk'], 'famfam': 'shape_square_add', 'permissions': [PERMISSION_SOURCES_SETUP_EDIT]} -setup_source_transformation_edit = {'text': _(u'edit'), 'view': 'setup_source_transformation_edit', 'args': 'transformation.pk', 'famfam': 'shape_square_edit', 'permissions': [PERMISSION_SOURCES_SETUP_EDIT]} -setup_source_transformation_delete = {'text': _(u'delete'), 'view': 'setup_source_transformation_delete', 'args': 'transformation.pk', 'famfam': 'shape_square_delete', 'permissions': [PERMISSION_SOURCES_SETUP_EDIT]} +setup_source_transformation_list = Link(text=_(u'transformations'), view='setup_source_transformation_list', args=['source.source_type', 'source.pk'], sprite='shape_move_front', permissions=[PERMISSION_SOURCES_SETUP_EDIT]) +setup_source_transformation_create = Link(text=_(u'add transformation'), view='setup_source_transformation_create', args=['source.source_type', 'source.pk'], sprite='shape_square_add', permissions=[PERMISSION_SOURCES_SETUP_EDIT]) +setup_source_transformation_edit = Link(text=_(u'edit'), view='setup_source_transformation_edit', args='transformation.pk', sprite='shape_square_edit', permissions=[PERMISSION_SOURCES_SETUP_EDIT]) +setup_source_transformation_delete = Link(text=_(u'delete'), view='setup_source_transformation_delete', args='transformation.pk', sprite='shape_square_delete', permissions=[PERMISSION_SOURCES_SETUP_EDIT]) -source_list = {'text': _(u'Document sources'), 'view': 'setup_web_form_list', 'famfam': 'page_add', 'children_url_regex': [r'sources/setup'], 'permissions': [PERMISSION_SOURCES_SETUP_VIEW]} +source_list = Link(text=_(u'Document sources'), view='setup_web_form_list', sprite='page_add', children_url_regex=[r'sources/setup'], permissions=[PERMISSION_SOURCES_SETUP_VIEW]) -upload_version = {'text': _(u'upload new version'), 'view': 'upload_version', 'args': 'object.pk', 'famfam': 'page_add', 'permissions': [PERMISSION_DOCUMENT_NEW_VERSION]} +upload_version = Link(text=_(u'upload new version'), view='upload_version', args='object.pk', sprite='page_add', permissions=[PERMISSION_DOCUMENT_NEW_VERSION]) -register_links(StagingFile, [staging_file_delete]) +bind_links([StagingFile], [staging_file_delete]) -register_links(SourceTransformation, [setup_source_transformation_edit, setup_source_transformation_delete]) +bind_links([SourceTransformation], [setup_source_transformation_edit, setup_source_transformation_delete]) -register_links(['setup_imap_email_list', 'setup_pop3_email_list', 'setup_web_form_list', 'setup_staging_folder_list', 'setup_watch_folder_list', 'setup_source_create'], [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list], menu_name='form_header') -register_links([WebForm, StagingFolder, POP3Email, IMAPEmail, 'setup_web_form_list', 'setup_staging_folder_list', 'setup_watch_folder_list', 'setup_source_create', 'setup_pop3_email_list', 'setup_imap_email_list'], [setup_source_create], menu_name='secondary_menu') +bind_links(['setup_imap_email_list', 'setup_pop3_email_list', 'setup_web_form_list', 'setup_staging_folder_list', 'setup_watch_folder_list', 'setup_source_create'], [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list], menu_name='form_header') +bind_links([WebForm, StagingFolder, POP3Email, IMAPEmail, 'setup_web_form_list', 'setup_staging_folder_list', 'setup_watch_folder_list', 'setup_source_create', 'setup_pop3_email_list', 'setup_imap_email_list'], [setup_source_create], menu_name='secondary_menu') -register_links(WebForm, [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list], menu_name='form_header') -register_links(WebForm, [setup_source_transformation_list, setup_source_edit, setup_source_delete]) +bind_links([WebForm], [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list], menu_name='form_header') +bind_links([WebForm], [setup_source_transformation_list, setup_source_edit, setup_source_delete]) -register_links(StagingFolder, [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list], menu_name='form_header') -register_links(StagingFolder, [setup_source_transformation_list, setup_source_edit, setup_source_delete]) +bind_links([StagingFolder], [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list], menu_name='form_header') +bind_links([StagingFolder], [setup_source_transformation_list, setup_source_edit, setup_source_delete]) -register_links(POP3Email, [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list], menu_name='form_header') -register_links(POP3Email, [setup_source_transformation_list, setup_source_edit, setup_source_delete]) -register_links(POP3Email, [setup_source_log_list]) +bind_links([POP3Email], [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list], menu_name='form_header') +bind_links([POP3Email], [setup_source_transformation_list, setup_source_edit, setup_source_delete]) +bind_links([POP3Email], [setup_source_log_list]) -register_links(IMAPEmail, [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list], menu_name='form_header') -register_links(IMAPEmail, [setup_source_transformation_list, setup_source_edit, setup_source_delete]) -register_links(IMAPEmail, [setup_source_log_list]) +bind_links([IMAPEmail], [setup_web_form_list, setup_staging_folder_list, setup_pop3_email_list, setup_imap_email_list], menu_name='form_header') +bind_links([IMAPEmail], [setup_source_transformation_list, setup_source_edit, setup_source_delete]) +bind_links([IMAPEmail], [setup_source_log_list]) -register_links(WatchFolder, [setup_web_form_list, setup_staging_folder_list, setup_watch_folder_list, setup_imap_email_list], menu_name='form_header') -register_links(WatchFolder, [setup_source_transformation_list, setup_source_edit, setup_source_delete]) +bind_links([WatchFolder], [setup_web_form_list, setup_staging_folder_list, setup_watch_folder_list, setup_imap_email_list], menu_name='form_header') +bind_links([WatchFolder], [setup_source_transformation_list, setup_source_edit, setup_source_delete]) # Document version -register_links(['document_version_list', 'upload_version', 'document_version_revert'], [upload_version], menu_name='sidebar') +bind_links(['document_version_list', 'upload_version', 'document_version_revert'], [upload_version], menu_name='sidebar') -register_links(['setup_source_transformation_create', 'setup_source_transformation_edit', 'setup_source_transformation_delete', 'setup_source_transformation_list'], [setup_source_transformation_create], menu_name='sidebar') +bind_links(['setup_source_transformation_create', 'setup_source_transformation_edit', 'setup_source_transformation_delete', 'setup_source_transformation_list'], [setup_source_transformation_create], menu_name='sidebar') source_views = ['setup_web_form_list', 'setup_staging_folder_list', 'setup_watch_folder_list', 'setup_source_edit', 'setup_source_delete', 'setup_source_create', 'setup_source_transformation_list', 'setup_source_transformation_edit', 'setup_source_transformation_delete', 'setup_source_transformation_create'] diff --git a/apps/sources/views.py b/apps/sources/views.py index 351a6e80e3..54d5fb7f43 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -23,6 +23,7 @@ from common.utils import encapsulate from common.widgets import two_state_template import sendfile from acls.models import AccessEntry +from navigation.api import Link from .models import (WebForm, StagingFolder, SourceTransformation, WatchFolder, POP3Email, SourceLog, IMAPEmail) @@ -55,14 +56,7 @@ def get_tab_link_for_source(source, document=None): view = u'upload_interactive' args = [u'"%s"' % source.source_type, source.pk] - return { - 'text': source.title, - 'view': view, - 'args': args, - 'famfam': source.icon, - 'keep_query': True, - 'conditional_highlight': return_function(source), - } + return Link(text=source.title, view=view, args=args, sprite=source.icon, keep_query=True, conditional_highlight=return_function(source)) def get_active_tab_links(document=None): @@ -703,6 +697,7 @@ def setup_source_transformation_edit(request, transformation_id): return render_to_response('generic_form.html', { 'title': _(u'Edit transformation: %s') % source_transformation, 'form': form, + 'source_type': source_transformation.content_object.source_type, 'source': source_transformation.content_object, 'transformation': source_transformation, 'navigation_object_list': [ @@ -735,6 +730,7 @@ def setup_source_transformation_delete(request, transformation_id): 'delete_view': True, 'transformation': source_transformation, 'source': source_transformation.content_object, + 'source_type': source_transformation.content_object.source_type, 'navigation_object_list': [ {'object': 'source', 'name': _(u'source')}, {'object': 'transformation', 'name': _(u'transformation')} diff --git a/apps/tags/__init__.py b/apps/tags/__init__.py index 2bfcb2f508..ec5df2c9db 100644 --- a/apps/tags/__init__.py +++ b/apps/tags/__init__.py @@ -2,8 +2,8 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ -from navigation.api import (register_links, register_top_menu, - register_model_list_columns, register_multi_item_links) +from navigation.api import (bind_links, register_top_menu, + register_model_list_columns, register_multi_item_links, Link) from common.utils import encapsulate from documents.models import Document from acls.api import class_permissions @@ -17,17 +17,17 @@ from .permissions import (PERMISSION_TAG_CREATE, PERMISSION_TAG_ATTACH, PERMISSION_TAG_REMOVE, PERMISSION_TAG_DELETE, PERMISSION_TAG_EDIT, PERMISSION_TAG_VIEW) -tag_list = {'text': _(u'tag list'), 'view': 'tag_list', 'famfam': 'tag_blue'} -tag_create = {'text': _(u'create new tag'), 'view': 'tag_create', 'famfam': 'tag_blue_add', 'permissions': [PERMISSION_TAG_CREATE]} -tag_attach = {'text': _(u'attach tag'), 'view': 'tag_attach', 'args': 'object.pk', 'famfam': 'tag_blue_add', 'permissions': [PERMISSION_TAG_ATTACH]} -tag_document_remove = {'text': _(u'remove'), 'view': 'tag_remove', 'args': ['object.id', 'document.id'], 'famfam': 'tag_blue_delete', 'permissions': [PERMISSION_TAG_REMOVE]} -tag_document_remove_multiple = {'text': _(u'remove'), 'view': 'tag_multiple_remove', 'args': 'document.id', 'famfam': 'tag_blue_delete', 'permissions': [PERMISSION_TAG_REMOVE]} -tag_document_list = {'text': _(u'tags'), 'view': 'document_tags', 'args': 'object.pk', 'famfam': 'tag_blue', 'permissions': [PERMISSION_TAG_REMOVE, PERMISSION_TAG_ATTACH], 'children_view_regex': ['tag']} -tag_delete = {'text': _(u'delete'), 'view': 'tag_delete', 'args': 'object.id', 'famfam': 'tag_blue_delete', 'permissions': [PERMISSION_TAG_DELETE]} -tag_edit = {'text': _(u'edit'), 'view': 'tag_edit', 'args': 'object.id', 'famfam': 'tag_blue_edit', 'permissions': [PERMISSION_TAG_EDIT]} -tag_tagged_item_list = {'text': _(u'tagged documents'), 'view': 'tag_tagged_item_list', 'args': 'object.id', 'famfam': 'page'} -tag_multiple_delete = {'text': _(u'delete'), 'view': 'tag_multiple_delete', 'famfam': 'tag_blue_delete', 'permissions': [PERMISSION_TAG_DELETE]} -tag_acl_list = {'text': _(u'ACLs'), 'view': 'tag_acl_list', 'args': 'object.pk', 'famfam': 'lock', 'permissions': [ACLS_VIEW_ACL]} +tag_list = Link(text=_(u'tag list'), view='tag_list', sprite='tag_blue') +tag_create = Link(text=_(u'create new tag'), view='tag_create', sprite='tag_blue_add', permissions=[PERMISSION_TAG_CREATE]) +tag_attach = Link(text=_(u'attach tag'), view='tag_attach', args='object.pk', sprite='tag_blue_add', permissions=[PERMISSION_TAG_ATTACH]) +tag_document_remove = Link(text=_(u'remove'), view='tag_remove', args=['object.pk', 'document.pk'], sprite='tag_blue_delete', permissions=[PERMISSION_TAG_REMOVE]) +tag_document_remove_multiple = Link(text=_(u'remove'), view='tag_multiple_remove', args='document.pk', sprite='tag_blue_delete', permissions=[PERMISSION_TAG_REMOVE]) +tag_document_list = Link(text=_(u'tags'), view='document_tags', args='object.pk', sprite='tag_blue', permissions=[PERMISSION_TAG_REMOVE, PERMISSION_TAG_ATTACH], children_view_regex=['tag']) +tag_delete = Link(text=_(u'delete'), view='tag_delete', args='object.pk', sprite='tag_blue_delete', permissions=[PERMISSION_TAG_DELETE]) +tag_edit = Link(text=_(u'edit'), view='tag_edit', args='object.pk', sprite='tag_blue_edit', permissions=[PERMISSION_TAG_EDIT]) +tag_tagged_item_list = Link(text=_(u'tagged documents'), view='tag_tagged_item_list', args='object.pk', sprite='page') +tag_multiple_delete = Link(text=_(u'delete'), view='tag_multiple_delete', sprite='tag_blue_delete', permissions=[PERMISSION_TAG_DELETE]) +tag_acl_list = Link(text=_(u'ACLs'), view='tag_acl_list', args='object.pk', sprite='lock', permissions=[ACLS_VIEW_ACL]) register_model_list_columns(Tag, [ { @@ -46,13 +46,13 @@ register_model_list_columns(Document, [ }, ]) -register_links(Tag, [tag_tagged_item_list, tag_edit, tag_delete, tag_acl_list]) +bind_links([Tag], [tag_tagged_item_list, tag_edit, tag_delete, tag_acl_list]) register_multi_item_links(['tag_list'], [tag_multiple_delete]) -register_links([Tag, 'tag_list', 'tag_create'], [tag_list, tag_create], menu_name='secondary_menu') -register_top_menu('tags', link={'text': _(u'tags'), 'view': 'tag_list', 'famfam': 'tag_blue'}, children_view_regex=[r'^tag_(list|create|delete|edit|tagged|acl)']) +bind_links([Tag, 'tag_list', 'tag_create'], [tag_list, tag_create], menu_name='secondary_menu') +register_top_menu('tags', link=Link(text=_(u'tags'), view='tag_list', sprite='tag_blue', children_view_regex=[r'^tag_(list|create|delete|edit|tagged|acl)'])) -register_links(Document, [tag_document_list], menu_name='form_header') -register_links(['document_tags', 'tag_remove', 'tag_multiple_remove', 'tag_attach'], [tag_attach], menu_name='sidebar') +bind_links([Document], [tag_document_list], menu_name='form_header') +bind_links(['document_tags', 'tag_remove', 'tag_multiple_remove', 'tag_attach'], [tag_attach], menu_name='sidebar') register_multi_item_links(['document_tags'], [tag_document_remove_multiple]) class_permissions(Document, [ diff --git a/apps/user_management/__init__.py b/apps/user_management/__init__.py index 00d0e50533..4e04ca2c9c 100644 --- a/apps/user_management/__init__.py +++ b/apps/user_management/__init__.py @@ -3,36 +3,36 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User, Group -from navigation.api import register_links, register_multi_item_links +from navigation.api import bind_links, register_multi_item_links, Link from project_setup.api import register_setup from .permissions import (PERMISSION_USER_CREATE, PERMISSION_USER_EDIT, PERMISSION_USER_VIEW, PERMISSION_USER_DELETE, PERMISSION_GROUP_CREATE, PERMISSION_GROUP_EDIT, PERMISSION_GROUP_VIEW, PERMISSION_GROUP_DELETE) -user_list = {'text': _(u'user list'), 'view': 'user_list', 'famfam': 'user', 'permissions': [PERMISSION_USER_VIEW]} -user_setup = {'text': _(u'users'), 'view': 'user_list', 'famfam': 'user', 'icon': 'user.png', 'permissions': [PERMISSION_USER_VIEW], 'children_view_regex': [r'^user_']} -user_edit = {'text': _(u'edit'), 'view': 'user_edit', 'args': 'object.id', 'famfam': 'user_edit', 'permissions': [PERMISSION_USER_EDIT]} -user_add = {'text': _(u'create new user'), 'view': 'user_add', 'famfam': 'user_add', 'permissions': [PERMISSION_USER_CREATE]} -user_delete = {u'text': _('delete'), 'view': 'user_delete', 'args': 'object.id', 'famfam': 'user_delete', 'permissions': [PERMISSION_USER_DELETE]} -user_multiple_delete = {u'text': _('delete'), 'view': 'user_multiple_delete', 'famfam': 'user_delete', 'permissions': [PERMISSION_USER_DELETE]} -user_set_password = {u'text': _('reset password'), 'view': 'user_set_password', 'args': 'object.id', 'famfam': 'lock_edit', 'permissions': [PERMISSION_USER_EDIT]} -user_multiple_set_password = {u'text': _('reset password'), 'view': 'user_multiple_set_password', 'famfam': 'lock_edit', 'permissions': [PERMISSION_USER_EDIT]} +user_list = Link(text=_(u'user list'), view='user_list', sprite='user', permissions=[PERMISSION_USER_VIEW]) +user_setup = Link(text=_(u'users'), view='user_list', sprite='user', icon='user.png', permissions=[PERMISSION_USER_VIEW], children_view_regex=[r'^user_']) +user_edit = Link(text=_(u'edit'), view='user_edit', args='object.id', sprite='user_edit', permissions=[PERMISSION_USER_EDIT]) +user_add = Link(text=_(u'create new user'), view='user_add', sprite='user_add', permissions=[PERMISSION_USER_CREATE]) +user_delete = Link(text=_('delete'), view='user_delete', args='object.id', sprite='user_delete', permissions=[PERMISSION_USER_DELETE]) +user_multiple_delete = Link(text=_('delete'), view='user_multiple_delete', sprite='user_delete', permissions=[PERMISSION_USER_DELETE]) +user_set_password = Link(text=_('reset password'), view='user_set_password', args='object.id', sprite='lock_edit', permissions=[PERMISSION_USER_EDIT]) +user_multiple_set_password = Link(text=_('reset password'), view='user_multiple_set_password', sprite='lock_edit', permissions=[PERMISSION_USER_EDIT]) -group_list = {'text': _(u'group list'), 'view': 'group_list', 'famfam': 'group', 'permissions': [PERMISSION_GROUP_VIEW]} -group_setup = {'text': _(u'groups'), 'view': 'group_list', 'famfam': 'group', 'icon': 'group.png', 'permissions': [PERMISSION_GROUP_VIEW], 'children_view_regex': [r'^group_']} -group_edit = {'text': _(u'edit'), 'view': 'group_edit', 'args': 'object.id', 'famfam': 'group_edit', 'permissions': [PERMISSION_GROUP_EDIT]} -group_add = {'text': _(u'create new group'), 'view': 'group_add', 'famfam': 'group_add', 'permissions': [PERMISSION_GROUP_CREATE]} -group_delete = {u'text': _('delete'), 'view': 'group_delete', 'args': 'object.id', 'famfam': 'group_delete', 'permissions': [PERMISSION_GROUP_DELETE]} -group_multiple_delete = {u'text': _('delete'), 'view': 'group_multiple_delete', 'famfam': 'group_delete', 'permissions': [PERMISSION_GROUP_DELETE]} -group_members = {'text': _(u'members'), 'view': 'group_members', 'args': 'object.id', 'famfam': 'group_link', 'permissions': [PERMISSION_GROUP_EDIT]} +group_list = Link(text=_(u'group list'), view='group_list', sprite='group', permissions=[PERMISSION_GROUP_VIEW]) +group_setup = Link(text=_(u'groups'), view='group_list', sprite='group', icon='group.png', permissions=[PERMISSION_GROUP_VIEW], children_view_regex=[r'^group_']) +group_edit = Link(text=_(u'edit'), view='group_edit', args='object.id', sprite='group_edit', permissions=[PERMISSION_GROUP_EDIT]) +group_add = Link(text=_(u'create new group'), view='group_add', sprite='group_add', permissions=[PERMISSION_GROUP_CREATE]) +group_delete = Link(text=_('delete'), view='group_delete', args='object.id', sprite='group_delete', permissions=[PERMISSION_GROUP_DELETE]) +group_multiple_delete = Link(text=_('delete'), view='group_multiple_delete', sprite='group_delete', permissions=[PERMISSION_GROUP_DELETE]) +group_members = Link(text=_(u'members'), view='group_members', args='object.id', sprite='group_link', permissions=[PERMISSION_GROUP_EDIT]) -register_links(User, [user_edit, user_set_password, user_delete]) -register_links(['user_multiple_set_password', 'user_set_password', 'user_multiple_delete', 'user_delete', 'user_edit', 'user_list', 'user_add'], [user_list, user_add], menu_name=u'secondary_menu') +bind_links([User], [user_edit, user_set_password, user_delete]) +bind_links(['user_multiple_set_password', 'user_set_password', 'user_multiple_delete', 'user_delete', 'user_edit', 'user_list', 'user_add'], [user_list, user_add], menu_name=u'secondary_menu') register_multi_item_links(['user_list'], [user_multiple_set_password, user_multiple_delete]) -register_links(Group, [group_edit, group_members, group_delete]) -register_links(['group_multiple_delete', 'group_delete', 'group_edit', 'group_list', 'group_add', 'group_members'], [group_list, group_add], menu_name=u'secondary_menu') +bind_links([Group], [group_edit, group_members, group_delete]) +bind_links(['group_multiple_delete', 'group_delete', 'group_edit', 'group_list', 'group_add', 'group_members'], [group_list, group_add], menu_name=u'secondary_menu') register_multi_item_links(['group_list'], [group_multiple_delete]) user_management_views = [ diff --git a/apps/workflows/__init__.py b/apps/workflows/__init__.py new file mode 100644 index 0000000000..d4a714a21e --- /dev/null +++ b/apps/workflows/__init__.py @@ -0,0 +1,68 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ + +from project_setup.api import register_setup +from navigation.api import Link, bind_links + +from .permissions import (PERMISSION_WORKFLOW_SETUP_VIEW, + PERMISSION_WORKFLOW_SETUP_CREATE, PERMISSION_WORKFLOW_SETUP_EDIT, + PERMISSION_WORKFLOW_SETUP_DELETE, PERMISSION_STATE_SETUP_VIEW, + PERMISSION_STATE_SETUP_CREATE, PERMISSION_STATE_SETUP_EDIT, + PERMISSION_STATE_SETUP_DELETE) + +from .models import (Workflow, State, WorkflowState, WorkflowNode) + +setup_workflow_list_link = Link(text=_(u'workflow list'), view='setup_workflow_list', sprite='chart_organisation', permissions=[PERMISSION_WORKFLOW_SETUP_VIEW]) +setup_workflow_create_link = Link(text=_(u'create new workflow'), view='setup_workflow_create', sprite='chart_organisation_add', permissions=[PERMISSION_WORKFLOW_SETUP_CREATE]) +setup_workflow_edit_link = Link(text=_(u'edit'), view='setup_workflow_edit', args='workflow.pk', sprite='chart_organisation', permissions=[PERMISSION_WORKFLOW_SETUP_EDIT]) +setup_workflow_delete_link = Link(text=_(u'delete'), view='setup_workflow_delete', args='workflow.pk', sprite='chart_organisation_delete', permissions=[PERMISSION_WORKFLOW_SETUP_DELETE]) +setup_workflow_states_list_link = Link(text=_(u'states'), view='setup_workflow_states_list', args='workflow.pk', sprite='transmit_go', permissions=[PERMISSION_WORKFLOW_SETUP_EDIT]) +setup_workflow_states_add_link = Link(text=_(u'add workflow state'), view='setup_workflow_state_add', args='workflow.pk', sprite='transmit_add', permissions=[PERMISSION_WORKFLOW_SETUP_EDIT]) +setup_workflow_states_edit_link = Link(text=_(u'edit workflow state'), view='setup_workflow_state_edit', args='workflow_state.pk', sprite='transmit_edit', permissions=[PERMISSION_WORKFLOW_SETUP_EDIT]) +setup_workflow_states_remove_link = Link(text=_(u'remove workflow state'), view='setup_workflow_state_remove', args='workflow_state.pk', sprite='transmit_delete', permissions=[PERMISSION_WORKFLOW_SETUP_EDIT]) + +setup_workflow_state_transitions_list_link = Link(text=_(u'workflow state transitions'), view='setup_workflow_state_transitions_list', args='workflow_state.pk', sprite='chart_line', permissions=[PERMISSION_WORKFLOW_SETUP_EDIT]) +setup_workflow_state_transition_add_link = Link(text=_(u'add workflow state transition'), view='setup_workflow_state_transition_add', args='workflow_state.pk', sprite='chart_line_add', permissions=[PERMISSION_WORKFLOW_SETUP_EDIT]) +setup_workflow_state_transition_edit_link = Link(text=_(u'edit workflow state transition'), view='setup_workflow_state_transition_edit', args='workflow_state_transition.pk', sprite='chart_line_edit', permissions=[PERMISSION_WORKFLOW_SETUP_EDIT]) + +setup_state_list_link = Link(text=_(u'state list'), view='setup_state_list', sprite='transmit', permissions=[PERMISSION_STATE_SETUP_VIEW]) +setup_state_create_link = Link(text=_(u'create new state'), view='setup_state_create', sprite='transmit_add', permissions=[PERMISSION_STATE_SETUP_CREATE]) +setup_state_edit_link = Link(text=_(u'edit'), view='setup_state_edit', args='object.pk', sprite='transmit_edit', permissions=[PERMISSION_STATE_SETUP_EDIT]) +setup_state_delete_link = Link(text=_(u'delete'), view='setup_state_delete', args='object.pk', sprite='transmit_delete', permissions=[PERMISSION_STATE_SETUP_DELETE]) + +setup_workflow_node_list_link = Link(text=_(u'node list'), view='setup_workflow_node_list', args='workflow.pk', sprite='chart_line', permissions=[PERMISSION_WORKFLOW_SETUP_EDIT]) +#setup_workflow_node_create_link = Link(text=_(u'create new transition'), view='setup_transition_create', sprite='chart_line_add', permissions=[PERMISSION_TRANSITION_SETUP_CREATE]) +setup_workflow_node_edit_link = Link(text=_(u'edit'), view='setup_workflow_node_edit', args='workflow_node.pk', sprite='chart_line_edit', permissions=[PERMISSION_WORKFLOW_SETUP_EDIT]) +#setup_workflow_node_delete_link = Link(text=_(u'delete'), view='setup_transition_delete', args='transition.pk', sprite='chart_line_delete', permissions=[PERMISSION_TRANSITION_SETUP_DELETE]) + +bind_links( + [ + Workflow, State, + 'setup_workflow_list', 'setup_workflow_create', + 'setup_state_list', 'setup_state_create', + #'setup_transition_list', 'setup_transition_create', + 'setup_transition_create', + ], [ + setup_workflow_list_link, setup_state_list_link#, setup_transition_list_link + ], menu_name=u'form_header') + +bind_links([Workflow], [setup_workflow_node_list_link, setup_workflow_states_list_link, setup_workflow_edit_link, setup_workflow_delete_link]) +bind_links([Workflow, 'setup_workflow_list', 'setup_workflow_create'], [setup_workflow_create_link], menu_name=u'secondary_menu') +bind_links([WorkflowState, 'setup_workflow_states_list', 'setup_workflow_states_add'], [setup_workflow_states_add_link], menu_name=u'sidebar') + +bind_links([State], [setup_state_edit_link, setup_state_delete_link]) +bind_links([State, 'setup_state_list', 'setup_state_create'], [setup_state_create_link], menu_name=u'secondary_menu') + +#bind_links([Transition], [setup_transition_edit_link, setup_transition_delete_link]) +#bind_links([Transition, 'setup_transition_list', 'setup_transition_create'], [setup_transition_create_link], menu_name=u'secondary_menu') + +#bind_links([WorkflowState], [setup_workflow_state_transitions_list_link, setup_workflow_states_edit_link, setup_workflow_states_remove_link]) +bind_links([WorkflowState], [setup_workflow_states_edit_link, setup_workflow_states_remove_link]) + +#bind_links([WorkflowState], [setup_workflow_state_transition_add_link], menu_name=u'sidebar') +#bind_links([WorkflowNode], [setup_workflow_state_transition_add_link], menu_name=u'sidebar') + +bind_links([WorkflowNode], [setup_workflow_node_edit_link])#, setup_transition_delete_link]) + +register_setup(Link(text=_(u'workflows'), view='setup_workflow_list', icon='chart_organisation.png', permissions=[PERMISSION_WORKFLOW_SETUP_VIEW])) diff --git a/apps/workflows/forms.py b/apps/workflows/forms.py new file mode 100644 index 0000000000..5f0e897ebd --- /dev/null +++ b/apps/workflows/forms.py @@ -0,0 +1,70 @@ +from __future__ import absolute_import + +from django import forms +from django.utils.translation import ugettext_lazy as _ + +from .models import Workflow, State, WorkflowState, WorkflowNode + + +class NodeForm(forms.Form): + def __init__(self, *args, **kwargs): + #workflow = kwargs.pop('workflow') + super(WorkflowStateSetupForm, self).__init__(*args, **kwargs) + #self.fields['workflow'].initial = workflow + #self.fields['workflow'].widget = forms.widgets.HiddenInput() + print self.instance + + #def choices(self, workflow): + # return { + ## 'next_node': workflow.nodes.all() + # } + + +class WorkflowSetupForm(forms.ModelForm): + class Meta: + exclude = ('initial_node,') + model = Workflow + + +class StateSetupForm(forms.ModelForm): + class Meta: + model = State + + +class WorkflowStateSetupForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + workflow = kwargs.pop('workflow') + super(WorkflowStateSetupForm, self).__init__(*args, **kwargs) + self.fields['workflow'].initial = workflow + self.fields['workflow'].widget = forms.widgets.HiddenInput() + + class Meta: + model = WorkflowState + + +class WorkflowNodeSetupForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + workflow = kwargs.pop('workflow') + super(WorkflowNodeSetupForm, self).__init__(*args, **kwargs) + self.fields['workflow'].initial = workflow + self.fields['workflow'].widget = forms.widgets.HiddenInput() + + class Meta: + model = WorkflowNode + +#class TransitionSetupForm(forms.ModelForm): +# class Meta: +# model = Transition + + +#class WorkflowStateTransitionSetupForm(forms.ModelForm): +# def __init__(self, *args, **kwargs): +# workflow_state = kwargs.pop('workflow_state') +# super(WorkflowStateTransitionSetupForm, self).__init__(*args, **kwargs) +# self.fields['workflow_state_source'].initial = workflow_state +# self.fields['workflow_state_source'].widget = forms.widgets.HiddenInput() +# +# class Meta: +# model = WorkflowStateTransition + + diff --git a/apps/workflows/literals.py b/apps/workflows/literals.py new file mode 100644 index 0000000000..da3e4aeb23 --- /dev/null +++ b/apps/workflows/literals.py @@ -0,0 +1,19 @@ +from django.utils.translation import ugettext_lazy as _ + +OPERAND_OR = 'or' +OPERAND_AND = 'and' + +OPERAND_CHOICES = ( + (OPERAND_OR, _(u'or')), + (OPERAND_AND, _(u'and')) +) + +NODE_TYPE_TASK = 'task' +NODE_TYPE_START = 'start' +NODE_TYPE_END = 'end' + +NODE_TYPE_CHOICES = ( + (NODE_TYPE_TASK, _(u'Simple task')), + (NODE_TYPE_START, _(u'Start')), + (NODE_TYPE_END, _(u'End')), +) diff --git a/apps/workflows/migrations/0001_initial.py b/apps/workflows/migrations/0001_initial.py new file mode 100644 index 0000000000..015bc09db3 --- /dev/null +++ b/apps/workflows/migrations/0001_initial.py @@ -0,0 +1,202 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Adding model 'Ability' + db.create_table('workflows_ability', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('label', self.gf('django.db.models.fields.CharField')(unique=True, max_length=128)), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('workflows', ['Ability']) + + # Adding model 'Workflow' + db.create_table('workflows_workflow', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('label', self.gf('django.db.models.fields.CharField')(unique=True, max_length=128)), + ('initial_state', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='workflow_initial_state', null=True, to=orm['workflows.WorkflowState'])), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('workflows', ['Workflow']) + + # Adding model 'State' + db.create_table('workflows_state', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('label', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('workflows', ['State']) + + # Adding model 'Transition' + db.create_table('workflows_transition', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('label', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('workflows', ['Transition']) + + # Adding model 'WorkflowState' + db.create_table('workflows_workflowstate', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('workflow', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_workflow', to=orm['workflows.Workflow'])), + ('state', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_state', to=orm['workflows.State'])), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('workflows', ['WorkflowState']) + + # Adding model 'WorkflowStateAbilityGrant' + db.create_table('workflows_workflowstateabilitygrant', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('workflow_state', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_ability', to=orm['workflows.WorkflowState'])), + ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_ability_object', to=orm['contenttypes.ContentType'])), + ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()), + )) + db.send_create_signal('workflows', ['WorkflowStateAbilityGrant']) + + # Adding model 'WorkflowStateTransition' + db.create_table('workflows_workflowstatetransition', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('workflow_state_source', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_transition_source', to=orm['workflows.WorkflowState'])), + ('transition', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_transition', to=orm['workflows.Transition'])), + ('workflow_state_destination', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_transition_destination', to=orm['workflows.WorkflowState'])), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('workflows', ['WorkflowStateTransition']) + + # Adding model 'WorkflowStateTransitionAbility' + db.create_table('workflows_workflowstatetransitionability', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('attribute_comparison_operand', self.gf('django.db.models.fields.CharField')(default='and', max_length=8)), + ('negate', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('ability', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_transition_ability', to=orm['workflows.Ability'])), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('workflows', ['WorkflowStateTransitionAbility']) + + # Adding model 'WorkflowInstance' + db.create_table('workflows_workflowinstance', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('workflow', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['workflows.Workflow'])), + ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_instance_object', to=orm['contenttypes.ContentType'])), + ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()), + ('workflow_state', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_instance_state', to=orm['workflows.WorkflowState'])), + )) + db.send_create_signal('workflows', ['WorkflowInstance']) + + # Adding unique constraint on 'WorkflowInstance', fields ['content_type', 'object_id', 'workflow'] + db.create_unique('workflows_workflowinstance', ['content_type_id', 'object_id', 'workflow_id']) + + + def backwards(self, orm): + + # Removing unique constraint on 'WorkflowInstance', fields ['content_type', 'object_id', 'workflow'] + db.delete_unique('workflows_workflowinstance', ['content_type_id', 'object_id', 'workflow_id']) + + # Deleting model 'Ability' + db.delete_table('workflows_ability') + + # Deleting model 'Workflow' + db.delete_table('workflows_workflow') + + # Deleting model 'State' + db.delete_table('workflows_state') + + # Deleting model 'Transition' + db.delete_table('workflows_transition') + + # Deleting model 'WorkflowState' + db.delete_table('workflows_workflowstate') + + # Deleting model 'WorkflowStateAbilityGrant' + db.delete_table('workflows_workflowstateabilitygrant') + + # Deleting model 'WorkflowStateTransition' + db.delete_table('workflows_workflowstatetransition') + + # Deleting model 'WorkflowStateTransitionAbility' + db.delete_table('workflows_workflowstatetransitionability') + + # Deleting model 'WorkflowInstance' + db.delete_table('workflows_workflowinstance') + + + models = { + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'workflows.ability': { + 'Meta': {'object_name': 'Ability'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}) + }, + 'workflows.state': { + 'Meta': {'object_name': 'State'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'workflows.transition': { + 'Meta': {'object_name': 'Transition'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'workflows.workflow': { + 'Meta': {'object_name': 'Workflow'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'initial_state': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_initial_state'", 'null': 'True', 'to': "orm['workflows.WorkflowState']"}), + 'label': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}) + }, + 'workflows.workflowinstance': { + 'Meta': {'unique_together': "(('content_type', 'object_id', 'workflow'),)", 'object_name': 'WorkflowInstance'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'workflow_instance_object'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'workflow': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.Workflow']"}), + 'workflow_state': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'workflow_instance_state'", 'to': "orm['workflows.WorkflowState']"}) + }, + 'workflows.workflowstate': { + 'Meta': {'object_name': 'WorkflowState'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'workflow_state_state'", 'to': "orm['workflows.State']"}), + 'workflow': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'workflow_state_workflow'", 'to': "orm['workflows.Workflow']"}) + }, + 'workflows.workflowstateabilitygrant': { + 'Meta': {'object_name': 'WorkflowStateAbilityGrant'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'workflow_state_ability_object'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'workflow_state': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'workflow_state_ability'", 'to': "orm['workflows.WorkflowState']"}) + }, + 'workflows.workflowstatetransition': { + 'Meta': {'object_name': 'WorkflowStateTransition'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'transition': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'workflow_state_transition'", 'to': "orm['workflows.Transition']"}), + 'workflow_state_destination': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'workflow_state_transition_destination'", 'to': "orm['workflows.WorkflowState']"}), + 'workflow_state_source': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'workflow_state_transition_source'", 'to': "orm['workflows.WorkflowState']"}) + }, + 'workflows.workflowstatetransitionability': { + 'Meta': {'object_name': 'WorkflowStateTransitionAbility'}, + 'ability': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'workflow_state_transition_ability'", 'to': "orm['workflows.Ability']"}), + 'attribute_comparison_operand': ('django.db.models.fields.CharField', [], {'default': "'and'", 'max_length': '8'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'negate': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + } + } + + complete_apps = ['workflows'] diff --git a/apps/workflows/migrations/0002_auto__del_workflowstateabilitygrant__del_workflowstatetransition__del_.py b/apps/workflows/migrations/0002_auto__del_workflowstateabilitygrant__del_workflowstatetransition__del_.py new file mode 100644 index 0000000000..6c8fb3eac5 --- /dev/null +++ b/apps/workflows/migrations/0002_auto__del_workflowstateabilitygrant__del_workflowstatetransition__del_.py @@ -0,0 +1,231 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Removing unique constraint on 'WorkflowInstance', fields ['object_id', 'content_type', 'workflow'] + db.delete_unique('workflows_workflowinstance', ['object_id', 'content_type_id', 'workflow_id']) + + # Deleting model 'WorkflowStateAbilityGrant' + db.delete_table('workflows_workflowstateabilitygrant') + + # Deleting model 'WorkflowStateTransition' + db.delete_table('workflows_workflowstatetransition') + + # Deleting model 'WorkflowStateTransitionAbility' + db.delete_table('workflows_workflowstatetransitionability') + + # Deleting model 'Transition' + db.delete_table('workflows_transition') + + # Adding model 'WorkflowInstanceActiveState' + db.create_table('workflows_workflowinstanceactivestate', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('workflow_instance', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['workflows.WorkflowInstance'])), + ('state', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['workflows.State'], null=True)), + )) + db.send_create_signal('workflows', ['WorkflowInstanceActiveState']) + + # Adding unique constraint on 'WorkflowInstanceActiveState', fields ['workflow_instance', 'state'] + db.create_unique('workflows_workflowinstanceactivestate', ['workflow_instance_id', 'state_id']) + + # Adding model 'End' + db.create_table('workflows_end', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('label', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('workflows', ['End']) + + # Adding model 'WorkflowInstanceActiveNode' + db.create_table('workflows_workflowinstanceactivenode', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('workflow_instance', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['workflows.WorkflowInstance'])), + ('workflow_node', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['workflows.WorkflowNode'])), + )) + db.send_create_signal('workflows', ['WorkflowInstanceActiveNode']) + + # Adding model 'Start' + db.create_table('workflows_start', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('label', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'], null=True)), + ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')(null=True)), + )) + db.send_create_signal('workflows', ['Start']) + + # Adding model 'WorkflowNode' + db.create_table('workflows_workflownode', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('workflow', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['workflows.Workflow'])), + ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])), + ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('workflows', ['WorkflowNode']) + + # Adding field 'Workflow.initial_node' + db.add_column('workflows_workflow', 'initial_node', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='workflow_initial_node', null=True, to=orm['workflows.WorkflowNode']), keep_default=False) + + # Deleting field 'WorkflowInstance.workflow_state' + db.delete_column('workflows_workflowinstance', 'workflow_state_id') + + # Adding unique constraint on 'WorkflowState', fields ['state', 'workflow'] + db.create_unique('workflows_workflowstate', ['state_id', 'workflow_id']) + + + def backwards(self, orm): + + # Removing unique constraint on 'WorkflowState', fields ['state', 'workflow'] + db.delete_unique('workflows_workflowstate', ['state_id', 'workflow_id']) + + # Removing unique constraint on 'WorkflowInstanceActiveState', fields ['workflow_instance', 'state'] + db.delete_unique('workflows_workflowinstanceactivestate', ['workflow_instance_id', 'state_id']) + + # Adding model 'WorkflowStateAbilityGrant' + db.create_table('workflows_workflowstateabilitygrant', ( + ('workflow_state', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_ability', to=orm['workflows.WorkflowState'])), + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_ability_object', to=orm['contenttypes.ContentType'])), + ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()), + )) + db.send_create_signal('workflows', ['WorkflowStateAbilityGrant']) + + # Adding model 'WorkflowStateTransition' + db.create_table('workflows_workflowstatetransition', ( + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + ('workflow_state_source', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_transition_source', to=orm['workflows.WorkflowState'])), + ('transition', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_transition', to=orm['workflows.Transition'])), + ('workflow_state_destination', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_transition_destination', to=orm['workflows.WorkflowState'])), + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + )) + db.send_create_signal('workflows', ['WorkflowStateTransition']) + + # Adding model 'WorkflowStateTransitionAbility' + db.create_table('workflows_workflowstatetransitionability', ( + ('ability', self.gf('django.db.models.fields.related.ForeignKey')(related_name='workflow_state_transition_ability', to=orm['workflows.Ability'])), + ('attribute_comparison_operand', self.gf('django.db.models.fields.CharField')(default='and', max_length=8)), + ('negate', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('workflows', ['WorkflowStateTransitionAbility']) + + # Adding model 'Transition' + db.create_table('workflows_transition', ( + ('label', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + )) + db.send_create_signal('workflows', ['Transition']) + + # Deleting model 'WorkflowInstanceActiveState' + db.delete_table('workflows_workflowinstanceactivestate') + + # Deleting model 'End' + db.delete_table('workflows_end') + + # Deleting model 'WorkflowInstanceActiveNode' + db.delete_table('workflows_workflowinstanceactivenode') + + # Deleting model 'Start' + db.delete_table('workflows_start') + + # Deleting model 'WorkflowNode' + db.delete_table('workflows_workflownode') + + # Deleting field 'Workflow.initial_node' + db.delete_column('workflows_workflow', 'initial_node_id') + + # User chose to not deal with backwards NULL issues for 'WorkflowInstance.workflow_state' + raise RuntimeError("Cannot reverse this migration. 'WorkflowInstance.workflow_state' and its values cannot be restored.") + + # Adding unique constraint on 'WorkflowInstance', fields ['object_id', 'content_type', 'workflow'] + db.create_unique('workflows_workflowinstance', ['object_id', 'content_type_id', 'workflow_id']) + + + models = { + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'workflows.ability': { + 'Meta': {'object_name': 'Ability'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}) + }, + 'workflows.end': { + 'Meta': {'object_name': 'End'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'workflows.start': { + 'Meta': {'object_name': 'Start'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']", 'null': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}) + }, + 'workflows.state': { + 'Meta': {'object_name': 'State'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'workflows.workflow': { + 'Meta': {'object_name': 'Workflow'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'initial_node': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_initial_node'", 'null': 'True', 'to': "orm['workflows.WorkflowNode']"}), + 'initial_state': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'workflow_initial_state'", 'null': 'True', 'to': "orm['workflows.WorkflowState']"}), + 'label': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}) + }, + 'workflows.workflowinstance': { + 'Meta': {'object_name': 'WorkflowInstance'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'workflow_instance_object'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'workflow': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.Workflow']"}) + }, + 'workflows.workflowinstanceactivenode': { + 'Meta': {'object_name': 'WorkflowInstanceActiveNode'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'workflow_instance': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.WorkflowInstance']"}), + 'workflow_node': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.WorkflowNode']"}) + }, + 'workflows.workflowinstanceactivestate': { + 'Meta': {'unique_together': "(('workflow_instance', 'state'),)", 'object_name': 'WorkflowInstanceActiveState'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.State']", 'null': 'True'}), + 'workflow_instance': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.WorkflowInstance']"}) + }, + 'workflows.workflownode': { + 'Meta': {'object_name': 'WorkflowNode'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'workflow': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.Workflow']"}) + }, + 'workflows.workflowstate': { + 'Meta': {'unique_together': "(('workflow', 'state'),)", 'object_name': 'WorkflowState'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.State']"}), + 'workflow': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['workflows.Workflow']"}) + } + } + + complete_apps = ['workflows'] diff --git a/apps/workflows/migrations/__init__.py b/apps/workflows/migrations/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/workflows/models.py b/apps/workflows/models.py new file mode 100644 index 0000000000..509e317e3e --- /dev/null +++ b/apps/workflows/models.py @@ -0,0 +1,325 @@ +from __future__ import absolute_import + +from django.db import models +from django.contrib.contenttypes import generic +from django.contrib.contenttypes.models import ContentType +from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext + +from permissions.models import StoredPermission + +from .literals import OPERAND_CHOICES, OPERAND_AND +#from .literals import NODE_TYPE_TASK, NODE_TYPE_START, NODE_TYPE_END + +#NODE_TYPE_CHOICES + +class Ability(models.Model): + label = models.CharField(max_length=128, unique=True, verbose_name = _(u'label')) + description = models.TextField(blank=True, verbose_name=_(u'description')) + + def __unicode__(self): + return self.label + + class Meta: + verbose_name = _(u'ability') + verbose_name_plural = _(u'abilities') + + +class Workflow(models.Model): + label = models.CharField(max_length=128, unique=True, verbose_name = _(u'label')) + initial_node = models.ForeignKey('WorkflowNode', related_name='workflow_initial_node', blank=True, null=True, verbose_name=_(u'initial node')) + initial_state = models.ForeignKey('WorkflowState', related_name='workflow_initial_state', blank=True, null=True, verbose_name=_(u'initial state')) + description = models.TextField(blank=True, verbose_name=_(u'description')) + + def __unicode__(self): + return self.label + + @property + def workflow_nodes(self): + return self.workflownode_set + + def get_nodes(self): + return [workflow_node.node for workflow_node in self.workflownode_set.all()] + + def add_node(self, node): + workflow_node = WorkflowNode( + workflow=self, + node=node) + workflow_node.save() + return workflow_node + + def save(self, *args, **kwargs): + is_new = not self.pk + result = super(Workflow, self).save(*args, **kwargs) + + if is_new: + # Instanciate a new start node + start_node = Start() + start_node.save() + + # Set the start node a + workflow_node = self.add_node(node=start_node) + + self.initial_node = workflow_node + self.save() + + return result + + class Meta: + verbose_name = _(u'workflow') + verbose_name_plural = _(u'workflows') + + +class Node(models.Model): + """ + Must provide: + possible_next_nodes() + Arguments: None + Returns: + List of possible nodes after this one executes + + choices() + Arguments: workflow + Returns: + { + 'next_node': workflow.nodes.all() + } + + execute() + Arguments: workflow_instance + Returns: next_node + """ + + label = models.CharField(max_length=128, verbose_name=_(u'label')) + description = models.TextField(blank=True, verbose_name=_(u'description')) + + def __unicode__(self): + return self.label + + class Meta: + verbose_name = _(u'state') + verbose_name_plural = _(u'states') + abstract = True + + +class Start(Node): + """ + The node with which all workflows start + """ + content_type = models.ForeignKey(ContentType, null=True) + object_id = models.PositiveIntegerField(null=True) + next_node = generic.GenericForeignKey(ct_field='content_type', fk_field='object_id') + + def __unicode__(self): + return ugettext(u'Start') + + def possible_next_nodes(self): + return self.next_node + + def choices(self, workflow): + return { + 'next_node': workflow.nodes.all() + } + + def execute(self, workflow_instance): + return self.next_node + + class Meta(Node.Meta): + verbose_name = _(u'start node') + verbose_name_plural = _(u'start nodes') + + +class End(Node): + class Meta(Node.Meta): + verbose_name = _(u'end node') + verbose_name_plural = _(u'end nodes') + + +''' +class Sequence(Node): + """ + A node that is enabled after the completion of a preceding node in the same workflow + """ + content_type = models.ForeignKey(ContentType) + object_id = models.PositiveIntegerField() + next_node = generic.GenericForeignKey(ct_field='content_type', fk_field='object_id') + #node_type = NODE_TYPE_TASK + + def execute(self): + return self.next_node + + class Meta(Node.Meta): + verbose_name = _(u'task') + verbose_name_plural = _(u'tasks') +''' + +class State(models.Model): + label = models.CharField(max_length=128, verbose_name=_(u'label')) + description = models.TextField(blank=True, verbose_name=_(u'description')) + + def __unicode__(self): + return self.label + + class Meta: + verbose_name = _(u'state') + verbose_name_plural = _(u'states') + ordering = ('label',) + + +class WorkflowState(models.Model): + """ + List of possible states the object of this worflow could be in + """ + workflow = models.ForeignKey(Workflow, verbose_name=_(u'workflow')) + state = models.ForeignKey(State, verbose_name=_(u'state')) + description = models.TextField(blank=True, verbose_name=_(u'description')) + + def __unicode__(self): + return unicode(self.state) + + class Meta: + unique_together = ('workflow', 'state') + verbose_name = _(u'workflow state') + verbose_name_plural = _(u'workflows states') + +# TODO: Reduntant - remove +class WorkflowNode(models.Model): + workflow = models.ForeignKey(Workflow, verbose_name=_(u'workflow')) + content_type = models.ForeignKey(ContentType)#, limit_choices_to={'model__in': ('model1', 'model2')})#, related_name='workflow_state_ability_object')#, blank=True, null=True) + object_id = models.PositiveIntegerField()#blank=True, null=True) + node = generic.GenericForeignKey(ct_field='content_type', fk_field='object_id') + description = models.TextField(blank=True, verbose_name=_(u'description')) + + def __unicode__(self): + return unicode(self.node) + + #def save(self, *args, **kwargs): + # if not issubclass( + # return super(WorkflowNode, self).save(*args, **kwargs) + + class Meta: + #unique_together = ('workflow', 'state') + verbose_name = _(u'workflow node') + verbose_name_plural = _(u'workflows nodes') + +""" +class WorkflowTaskAbilityGrant(models.Model): + workflow_state = models.ForeignKey(WorkflowState, related_name='workflow_state_ability', verbose_name=_(u'workflow state')) + content_type = models.ForeignKey(ContentType, related_name='workflow_state_ability_object')#, blank=True, null=True) + object_id = models.PositiveIntegerField()#blank=True, null=True) + content_object = generic.GenericForeignKey(ct_field='content_type', fk_field='object_id') + + def __unicode__(self): + return unicode(self.content_object) + + class Meta: + verbose_name = _(u'workflow state ability grant') + verbose_name_plural = _(u'workflows states ability grant') + +#TODO: WorkflowStateACLEntry +#WorkflowState +#Actor +#Object +#Permission (s) + + +#TODO: WorkflowStateAlarm +#label +#timedate +#interval + + +class WorkflowStateTransition(models.Model): + workflow_state_source = models.ForeignKey(WorkflowState, verbose_name=_(u'workflow state source')) + transition = models.ForeignKey(Transition, related_name='workflow_state_transition', verbose_name=_(u'transition')) + workflow_state_destination = models.ForeignKey(WorkflowState, related_name='workflow_state_transition_destination', verbose_name=_(u'workflow state destination')) + description = models.TextField(blank=True, verbose_name=_(u'description')) + + def __unicode__(self): + return unicode(self.transition) + + class Meta: + verbose_name = _(u'workflow state transition') + verbose_name_plural = _(u'workflows states transitions') + + +class WorkflowStateTransitionAbility(models.Model): + attribute_comparison_operand = models.CharField(max_length=8, default=OPERAND_AND, choices=OPERAND_CHOICES, verbose_name=_(u'operand')) + negate = models.BooleanField(verbose_name=_(u'negate'), help_text=_(u'Inverts the attribute comparison.')) + ability = models.ForeignKey(Ability, related_name='workflow_state_transition_ability', verbose_name=_(u'ability')) + + description = models.TextField(blank=True, verbose_name=_(u'description')) + + def __unicode__(self): + return unicode(self.ability) + + class Meta: + verbose_name = _(u'transition') + verbose_name_plural = _(u'transitions') + +""" +class WorkflowInstance(models.Model): + workflow = models.ForeignKey(Workflow, verbose_name=_(u'workflow')) + content_type = models.ForeignKey(ContentType, verbose_name=_(u'Content type'), related_name='workflow_instance_object')#, blank=True, null=True) + object_id = models.PositiveIntegerField()#blank=True, null=True) + content_object = generic.GenericForeignKey(ct_field='content_type', fk_field='object_id') + + def __unicode__(self): + return unicode(self.content_object) + + @property + def active_nodes(self): + return self.workflowinstanceactivenode_set + + def set_active_state(self, state): + active_state = self.get_active_state() + if active_state: + active_state.delete() + + # Trigger an exception if the state argument if not allowed for this workflow + state = WorkflowState.objects.get(workflow=self.workflow, state=state).state + + self.workflowinstanceactivestate_set.create( + workflow_instance = self, + state = state + ) + + def get_active_state(self): + try: + return self.workflowinstanceactivestate_set.get().state + except WorkflowInstanceActiveState.DoesNotExist: + return None + + active_state = property(get_active_state, set_active_state) + + class Meta: + verbose_name = _(u'workflow instance') + verbose_name_plural = _(u'workflow instances') + + # unique_together = ('content_type', 'object_id', 'workflow') + + +class WorkflowInstanceActiveNode(models.Model): + workflow_instance = models.ForeignKey(WorkflowInstance, verbose_name=_(u'workflow instance')) + workflow_node = models.ForeignKey(WorkflowNode, verbose_name=_(u'workflow node')) + + class Meta: + verbose_name = _(u'workflow instance active node') + verbose_name_plural = _(u'workflow instances active nodes') + + +class WorkflowInstanceState(models.Model): + """ + This class holds the active state for the workflow instance + """ + workflow_instance = models.ForeignKey(WorkflowInstance, verbose_name=_(u'workflow instance')) + state = models.ForeignKey(State, null=True, verbose_name=_(u'state')) + + class Meta: + unique_together = ('workflow_instance', 'state') + verbose_name = _(u'workflow instance active state') + verbose_name_plural = _(u'workflow instances active states') + + +# TODO: WorkflowInstanceActiveNodeHistory +# TODO: WorkflowInstanceActiveStateHistory diff --git a/apps/workflows/permissions.py b/apps/workflows/permissions.py new file mode 100644 index 0000000000..eaece09a8a --- /dev/null +++ b/apps/workflows/permissions.py @@ -0,0 +1,25 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ + +from permissions.models import PermissionNamespace, Permission + +namespace = PermissionNamespace('workflows', _(u'Workflows')) + +PERMISSION_WORKFLOW_SETUP_VIEW = Permission.objects.register(namespace, 'workflow_setup_view', _(u'View existing workflow templates')) +PERMISSION_WORKFLOW_SETUP_CREATE = Permission.objects.register(namespace, 'workflow_setup_create', _(u'Create new workflow templates')) +PERMISSION_WORKFLOW_SETUP_EDIT = Permission.objects.register(namespace, 'workflow_setup_edit', _(u'Edit existing workflow templates')) +PERMISSION_WORKFLOW_SETUP_DELETE = Permission.objects.register(namespace, 'workflow_setup_delete', _(u'Delete existing workflow templates')) + +PERMISSION_WORKFLOW_RUN = Permission.objects.register(namespace, 'workflow_setup_run', _(u'Execute a workflow')) + +#PERMISSION_STATE_SETUP_VIEW = Permission.objects.register(namespace, 'state_setup_view', _(u'View existing states')) +#PERMISSION_STATE_SETUP_CREATE = Permission.objects.register(namespace, 'state_setup_create', _(u'Create new state templates')) +#PERMISSION_STATE_SETUP_EDIT = Permission.objects.register(namespace, 'state_setup_edit', _(u'Edit existing state templates')) +#PERMISSION_STATE_SETUP_DELETE = Permission.objects.register(namespace, 'state_setup_delete', _(u'Delete existing state templates')) + +#PERMISSION_TRANSITION_SETUP_VIEW = Permission.objects.register(namespace, 'transition_setup_view', _(u'View existing transition templates')) +#PERMISSION_TRANSITION_SETUP_CREATE = Permission.objects.register(namespace, 'transition_setup_create', _(u'Create new transition templates')) +#PERMISSION_TRANSITION_SETUP_EDIT = Permission.objects.register(namespace, 'transition_setup_edit', _(u'Edit existing transition templates')) +#PERMISSION_TRANSITION_SETUP_DELETE = Permission.objects.register(namespace, 'transition_setup_delete', _(u'Delete existing transition templates')) + diff --git a/apps/workflows/static/images/icons/chart_organisation.png b/apps/workflows/static/images/icons/chart_organisation.png new file mode 100644 index 0000000000..5d408a347e Binary files /dev/null and b/apps/workflows/static/images/icons/chart_organisation.png differ diff --git a/apps/workflows/static/images/icons/chart_organisation_delete.png b/apps/workflows/static/images/icons/chart_organisation_delete.png new file mode 100644 index 0000000000..78cc3b9d17 Binary files /dev/null and b/apps/workflows/static/images/icons/chart_organisation_delete.png differ diff --git a/apps/workflows/static/images/icons/transmit_delete.png b/apps/workflows/static/images/icons/transmit_delete.png new file mode 100644 index 0000000000..f34531ca78 Binary files /dev/null and b/apps/workflows/static/images/icons/transmit_delete.png differ diff --git a/apps/workflows/tests.py b/apps/workflows/tests.py new file mode 100644 index 0000000000..501deb776c --- /dev/null +++ b/apps/workflows/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" + +from django.test import TestCase + + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.assertEqual(1 + 1, 2) diff --git a/apps/workflows/urls.py b/apps/workflows/urls.py new file mode 100644 index 0000000000..29b54ab972 --- /dev/null +++ b/apps/workflows/urls.py @@ -0,0 +1,21 @@ +from django.conf.urls.defaults import patterns, url + +urlpatterns = patterns('workflows.views', + url(r'^setup/workflow/list/$', 'setup_workflow_list', (), 'setup_workflow_list'), + url(r'^setup/workflow/create/$', 'setup_workflow_create', (), 'setup_workflow_create'), + url(r'^setup/workflow/(?P\d+)/edit/$', 'setup_workflow_edit', (), 'setup_workflow_edit'), + url(r'^setup/workflow/(?P\d+)/delete/$', 'setup_workflow_delete', (), 'setup_workflow_delete'), + + url(r'^setup/workflow/(?P\d+)/state/list/$', 'setup_workflow_states_list', (), 'setup_workflow_states_list'), + url(r'^setup/workflow/(?P\d+)/state/add/$', 'setup_workflow_state_add', (), 'setup_workflow_state_add'), + url(r'^setup/workflow/state/(?P\d+)/edit/$', 'setup_workflow_state_edit', (), 'setup_workflow_state_edit'), + url(r'^setup/workflow/state/(?P\d+)/remove/$', 'setup_workflow_state_remove', (), 'setup_workflow_state_remove'), + + url(r'^setup/state/list/$', 'setup_state_list', (), 'setup_state_list'), + url(r'^setup/state/create/$', 'setup_state_create', (), 'setup_state_create'), + url(r'^setup/state/(?P\d+)/edit/$', 'setup_state_edit', (), 'setup_state_edit'), + url(r'^setup/state/(?P\d+)/delete/$', 'setup_state_delete', (), 'setup_state_delete'), + + url(r'^setup/workflow/(?P\d+)/node/list/$', 'setup_workflow_node_list', (), 'setup_workflow_node_list'), + url(r'^setup/workflow/node/(?P\d+)/edit/$', 'setup_workflow_node_edit', (), 'setup_workflow_node_edit'), +) diff --git a/apps/workflows/views.py b/apps/workflows/views.py new file mode 100644 index 0000000000..33c5a778b9 --- /dev/null +++ b/apps/workflows/views.py @@ -0,0 +1,689 @@ +from __future__ import absolute_import + +import logging + +from django.http import HttpResponseRedirect +from django.shortcuts import render_to_response, get_object_or_404 +from django.template import RequestContext +from django.contrib import messages +from django.core.urlresolvers import reverse +from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext +from django.utils.safestring import mark_safe +from django.conf import settings +from django.core.exceptions import PermissionDenied + +from permissions.models import Permission +from common.utils import encapsulate +#from common.widgets import two_state_template +#from acls.models import AccessEntry + +from .models import Workflow, State, WorkflowState, WorkflowNode +from .forms import (WorkflowSetupForm, StateSetupForm, + WorkflowStateSetupForm, WorkflowNodeSetupForm) +from .permissions import (PERMISSION_WORKFLOW_SETUP_VIEW, + PERMISSION_WORKFLOW_SETUP_CREATE, PERMISSION_WORKFLOW_SETUP_EDIT, + PERMISSION_WORKFLOW_SETUP_DELETE, PERMISSION_STATE_SETUP_VIEW, + PERMISSION_STATE_SETUP_CREATE, PERMISSION_STATE_SETUP_EDIT, + PERMISSION_STATE_SETUP_DELETE) + +logger = logging.getLogger(__name__) + + +# Setup views +def setup_workflow_list(request): + Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_VIEW]) + + context = { + 'object_list': Workflow.objects.all(), + 'title': _(u'workflows'), + 'hide_link': True, + 'extra_columns': [ + {'name': _(u'Initial state'), 'attribute': encapsulate(lambda workflow: workflow.initial_state or _(u'None'))}, + ], + 'list_object_variable_name': 'workflow', + } + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) + + +def setup_workflow_create(request): + Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_CREATE]) + redirect_url = reverse('setup_workflow_list') + + if request.method == 'POST': + form = WorkflowSetupForm(request.POST) + if form.is_valid(): + workflow = form.save() + messages.success(request, _(u'Workflow created succesfully.')) + return HttpResponseRedirect(redirect_url) + else: + form = WorkflowSetupForm() + + return render_to_response('generic_form.html', { + 'title': _(u'create workflow'), + 'form': form, + }, + context_instance=RequestContext(request)) + + +def setup_workflow_edit(request, workflow_pk): + Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT]) + workflow = get_object_or_404(Workflow, pk=workflow_pk) + + if request.method == 'POST': + form = WorkflowSetupForm(instance=workflow, data=request.POST) + if form.is_valid(): + form.save() + messages.success(request, _(u'Workflow "%s" updated successfully.') % workflow) + return HttpResponseRedirect(reverse('setup_workflow_list')) + else: + form = WorkflowSetupForm(instance=workflow) + + return render_to_response('generic_form.html', { + 'title': _(u'edit workflow: %s') % workflow, + 'form': form, + 'workflow': workflow, + 'navigation_object_list': [ + {'object': 'workflow', 'name': _(u'workflow')}, + ], + }, + context_instance=RequestContext(request)) + + +def setup_workflow_delete(request, workflow_pk=None, workflow_pk_list=None): + post_action_redirect = None + + if workflow_pk: + workflows = [get_object_or_404(Workflow, pk=workflow_pk)] + post_action_redirect = reverse('setup_workflow_list') + elif workflow_pk_list: + workflows = [get_object_or_404(Workflow, pk=workflow_pk) for workflow_pk in workflow_pk_list.split(',')] + else: + messages.error(request, _(u'Must provide at least one workflow.')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_DELETE]) + except PermissionDenied: + workflows = AccessEntry.objects.filter_objects_by_access(PERMISSION_WORKFLOW_SETUP_DELETE, request.user, workflows) + + previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) + next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', '/'))) + + if request.method == 'POST': + for workflow in workflows: + try: + workflow.delete() + messages.success(request, _(u'Workflows "%s" deleted successfully.') % workflow) + except Exception, e: + messages.error(request, _(u'Error deleting workflow "%(workflow)s": %(error)s') % { + 'workflow': workflow, 'error': e + }) + + return HttpResponseRedirect(next) + + context = { + 'delete_view': True, + 'previous': previous, + 'next': next, + 'form_icon': u'chart_organisation_delete.png', + 'navigation_object_list': [ + {'object': 'workflow', 'name': _(u'workflow')}, + ], + } + if len(workflows) == 1: + context['workflow'] = workflows[0] + context['title'] = _(u'Are you sure you wish to delete the workflow: %s?') % ', '.join([unicode(d) for d in workflows]) + context['message'] = _('Will be removed from all documents.') + elif len(workflows) > 1: + context['title'] = _(u'Are you sure you wish to delete the workflows: %s?') % ', '.join([unicode(d) for d in workflows]) + context['message'] = _('Will be removed from all documents.') + + return render_to_response('generic_confirm.html', context, + context_instance=RequestContext(request)) + + +def setup_workflow_states_list(request, workflow_pk): + Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT]) + workflow = get_object_or_404(Workflow, pk=workflow_pk) + + context = { + 'object_list': workflow.workflowstate_set.all(), + 'title': _(u'states for workflow: %s') % workflow, + 'hide_link': True, + 'workflow': workflow, + 'navigation_object_list': [ + {'object': 'workflow', 'name': _(u'workflow')}, + ], + 'list_object_variable_name': 'workflow_state', + } + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) + + +def setup_workflow_state_add(request, workflow_pk): + Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT]) + redirect_url = reverse('setup_workflow_states_list', args=[workflow_pk]) + workflow = get_object_or_404(Workflow, pk=workflow_pk) + + if request.method == 'POST': + form = WorkflowStateSetupForm(workflow=workflow, data=request.POST) + if form.is_valid(): + state = form.save() + messages.success(request, _(u'worflow state created succesfully.')) + return HttpResponseRedirect(redirect_url) + else: + form = WorkflowStateSetupForm(workflow=workflow) + + return render_to_response('generic_form.html', { + 'title': _(u'add worflow state'), + 'form': form, + 'workflow': workflow, + 'navigation_object_list': [ + {'object': 'workflow', 'name': _(u'workflow')}, + ], + }, context_instance=RequestContext(request)) + + +def setup_workflow_state_edit(request, workflow_state_pk): + Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT]) + workflow_state = get_object_or_404(WorkflowState, pk=workflow_state_pk) + redirect_url = reverse('setup_workflow_states_list', args=[workflow_state.workflow.pk]) + + if request.method == 'POST': + form = WorkflowStateSetupForm(workflow=workflow_state.workflow, instance=workflow_state, data=request.POST) + if form.is_valid(): + state = form.save() + messages.success(request, _(u'worflow state edited succesfully.')) + return HttpResponseRedirect(redirect_url) + else: + form = WorkflowStateSetupForm(workflow=workflow_state.workflow, instance=workflow_state) + + return render_to_response('generic_form.html', { + 'title': _(u'edit worflow state: %s') % workflow_state, + 'form': form, + 'workflow': workflow_state.workflow, + 'workflow_state': workflow_state, + 'navigation_object_list': [ + {'object': 'workflow', 'name': _(u'workflow')}, + {'object': 'workflow_state', 'name': _(u'workflow state')} + ], + }, context_instance=RequestContext(request)) + + +def setup_workflow_state_remove(request, workflow_state_pk=None, workflow_state_pk_list=None): + post_action_redirect = None + + if workflow_state_pk: + workflow_states = [get_object_or_404(WorkflowState, pk=workflow_state_pk)] + post_action_redirect = reverse('setup_workflow_states_list', args=[workflow_states[0].workflow.pk]) + elif workflow_state_pk_list: + workflow_states = [get_object_or_404(WorkflowState, pk=workflow_state_pk) for workflow_state_pk in workflow_state_pk_list.split(',')] + else: + messages.error(request, _(u'Must provide at least one workflow state.')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT]) + except PermissionDenied: + workflow_states = AccessEntry.objects.filter_objects_by_access(PERMISSION_WORKFLOW_SETUP_EDIT, request.user, workflow_states) + + previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) + next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', '/'))) + + if request.method == 'POST': + for workflow_state in workflow_states: + try: + workflow_state.delete() + messages.success(request, _(u'Workflow states "%s" removed successfully.') % workflow_state) + except Exception, e: + messages.error(request, _(u'Error removing workflow state "%(workflow_state)s": %(error)s') % { + 'workflow_state': workflow_state, 'error': e + }) + + return HttpResponseRedirect(next) + + context = { + 'object_name': _(u'workflow state'), + 'delete_view': True, + 'previous': previous, + 'next': next, + 'form_icon': u'transmit_delete.png', + 'workflow': workflow_states[0].workflow, + 'navigation_object_list': [ + {'object': 'workflow', 'name': _(u'workflow')}, + {'object': 'workflow_state', 'name': _(u'workflow state')} + ], + } + if len(workflow_states) == 1: + context['title'] = _(u'Are you sure you wish to remove the workflow state: %s?') % ', '.join([unicode(d) for d in workflow_states]) + context['workflow_state'] = workflow_states[0] + elif len(states) > 1: + context['title'] = _(u'Are you sure you wish to remove the workflow states: %s?') % ', '.join([unicode(d) for d in workflow_states]) + + return render_to_response('generic_confirm.html', context, + context_instance=RequestContext(request)) + + +# Nodes +def setup_workflow_node_list(request, workflow_pk): + Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT]) + workflow = get_object_or_404(Workflow, pk=workflow_pk) + + context = { + 'object_list': workflow.workflow_nodes.all(), + 'extra_columns': [ + {'name': _(u'Posible next nodes'), 'attribute': encapsulate(lambda workflow_node: workflow_node.node.possible_next_nodes() or _(u'None'))}, + ], + 'title': _(u'nodes of workflow: %s') % workflow, + 'hide_link': True, + 'workflow': workflow, + 'navigation_object_list': [ + {'object': 'workflow', 'name': _(u'workflow')}, + ], + 'list_object_variable_name': 'workflow_node', + } + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) + + +def setup_workflow_node_edit(request, workflow_node_pk): + Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT]) + workflow_node = get_object_or_404(WorkflowNode, pk=workflow_node_pk) + redirect_url = reverse('setup_workflow_node_list', args=[workflow_node.workflow.pk]) + + if request.method == 'POST': + form = WorkflowNodeSetupForm(workflow=workflow_node.workflow, instance=workflow_node, data=request.POST) + if form.is_valid(): + state = form.save() + messages.success(request, _(u'worflow node edited succesfully.')) + return HttpResponseRedirect(redirect_url) + else: + form = WorkflowNodeSetupForm(workflow=workflow_node.workflow, instance=workflow_node) + + return render_to_response('generic_form.html', { + 'title': _(u'edit worflow node: %s') % workflow_node, + 'form': form, + 'workflow': workflow_node.workflow, + 'workflow_node': workflow_node, + 'navigation_object_list': [ + {'object': 'workflow', 'name': _(u'workflow')}, + {'object': 'workflow_node', 'name': _(u'workflow node')} + ], + }, context_instance=RequestContext(request)) +""" +def setup_workflow_transition_list(request, state_workflow_pk): + Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT]) + workflow = get_object_or_404(Workflow, pk=workflow_pk) + + context = { + 'object_list': workflow.workflowstate_set.all(), + 'title': _(u'states for workflow: %s') % workflow, + 'hide_link': True, + 'workflow': workflow, + 'navigation_object_list': [ + {'object': 'workflow', 'name': _(u'workflow')}, + ], + 'list_object_variable_name': 'workflow_state', + } + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) +""" +# States +def setup_state_list(request): + Permission.objects.check_permissions(request.user, [PERMISSION_STATE_SETUP_VIEW]) + + context = { + 'object_list': State.objects.all(), + 'title': _(u'states'), + 'hide_link': True, + } + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) + + +def setup_state_create(request): + Permission.objects.check_permissions(request.user, [PERMISSION_STATE_SETUP_CREATE]) + redirect_url = reverse('setup_state_list') + + if request.method == 'POST': + form = StateSetupForm(request.POST) + if form.is_valid(): + state = form.save() + messages.success(request, _(u'State created succesfully.')) + return HttpResponseRedirect(redirect_url) + else: + form = StateSetupForm() + + return render_to_response('generic_form.html', { + 'title': _(u'create state'), + 'form': form, + }, + context_instance=RequestContext(request)) + + +def setup_state_edit(request, state_pk): + Permission.objects.check_permissions(request.user, [PERMISSION_STATE_SETUP_EDIT]) + state = get_object_or_404(State, pk=state_pk) + + if request.method == 'POST': + form = StateSetupForm(instance=state, data=request.POST) + if form.is_valid(): + form.save() + messages.success(request, _(u'State "%s" updated successfully.') % state) + return HttpResponseRedirect(reverse('setup_state_list')) + else: + form = StateSetupForm(instance=state) + + return render_to_response('generic_form.html', { + 'title': _(u'edit state: %s') % state, + 'form': form, + 'object': state, + 'object_name': _(u'state'), + }, + context_instance=RequestContext(request)) + + +def setup_state_delete(request, state_pk=None, state_pk_list=None): + post_action_redirect = None + + if state_pk: + states = [get_object_or_404(State, pk=state_pk)] + post_action_redirect = reverse('setup_state_list') + elif state_pk_list: + states = [get_object_or_404(State, pk=state_pk) for state_pk in state_pk_list.split(',')] + else: + messages.error(request, _(u'Must provide at least one state.')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_STATE_SETUP_DELETE]) + except PermissionDenied: + states = AccessEntry.objects.filter_objects_by_access(PERMISSION_STATE_SETUP_DELETE, request.user, states) + + previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) + next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', '/'))) + + if request.method == 'POST': + for state in states: + try: + state.delete() + messages.success(request, _(u'States "%s" deleted successfully.') % state) + except Exception, e: + messages.error(request, _(u'Error deleting state "%(state)s": %(error)s') % { + 'state': state, 'error': e + }) + + return HttpResponseRedirect(next) + + context = { + 'object_name': _(u'state'), + 'delete_view': True, + 'previous': previous, + 'next': next, + 'form_icon': u'transmit_delete.png', + } + if len(states) == 1: + context['object'] = states[0] + context['title'] = _(u'Are you sure you wish to delete the state: %s?') % ', '.join([unicode(d) for d in states]) + context['message'] = _('Will be removed from all documents.') + elif len(states) > 1: + context['title'] = _(u'Are you sure you wish to delete the states: %s?') % ', '.join([unicode(d) for d in states]) + context['message'] = _('Will be removed from all documents.') + + return render_to_response('generic_confirm.html', context, + context_instance=RequestContext(request)) + +""" +# Transitions +def setup_transition_list(request): + Permission.objects.check_permissions(request.user, [PERMISSION_TRANSITION_SETUP_VIEW]) + + context = { + 'object_list': Transition.objects.all(), + 'title': _(u'transitions'), + 'hide_link': True, + 'list_object_variable_name': 'transition', + } + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) + + +def setup_transition_create(request): + Permission.objects.check_permissions(request.user, [PERMISSION_TRANSITION_SETUP_CREATE]) + redirect_url = reverse('setup_transition_list') + + if request.method == 'POST': + form = TransitionSetupForm(request.POST) + if form.is_valid(): + transition = form.save() + messages.success(request, _(u'Transition created succesfully.')) + return HttpResponseRedirect(redirect_url) + else: + form = TransitionSetupForm() + + return render_to_response('generic_form.html', { + 'title': _(u'create transition'), + 'form': form, + }, + context_instance=RequestContext(request)) + + +def setup_transition_edit(request, transition_pk): + Permission.objects.check_permissions(request.user, [PERMISSION_TRANSITION_SETUP_EDIT]) + transition = get_object_or_404(Transition, pk=transition_pk) + + if request.method == 'POST': + form = TransitionSetupForm(instance=transition, data=request.POST) + if form.is_valid(): + form.save() + messages.success(request, _(u'Transition "%s" updated successfully.') % transition) + return HttpResponseRedirect(reverse('setup_transition_list')) + else: + form = TransitionSetupForm(instance=transition) + + return render_to_response('generic_form.html', { + 'title': _(u'edit transition: %s') % transition, + 'form': form, + 'transition': transition, + 'navigation_object_list': [ + {'object': 'transition', 'name': _(u'transition')}, + ], + }, + context_instance=RequestContext(request)) + + +def setup_transition_delete(request, transition_pk=None, transition_pk_list=None): + post_action_redirect = None + + if transition_pk: + transitions = [get_object_or_404(Transition, pk=transition_pk)] + post_action_redirect = reverse('setup_transition_list') + elif transition_pk_list: + transitions = [get_object_or_404(Transition, pk=transition_pk) for transition_pk in transition_pk_list.split(',')] + else: + messages.error(request, _(u'Must provide at least one transition.')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_TRANSITION_SETUP_DELETE]) + except PermissionDenied: + transitions = AccessEntry.objects.filter_objects_by_access(PERMISSION_TRANSITION_SETUP_DELETE, request.user, transitions) + + previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) + next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', '/'))) + + if request.method == 'POST': + for transition in transitions: + try: + transition.delete() + messages.success(request, _(u'Transitions "%s" deleted successfully.') % transition) + except Exception, e: + messages.error(request, _(u'Error deleting transition "%(transition)s": %(error)s') % { + 'transition': transition, 'error': e + }) + + return HttpResponseRedirect(next) + + context = { + 'object_name': _(u'transition'), + 'delete_view': True, + 'previous': previous, + 'next': next, + 'form_icon': u'transmit_delete.png', + 'navigation_object_list': [ + {'object': 'transition', 'name': _(u'transition')}, + ], + } + if len(transitions) == 1: + context['transition'] = transitions[0] + context['title'] = _(u'Are you sure you wish to delete the transition: %s?') % ', '.join([unicode(d) for d in transitions]) + context['message'] = _('Will be removed from all documents.') + elif len(transitions) > 1: + context['title'] = _(u'Are you sure you wish to delete the transitions: %s?') % ', '.join([unicode(d) for d in transitions]) + context['message'] = _('Will be removed from all documents.') + + return render_to_response('generic_confirm.html', context, + context_instance=RequestContext(request)) +""" +""" +# State transitions +def setup_workflow_state_transitions_list(request, workflow_state_pk): + Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT]) + workflow_state = get_object_or_404(WorkflowState, pk=workflow_state_pk) + + context = { + 'object_list': workflow_state.transitions.all(), + 'title': _(u'transitions for workflow state: %s') % workflow_state, + 'hide_link': True, + 'workflow_state': workflow_state, + 'workflow': workflow_state.workflow, + 'navigation_object_list': [ + {'object': 'workflow', 'name': _(u'workflow')}, + {'object': 'workflow_state', 'name': _(u'state')}, + ], + 'list_object_variable_name': 'state_transition', + 'extra_columns': [ + {'name': _(u'Destination'), 'attribute': 'workflow_state_destination'}, + ], + } + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) + + +def setup_workflow_state_transition_add(request, workflow_state_pk): + Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT]) + workflow_state = get_object_or_404(WorkflowState, pk=workflow_state_pk) + redirect_url = reverse('setup_workflow_state_transitions_list', args=[workflow_state_pk]) + + if request.method == 'POST': + form = WorkflowStateTransitionSetupForm(workflow_state=workflow_state, data=request.POST) + if form.is_valid(): + workflow_state_transition = form.save() + messages.success(request, _(u'worflow state transition created succesfully.')) + return HttpResponseRedirect(redirect_url) + else: + form = WorkflowStateTransitionSetupForm(workflow_state=workflow_state) + + return render_to_response('generic_form.html', { + 'title': _(u'add transition to worflow state: %s') % workflow_state, + 'form': form, + 'workflow_state': workflow_state, + 'workflow': workflow_state.workflow, + 'navigation_object_list': [ + {'object': 'workflow', 'name': _(u'workflow')}, + {'object': 'workflow_state', 'name': _(u'state')}, + ], + }, context_instance=RequestContext(request)) + + +def setup_workflow_state_transition_edit(request, work_state_transition_pk): + Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT]) + workflow_state_transition = get_object_or_404(WorkflowStateTransition, pk=work_state_transition_pk) + redirect_url = reverse('setup_workflow_state_transitions_list', args=[workflow_state_transition.workflow_state_source.pk]) + + if request.method == 'POST': + form = WorkflowStateTransitionSetupForm(workflow_state=workflow_state_transition.workflow_state_source, instance=workflow_state_transition, data=request.POST) + if form.is_valid(): + workflow_state_transition = form.save() + messages.success(request, _(u'worflow state transition edited succesfully.')) + return HttpResponseRedirect(redirect_url) + else: + form = WorkflowStateSetupForm(workflow_state=workflow_state_transition.workflow_state_source, instance=workflow_state_transition) + + return render_to_response('generic_form.html', { + 'title': _(u'edit worflow state transition: %s') % workflow_state_transition, + 'form': form, + 'workflow_state': workflow_state_transition.workflow_state_source, + 'workflow': workflow_state_transition.workflow_state_source.workflow, + 'workflow_state_transition': workflow_state_transition, + 'navigation_object_list': [ + {'object': 'workflow', 'name': _(u'workflow')}, + {'object': 'workflow_state', 'name': _(u'state')}, + {'object': 'workflow_state_transition', 'name': _(u'transition')}, + ], + 'list_object_variable_name': 'workflow_state_transition', + }, context_instance=RequestContext(request)) +""" +""" +def setup_state_transition_remove(request, state_transition_pk=None, state_transition_pk_list=None): + post_action_redirect = None + + if state_transition_pk: + state_transitions = [get_object_or_404(WorkflowState, pk=state_transition_pk)] + post_action_redirect = reverse('setup_state_transitions_list', args=[state_transitions[0].state.pk]) + elif state_transition_pk_list: + state_transitions = [get_object_or_404(WorkflowState, pk=state_transition_pk) for state_transition_pk in state_transition_pk_list.split(',')] + else: + messages.error(request, _(u'Must provide at least one state state.')) + return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) + + try: + Permission.objects.check_permissions(request.user, [PERMISSION_STATE_SETUP_DELETE]) + except PermissionDenied: + state_transitions = AccessEntry.objects.filter_objects_by_access(PERMISSION_STATE_SETUP_DELETE, request.user, state_transitions) + + previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) + next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', '/'))) + + if request.method == 'POST': + for state_transition in state_transitions: + try: + state_transition.delete() + messages.success(request, _(u'Workflow states "%s" removed successfully.') % state_transition) + except Exception, e: + messages.error(request, _(u'Error removing state state "%(state_transition)s": %(error)s') % { + 'state_transition': state_transition, 'error': e + }) + + return HttpResponseRedirect(next) + + context = { + 'object_name': _(u'state state'), + 'delete_view': True, + 'previous': previous, + 'next': next, + 'form_icon': u'transmit_delete.png', + 'state': state_transitions[0].state, + 'navigation_object_list': [ + {'object': 'state', 'name': _(u'state')}, + {'object': 'state_transition', 'name': _(u'state state')} + ], + } + if len(state_transitions) == 1: + context['title'] = _(u'Are you sure you wish to remove the state state: %s?') % ', '.join([unicode(d) for d in state_transitions]) + context['state_transition'] = state_transitions[0] + elif len(states) > 1: + context['title'] = _(u'Are you sure you wish to remove the state states: %s?') % ', '.join([unicode(d) for d in state_transitions]) + + return render_to_response('generic_confirm.html', context, + context_instance=RequestContext(request)) +""" diff --git a/requirements/production.txt b/requirements/production.txt index 0e4c94e327..a6b71bd4a1 100644 --- a/requirements/production.txt +++ b/requirements/production.txt @@ -58,3 +58,4 @@ requests==0.10.1 -e git+https://github.com/toastdriven/django-haystack.git@c6fd81d4163eb816476a853d416b68757e0c7ca4#egg=django_haystack-dev Whoosh==2.3.2 Unidecode==0.04.9 +elementtree==1.2.7-20070827-preview diff --git a/settings.py b/settings.py index b1f4ba0929..82f5a48c27 100644 --- a/settings.py +++ b/settings.py @@ -176,7 +176,7 @@ INSTALLED_APPS = ( 'main', 'rest_api', 'document_signatures', - + 'workflows', # Has to be last so the other apps can register it's signals 'signaler', ) diff --git a/urls.py b/urls.py index ee1f199449..9a4cd7ad26 100644 --- a/urls.py +++ b/urls.py @@ -33,6 +33,7 @@ urlpatterns = patterns('', (r'^documents/signatures/', include('document_signatures.urls')), (r'^feedback/', include('feedback.urls')), (r'^mailer/', include('mailer.urls')), + (r'^workflows/', include('workflows.urls')), )