From 94ec7ca47f42aac020cb951ccbd71b27ec1d87a2 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 15 Mar 2012 01:55:03 -0400 Subject: [PATCH 01/52] Workflows app initial commit --- apps/workflows/__init__.py | 0 apps/workflows/models.py | 3 +++ apps/workflows/tests.py | 16 ++++++++++++++++ apps/workflows/views.py | 1 + settings.py | 2 +- urls.py | 1 + 6 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 apps/workflows/__init__.py create mode 100644 apps/workflows/models.py create mode 100644 apps/workflows/tests.py create mode 100644 apps/workflows/views.py diff --git a/apps/workflows/__init__.py b/apps/workflows/__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..71a8362390 --- /dev/null +++ b/apps/workflows/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. 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/views.py b/apps/workflows/views.py new file mode 100644 index 0000000000..60f00ef0ef --- /dev/null +++ b/apps/workflows/views.py @@ -0,0 +1 @@ +# Create your views here. diff --git a/settings.py b/settings.py index c6894408c2..acb77da668 100644 --- a/settings.py +++ b/settings.py @@ -175,7 +175,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')), ) From 8c8befabdd00a1a3a0916a7d40d9b134ce0660d9 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 16 Mar 2012 01:14:25 -0400 Subject: [PATCH 02/52] Initial model schema, workflow setup button, workflow list view --- apps/workflows/__init__.py | 19 ++ apps/workflows/literals.py | 9 + apps/workflows/migrations/0001_initial.py | 202 ++++++++++++++++++ apps/workflows/migrations/__init__.py | 0 apps/workflows/models.py | 145 ++++++++++++- apps/workflows/permissions.py | 9 + .../images/icons/chart_organisation.png | Bin 0 -> 1197 bytes .../icons/chart_organisation_delete.png | Bin 0 -> 1612 bytes apps/workflows/urls.py | 5 + apps/workflows/views.py | 58 ++++- 10 files changed, 444 insertions(+), 3 deletions(-) create mode 100644 apps/workflows/literals.py create mode 100644 apps/workflows/migrations/0001_initial.py create mode 100644 apps/workflows/migrations/__init__.py create mode 100644 apps/workflows/permissions.py create mode 100644 apps/workflows/static/images/icons/chart_organisation.png create mode 100644 apps/workflows/static/images/icons/chart_organisation_delete.png create mode 100644 apps/workflows/urls.py diff --git a/apps/workflows/__init__.py b/apps/workflows/__init__.py index e69de29bb2..dd31e1196e 100644 --- a/apps/workflows/__init__.py +++ b/apps/workflows/__init__.py @@ -0,0 +1,19 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ + +from navigation.api import register_links, register_multi_item_links +from project_setup.api import register_setup + +from .permissions import PERMISSION_WORKFLOW_SETUP_VIEW + +setup_workflow_link = {'text': _(u'workflows'), 'view': 'setup_workflow_list', 'icon': 'chart_organisation.png', 'permissions': [PERMISSION_WORKFLOW_SETUP_VIEW]} + +setup_workflow_list_link = {'text': _(u'workflow list'), 'view': 'setup_workflow_list', 'famfam': 'chart_organisation', 'permissions': [PERMISSION_WORKFLOW_SETUP_VIEW]} + +#register_links(User, [user_edit, user_set_password, user_delete]) +register_links(['setup_workflow_list'], [setup_workflow_link], menu_name=u'secondary_menu') +#register_multi_item_links(['user_list'], [user_multiple_set_password, user_multiple_delete]) + + +register_setup(setup_workflow_link) diff --git a/apps/workflows/literals.py b/apps/workflows/literals.py new file mode 100644 index 0000000000..8811669442 --- /dev/null +++ b/apps/workflows/literals.py @@ -0,0 +1,9 @@ +from django.utils.translation import ugettext_lazy as _ + +OPERAND_OR = 'or' +OPERAND_AND = 'and' + +OPERAND_CHOICES = ( + (OPERAND_OR, _(u'or')), + (OPERAND_AND, _(u'and')) +) 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/__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 index 71a8362390..6824cd61d9 100644 --- a/apps/workflows/models.py +++ b/apps/workflows/models.py @@ -1,3 +1,144 @@ -from django.db import models +from __future__ import absolute_import -# Create your models here. +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 permissions.models import StoredPermission + +from .literals import OPERAND_CHOICES, OPERAND_AND + + +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_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 + + class Meta: + verbose_name = _(u'workflow') + verbose_name_plural = _(u'workflows') + + +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 '%s (%s)' % (self.name, self.workflow.name) + return self.label + + class Meta: + verbose_name = _(u'state') + verbose_name_plural = _(u'states') + + +class Transition(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 '%s (%s)' % (self.name, self.workflow.name) + return self.label + + class Meta: + verbose_name = _(u'transition') + verbose_name_plural = _(u'transitions') + + +class WorkflowState(models.Model): + workflow = models.ForeignKey(Workflow, related_name='workflow_state_workflow', verbose_name=_(u'workflow')) + state = models.ForeignKey(State, related_name='workflow_state_state', verbose_name=_(u'state')) + description = models.TextField(blank=True, verbose_name=_(u'description')) + + def __unicode__(self): + #return '%s (%s)' % (self.label, self.workflow.label) + return unicode(self.state) + + class Meta: + verbose_name = _(u'workflow state') + verbose_name_plural = _(u'workflows states') + + +class WorkflowStateAbilityGrant(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, related_name='workflow_state_transition_source', 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') + workflow_state = models.ForeignKey(WorkflowState, related_name='workflow_instance_state', verbose_name=_(u'state')) + + def __unicode__(self): + return unicode(self.content_object) + + class Meta: + unique_together = ('content_type', 'object_id', 'workflow') diff --git a/apps/workflows/permissions.py b/apps/workflows/permissions.py new file mode 100644 index 0000000000..ef1939942c --- /dev/null +++ b/apps/workflows/permissions.py @@ -0,0 +1,9 @@ +from __future__ import absolute_import + +from django.utils.translation import ugettext_lazy as _ + +from permissions.models import PermissionNamespace, Permission + +user_management_namespace = PermissionNamespace('workflows', _(u'Workflows')) + +PERMISSION_WORKFLOW_SETUP_VIEW = Permission.objects.register(user_management_namespace, 'workflow_setup_view', _(u'View existing workflows 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 0000000000000000000000000000000000000000..5d408a347e97532a497f58544b27742339a35b9a GIT binary patch literal 1197 zcmV;e1XBBnP)FS~p0-Xc58u)DLr`R1E%=KJPb28~N{|5dncN$9Zz zfD8c{)&$4OU}Ewt9Ku(#q3{R_7&Q3rCw_%B6Ey%Hf(p=*9FE;O*+c!XF2$jMjtanv zxdiwBKV#35eE^cGe*5(ZSXDFWaVfwU3S744fT!stL;=MySz8f^LjhaTl9&ai2TOI@ zZ4RQBXbPaj6+jCZYN`Pya5%X@d8wkhj5RrTe`49^WKWJ)u(Xkr&E_Fuid<`AD=6(cJloK*15R6U{wiQ@F|?L zw6}DBiuJY6Axf&>M_EAY>+36na;vJ_alE@DfD92OUAuDq>*(kxIx(z8u|Sg$0>;M1 zcKJ-}FPYxn-UrC-#^+)Pm%<4>B)MS-IirlW@ctI(=?&0tE;uWz1`F_Ej>Oy z{_h8-om2NWz9sON9LXa^f|ejPJUl#)gXd`GRljFw{_1#~+p+)7z`($fp`oEavHgI< zxeIaF?{0s8|Mw0jmD@19Bwez`O(16z|RH9s~uLPfJQSyCE&kDk374QY_N034p1}B#?0xC0(PMe89k%IXf?#q?5N$n zUt;8##|vn^G8w%-3`$Y=9w%2*fF%-OWQ^KbDW%+)%W(8xn{=#bZ9(lJ#pnTQ7)O~mygAw z-Udzkj*9e_?UJYUbm7+dXDW;?2XRbqGG2}U+>it07OUK9EfRiy`QCg*$efU5GBiAz zjM+tYLnC7n!XY88+b=Hm{D9mna+`xVF0F}|7kkztAq_rq zxDzZP>Hkgs7c`^-_KTFs-k-4gCgO>iiVw zySXrDMBys)PYf*r=ZS;_yeV7oMK)#s**G2OPl(!?O2Q&>Lhxwve37t(=f;-i6mYiQ z0lmm>SIHiW#6^|o4n(xkI8Va1oKd%C)K1?MnU-`EjvLKd6wVWf*vjkaYm-wQYHhsd zJni7+#r)Dgf6soh=Wrgmy&>Gx@`F3iv)`S5i(EF4!||Lz#6q%Ocb5A~Wj-6QZVKTF zDihwMGA0(n*;zAF!VI-5gMRx;DnCp`;Aj9!K((O%3|H1{z87Es@s6^>K7)H@00000 LNkvXXu0mjfr0YpD literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..78cc3b9d179750305c784dd5a7b2f5eb033551c4 GIT binary patch literal 1612 zcmV-S2DABzP)mp8wA`$ z03m$<2isrgR!V6=mKgJ=ZGd6B$(=0%l0+K@jZVlp>>&dIfs?GE6G1iz@SO(CYmnT- z?;4-yIE?NZnE>q=0(l@;m^zFL;y6jlG69NegtcqX3XzxwQtC6qxw1^aibn8b%TE7n z%XCaSJ|a0tNU|R>!XtCWraivlE@pQHjp8J->dN{xZR=a!siFIrW1i){pGIf4vLGTh z>rNu;HMD;A`#X)kq=fiKy!XF7pfxr&4i0Tc5Q!qovXJQ69uB zbTl5w*L58}pKoT8d!1KaLqo#}!aPX#;bAZ;Va~AqG7(@r)wOHa_85lYF-=p5jl_+U zWeL$}tgX4ZxuL14$)~DnjU}Sd#t7AsWW-{(aGIvpn5HG1WO47wvdlc$O6v)Af_WgH zeZ0Qm6)?+(+)8h&ih_@QTUns#?Bh!b6B8KQ-RW`lOK;)gdntrz@oi116O4eyEVoPp z?HwIMLBZa=w`v;L8eQBwW)dbXj#$xd=(upf5n>jmGmITb?qmXX{unw6^YatVhs`;0 zPK+}Kb;E!u^Gc~0stR3EQCM<2`CSm8<6v`!s-*F>pjx0fM$=o=C&S%{U18}lBA$5Wa<3s`{Ux^v+5dL42v@j2PHEG@+bROQ%-${(nlVJcijfK^78n*MmUVV_H(E{{5|&1ocw;>nalNTdWe8amV(>1Y$~u! z^Hv37fkrNjgu_Rfmm}fOQNmOwV+uQ8B1d#Q@40pE~|gBZBxr9HA2z+LhZZ`Np@ml z)nnY{>mQi9qiXpIME37N?2oHtmBQR6Vt`0f{HS+S!oA=b{IYcuE_VCpE~`B8a^{q!@U`gSuQB1V zTHM^T>pfbS$1NVe=G&f_X^9k)c<@McuTZH|VD9gF_lc*=Rv*}_L#}gTEc!@D%g4#x z3o-SzHxc}DCoIZ;%P`UuM3OF-3lix;-onNB$+ry;A3s0V79!L1Y+N)KI#WVNek{dw~NbiY&Ym5iMXXo)_5alzWw`1;S7&8z+ymzy8fF5+>GPxw*DPDX| z7QnO^vSLuv@Yk$5ObA?or=$c1r6e!OsUg72x=h*O5A@@vZkz=VO>UkQ{IK;%ftkdb zeN+ndaUEd4gsD!%P_2v^T zTC8LpNa=Jj literal 0 HcmV?d00001 diff --git a/apps/workflows/urls.py b/apps/workflows/urls.py new file mode 100644 index 0000000000..bcad909101 --- /dev/null +++ b/apps/workflows/urls.py @@ -0,0 +1,5 @@ +from django.conf.urls.defaults import patterns, url + +urlpatterns = patterns('workflows.views', + url(r'^setup/list/$', 'setup_workflow_list', (), 'setup_workflow_list'), +) diff --git a/apps/workflows/views.py b/apps/workflows/views.py index 60f00ef0ef..ae8d56dbb6 100644 --- a/apps/workflows/views.py +++ b/apps/workflows/views.py @@ -1 +1,57 @@ -# Create your views here. +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 documents.permissions import (PERMISSION_DOCUMENT_CREATE, +# PERMISSION_DOCUMENT_NEW_VERSION) +#from documents.models import DocumentType, Document +#from documents.conf.settings import THUMBNAIL_SIZE +#from metadata.api import decode_metadata_from_url, metadata_repr_as_list +from permissions.models import Permission +#from common.utils import encapsulate +#from common.widgets import two_state_template +#import sendfile +#from acls.models import AccessEntry + +from .models import Workflow +#from .literals import (SOURCE_CHOICE_WEB_FORM, SOURCE_CHOICE_STAGING, +# SOURCE_CHOICE_WATCH, SOURCE_CHOICE_POP3_EMAIL, SOURCE_CHOICE_IMAP_EMAIL) +#from .literals import (SOURCE_UNCOMPRESS_CHOICE_Y, +# SOURCE_UNCOMPRESS_CHOICE_ASK) +#from .staging import create_staging_file_class +#from .forms import (StagingDocumentForm, WebFormForm, +# WatchFolderSetupForm) +from .permissions import PERMISSION_WORKFLOW_SETUP_VIEW + + +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, + #'list_object_variable_name': 'source', + #'source_type': source_type, + #'extra_columns': [ + # {'name': _(u'Enabled'), 'attribute': encapsulate(lambda source: two_state_template(source.enabled))}, + #], + } + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) From ffb5fc828696a5242d5f56903a748589f8ac5b93 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 16 Mar 2012 01:40:04 -0400 Subject: [PATCH 03/52] Added workflow create, edit and delete views --- apps/workflows/__init__.py | 14 ++-- apps/workflows/forms.py | 11 +++ apps/workflows/permissions.py | 5 +- apps/workflows/urls.py | 5 +- apps/workflows/views.py | 122 ++++++++++++++++++++++++++++------ 5 files changed, 132 insertions(+), 25 deletions(-) create mode 100644 apps/workflows/forms.py diff --git a/apps/workflows/__init__.py b/apps/workflows/__init__.py index dd31e1196e..898fdeed25 100644 --- a/apps/workflows/__init__.py +++ b/apps/workflows/__init__.py @@ -5,15 +5,21 @@ from django.utils.translation import ugettext_lazy as _ from navigation.api import register_links, register_multi_item_links from project_setup.api import register_setup -from .permissions import PERMISSION_WORKFLOW_SETUP_VIEW +from .permissions import (PERMISSION_WORKFLOW_SETUP_VIEW, + PERMISSION_WORKFLOW_SETUP_CREATE, PERMISSION_WORKFLOW_SETUP_EDIT, + PERMISSION_WORKFLOW_SETUP_DELETE) +from .models import Workflow setup_workflow_link = {'text': _(u'workflows'), 'view': 'setup_workflow_list', 'icon': 'chart_organisation.png', 'permissions': [PERMISSION_WORKFLOW_SETUP_VIEW]} setup_workflow_list_link = {'text': _(u'workflow list'), 'view': 'setup_workflow_list', 'famfam': 'chart_organisation', 'permissions': [PERMISSION_WORKFLOW_SETUP_VIEW]} +setup_workflow_create_link = {'text': _(u'create new'), 'view': 'setup_workflow_create', 'famfam': 'chart_organisation_add', 'permissions': [PERMISSION_WORKFLOW_SETUP_CREATE]} +setup_workflow_edit_link = {'text': _(u'edit'), 'view': 'setup_workflow_edit', 'args': 'object.pk', 'famfam': 'chart_organisation', 'permissions': [PERMISSION_WORKFLOW_SETUP_EDIT]} +setup_workflow_delete_link = {'text': _(u'delete'), 'view': 'setup_workflow_delete', 'args': 'object.pk', 'famfam': 'chart_organisation_delete', 'permissions': [PERMISSION_WORKFLOW_SETUP_DELETE]} -#register_links(User, [user_edit, user_set_password, user_delete]) -register_links(['setup_workflow_list'], [setup_workflow_link], menu_name=u'secondary_menu') +register_links(Workflow, [setup_workflow_edit_link, setup_workflow_delete_link]) +register_links([Workflow, 'setup_workflow_list', 'setup_workflow_create'], [setup_workflow_list_link], menu_name=u'form_header') +register_links([Workflow, 'setup_workflow_list', 'setup_workflow_create'], [setup_workflow_create_link], menu_name=u'secondary_menu') #register_multi_item_links(['user_list'], [user_multiple_set_password, user_multiple_delete]) - register_setup(setup_workflow_link) diff --git a/apps/workflows/forms.py b/apps/workflows/forms.py new file mode 100644 index 0000000000..800affbb35 --- /dev/null +++ b/apps/workflows/forms.py @@ -0,0 +1,11 @@ +from __future__ import absolute_import + +from django import forms +from django.utils.translation import ugettext_lazy as _ + +from .models import Workflow + + +class WorkflowSetupForm(forms.ModelForm): + class Meta: + model = Workflow diff --git a/apps/workflows/permissions.py b/apps/workflows/permissions.py index ef1939942c..89003b2e84 100644 --- a/apps/workflows/permissions.py +++ b/apps/workflows/permissions.py @@ -6,4 +6,7 @@ from permissions.models import PermissionNamespace, Permission user_management_namespace = PermissionNamespace('workflows', _(u'Workflows')) -PERMISSION_WORKFLOW_SETUP_VIEW = Permission.objects.register(user_management_namespace, 'workflow_setup_view', _(u'View existing workflows templates')) +PERMISSION_WORKFLOW_SETUP_VIEW = Permission.objects.register(user_management_namespace, 'workflow_setup_view', _(u'View existing workflow templates')) +PERMISSION_WORKFLOW_SETUP_CREATE = Permission.objects.register(user_management_namespace, 'workflow_setup_create', _(u'Create new workflow templates')) +PERMISSION_WORKFLOW_SETUP_EDIT = Permission.objects.register(user_management_namespace, 'workflow_setup_edit', _(u'Edit existing workflow templates')) +PERMISSION_WORKFLOW_SETUP_DELETE = Permission.objects.register(user_management_namespace, 'workflow_setup_delete', _(u'Delete existing workflow templates')) diff --git a/apps/workflows/urls.py b/apps/workflows/urls.py index bcad909101..ee434eeca9 100644 --- a/apps/workflows/urls.py +++ b/apps/workflows/urls.py @@ -1,5 +1,8 @@ from django.conf.urls.defaults import patterns, url urlpatterns = patterns('workflows.views', - url(r'^setup/list/$', 'setup_workflow_list', (), 'setup_workflow_list'), + 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'), ) diff --git a/apps/workflows/views.py b/apps/workflows/views.py index ae8d56dbb6..cb4d373874 100644 --- a/apps/workflows/views.py +++ b/apps/workflows/views.py @@ -13,26 +13,16 @@ from django.utils.safestring import mark_safe from django.conf import settings from django.core.exceptions import PermissionDenied -#from documents.permissions import (PERMISSION_DOCUMENT_CREATE, -# PERMISSION_DOCUMENT_NEW_VERSION) -#from documents.models import DocumentType, Document -#from documents.conf.settings import THUMBNAIL_SIZE -#from metadata.api import decode_metadata_from_url, metadata_repr_as_list from permissions.models import Permission -#from common.utils import encapsulate +from common.utils import encapsulate #from common.widgets import two_state_template -#import sendfile #from acls.models import AccessEntry from .models import Workflow -#from .literals import (SOURCE_CHOICE_WEB_FORM, SOURCE_CHOICE_STAGING, -# SOURCE_CHOICE_WATCH, SOURCE_CHOICE_POP3_EMAIL, SOURCE_CHOICE_IMAP_EMAIL) -#from .literals import (SOURCE_UNCOMPRESS_CHOICE_Y, -# SOURCE_UNCOMPRESS_CHOICE_ASK) -#from .staging import create_staging_file_class -#from .forms import (StagingDocumentForm, WebFormForm, -# WatchFolderSetupForm) -from .permissions import PERMISSION_WORKFLOW_SETUP_VIEW +from .forms import WorkflowSetupForm +from .permissions import (PERMISSION_WORKFLOW_SETUP_VIEW, + PERMISSION_WORKFLOW_SETUP_CREATE, PERMISSION_WORKFLOW_SETUP_EDIT, + PERMISSION_WORKFLOW_SETUP_DELETE) logger = logging.getLogger(__name__) @@ -45,13 +35,107 @@ def setup_workflow_list(request): context = { 'object_list': Workflow.objects.all(), 'title': _(u'workflows'), - #'hide_link': True, + 'hide_link': True, #'list_object_variable_name': 'source', #'source_type': source_type, - #'extra_columns': [ - # {'name': _(u'Enabled'), 'attribute': encapsulate(lambda source: two_state_template(source.enabled))}, - #], + 'extra_columns': [ + {'name': _(u'Initial state'), 'attribute': encapsulate(lambda workflow: workflow.initial_state or _(u'None'))}, + ], } 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') + #previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', redirect_url))) + + 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, + 'object': workflow, + 'object_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 = { + 'object_name': _(u'workflow'), + 'delete_view': True, + 'previous': previous, + 'next': next, + 'form_icon': u'chart_organisation_delete.png', + } + if len(workflows) == 1: + context['object'] = 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)) From 89aeb8ad7cacf8901066a29957e2964d6cf18e79 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 16 Mar 2012 01:55:21 -0400 Subject: [PATCH 04/52] Added state list, create, edit, delete views --- apps/workflows/__init__.py | 19 ++- apps/workflows/forms.py | 7 +- apps/workflows/permissions.py | 16 ++- .../static/images/icons/transmit_delete.png | Bin 0 -> 2575 bytes apps/workflows/urls.py | 5 + apps/workflows/views.py | 119 +++++++++++++++++- 6 files changed, 153 insertions(+), 13 deletions(-) create mode 100644 apps/workflows/static/images/icons/transmit_delete.png diff --git a/apps/workflows/__init__.py b/apps/workflows/__init__.py index 898fdeed25..4521dc5142 100644 --- a/apps/workflows/__init__.py +++ b/apps/workflows/__init__.py @@ -7,8 +7,10 @@ from project_setup.api import register_setup from .permissions import (PERMISSION_WORKFLOW_SETUP_VIEW, PERMISSION_WORKFLOW_SETUP_CREATE, PERMISSION_WORKFLOW_SETUP_EDIT, - PERMISSION_WORKFLOW_SETUP_DELETE) -from .models import Workflow + 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, Transition setup_workflow_link = {'text': _(u'workflows'), 'view': 'setup_workflow_list', 'icon': 'chart_organisation.png', 'permissions': [PERMISSION_WORKFLOW_SETUP_VIEW]} @@ -17,9 +19,18 @@ setup_workflow_create_link = {'text': _(u'create new'), 'view': 'setup_workflow_ setup_workflow_edit_link = {'text': _(u'edit'), 'view': 'setup_workflow_edit', 'args': 'object.pk', 'famfam': 'chart_organisation', 'permissions': [PERMISSION_WORKFLOW_SETUP_EDIT]} setup_workflow_delete_link = {'text': _(u'delete'), 'view': 'setup_workflow_delete', 'args': 'object.pk', 'famfam': 'chart_organisation_delete', 'permissions': [PERMISSION_WORKFLOW_SETUP_DELETE]} +setup_state_list_link = {'text': _(u'state list'), 'view': 'setup_state_list', 'famfam': 'transmit', 'permissions': [PERMISSION_STATE_SETUP_VIEW]} +setup_state_create_link = {'text': _(u'create new'), 'view': 'setup_state_create', 'famfam': 'transmit_add', 'permissions': [PERMISSION_STATE_SETUP_CREATE]} +setup_state_edit_link = {'text': _(u'edit'), 'view': 'setup_state_edit', 'args': 'object.pk', 'famfam': 'transmit_edit', 'permissions': [PERMISSION_STATE_SETUP_EDIT]} +setup_state_delete_link = {'text': _(u'delete'), 'view': 'setup_state_delete', 'args': 'object.pk', 'famfam': 'transmit_delete', 'permissions': [PERMISSION_STATE_SETUP_DELETE]} + register_links(Workflow, [setup_workflow_edit_link, setup_workflow_delete_link]) -register_links([Workflow, 'setup_workflow_list', 'setup_workflow_create'], [setup_workflow_list_link], menu_name=u'form_header') +register_links([Workflow, State, 'setup_workflow_list', 'setup_workflow_create', 'setup_state_list'], [setup_workflow_list_link], menu_name=u'form_header') register_links([Workflow, 'setup_workflow_list', 'setup_workflow_create'], [setup_workflow_create_link], menu_name=u'secondary_menu') -#register_multi_item_links(['user_list'], [user_multiple_set_password, user_multiple_delete]) + +register_links(State, [setup_state_edit_link, setup_state_delete_link]) +register_links([State, Workflow, 'setup_state_list', 'setup_workflow_list', 'setup_workflow_create'], [setup_state_list_link], menu_name=u'form_header') +register_links([State, 'setup_state_list', 'setup_state_create'], [setup_state_create_link], menu_name=u'secondary_menu') + register_setup(setup_workflow_link) diff --git a/apps/workflows/forms.py b/apps/workflows/forms.py index 800affbb35..fd425d4883 100644 --- a/apps/workflows/forms.py +++ b/apps/workflows/forms.py @@ -3,9 +3,14 @@ from __future__ import absolute_import from django import forms from django.utils.translation import ugettext_lazy as _ -from .models import Workflow +from .models import Workflow, State, Transition class WorkflowSetupForm(forms.ModelForm): class Meta: model = Workflow + + +class StateSetupForm(forms.ModelForm): + class Meta: + model = State diff --git a/apps/workflows/permissions.py b/apps/workflows/permissions.py index 89003b2e84..dcce9281bd 100644 --- a/apps/workflows/permissions.py +++ b/apps/workflows/permissions.py @@ -4,9 +4,15 @@ from django.utils.translation import ugettext_lazy as _ from permissions.models import PermissionNamespace, Permission -user_management_namespace = PermissionNamespace('workflows', _(u'Workflows')) +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_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_WORKFLOW_SETUP_VIEW = Permission.objects.register(user_management_namespace, 'workflow_setup_view', _(u'View existing workflow templates')) -PERMISSION_WORKFLOW_SETUP_CREATE = Permission.objects.register(user_management_namespace, 'workflow_setup_create', _(u'Create new workflow templates')) -PERMISSION_WORKFLOW_SETUP_EDIT = Permission.objects.register(user_management_namespace, 'workflow_setup_edit', _(u'Edit existing workflow templates')) -PERMISSION_WORKFLOW_SETUP_DELETE = Permission.objects.register(user_management_namespace, 'workflow_setup_delete', _(u'Delete existing workflow templates')) 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 0000000000000000000000000000000000000000..f34531ca7867129faaa58ff379592de2047c00d5 GIT binary patch literal 2575 zcmV+q3h?!bP)a_kHi}IlFh`8Ugjr{Ihre|3ByZ{_~&LW#C&rdmo;XJGD@^ zTFWsjSq5g&9Lur5X*ozl5~)410*!G=+3j-2cHFhCE%3$}K>@8!n<8hl6FCmVp-~ua^FTB%ZJ+sU(^}jneHQ{6 z*QQzBCaZD6gz6$t5ZK%8gTPP_27}3lmZ8Y;&)Y*yJeL+vN(wBRY^tp;HY}Ww%g?bC z=Yp-=3Jek%Y#D}-PaK@Op|KpdCcX^;P3x~~yNVpP5=*HCgdqVu7e?Sjhw!KSc6RK- z^$-pLM>OkH91cAWGY-=`^;Hips50MguPgv_u^9q=0T}M|4orKdsbV|{=4;^3)%Fxs z3m;0>cA>`=LK~J#xG=)Mhtpgijuuy1}etZ{`@LRLN2zDN3IZlMgO^)wRhZ zB+LsPrYYNhSh2OJ#9UZ7r2qm0K^X4x4^7+HRF+L5n*euuL(Q9og~s{`QwzY|;RDZ5 z$W!~A^ZU3q*s!7I>AW0nwYeY%Og0nfjGC`7kBJEgc|#zKpc96r9dkB0x8U@Irj0fG z?8PQ~VU-mIT_fOji#xB})-iLQ zzQk5x!PsL!^okG(#zB$NH^6Wl7;?2>v>8*e=(5L95g)3t9gLJ%e%j6^i0o4>=4P44$?(BNjG5-7GaVM z5#ZHGMh8^DIS@Wdj;-a{5}sEe9+BW=xA;EJ`Lp7eR}=*Tf&e_$1bR>FNj7|e3GbpFS16NC^}L>`o{ zmKypOO)5&ijC*h+Flx!jHE>bFAiZh=VAzb5j4`bs7|Sq9hJdWbxk1B96$Z^;-a-zJoalzAf!J?> z-qyq!!X^TV4sZ0cWFo}{Nl0+?shK~en8&znRbxLBewy;~^1t4;{5EhlH-kSA0Dn+` z;azV)+44Ie@!0{8hWmll>w(p3fJOgE4SL5p+1-zOK8DKW%OKRKm@@?8Kib*x9(h7I zqz5qyzPcBh-&7k8AuIgY`qgWmShQ$SjezkV3&-qQQjgW7*L9){Y3`Gv! zIfO+VA$5qUIa-rCTftgjfjk{oM;7H(0KqjJea~UjEuXRR>@xf>swN+M=FXj8;BZuK zsjR4g-u`|#ed;tE{QH5&C5Dk#nfN_SZ)d74vg|)|*)BJ5`&?jpJ2H8I=T)H4Pu}g? zf{nyWRDvmQkBfUv-8FT4=gpf3Lv9Z=HaWrNYTe!DYCTR)sa)ki2|vcW{u|ry)E?Zc zrXYsN>gf!sQ%1*SJ?01Z-go=;*I&PH=FA!39q~hZdmC_=fGBY!w0gMq51V1m>>BJv zWRRl~Y+{ozK0Oi?L;j#QU6^n%r91xcq**9PV5?Jt8QD0O>B0}xC~4cQ&hCBF?Ge&o^Dr{l>r zS}hztbQt>a{#h~~lh!JsCG4^RjDv2l6&K+twJA$n!~khIe7XlcaL_&a+p&)5QXegM z-*fNPc6(v{q|!;y*Vjkjkw5O-e&h+%60NN*Yc}sYp}~;kc5({lBtu^pnmbB zvl-fh;)lQQ9QY3|MJ`7`XSEg_nSJH#RKhuS^cb8yb9x=lyDoBFx(Ci)cxLw;o=rA3 zEt_0k1~v@Kw2xCRPJ-9#h4!uDvGEq5&|TTk_Vfc~g$I_$r6+AIu8QpMhLNPy_~D>$+nyfx=c*10b>(v3hWR)u z)!$U7qo!ry5+9pH0{e2Xsl%A5HCayXRZlLC|1P-Lqg9n?)LcQ~8M)L)X4YY~YDjCc l^ebv;N7TcN9pL{03;\d+)/edit/$', 'setup_workflow_edit', (), 'setup_workflow_edit'), url(r'^setup/workflow/(?P\d+)/delete/$', 'setup_workflow_delete', (), 'setup_workflow_delete'), + + 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'), ) diff --git a/apps/workflows/views.py b/apps/workflows/views.py index cb4d373874..1db556df9e 100644 --- a/apps/workflows/views.py +++ b/apps/workflows/views.py @@ -18,11 +18,13 @@ from common.utils import encapsulate #from common.widgets import two_state_template #from acls.models import AccessEntry -from .models import Workflow -from .forms import WorkflowSetupForm +from .models import Workflow, State, Transition +from .forms import WorkflowSetupForm, StateSetupForm from .permissions import (PERMISSION_WORKFLOW_SETUP_VIEW, PERMISSION_WORKFLOW_SETUP_CREATE, PERMISSION_WORKFLOW_SETUP_EDIT, - PERMISSION_WORKFLOW_SETUP_DELETE) + PERMISSION_WORKFLOW_SETUP_DELETE, PERMISSION_STATE_SETUP_VIEW, + PERMISSION_STATE_SETUP_CREATE, PERMISSION_STATE_SETUP_EDIT, + PERMISSION_STATE_SETUP_DELETE) logger = logging.getLogger(__name__) @@ -139,3 +141,114 @@ def setup_workflow_delete(request, workflow_pk=None, workflow_pk_list=None): return render_to_response('generic_confirm.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, + #'list_object_variable_name': 'source', + #'source_type': source_type, + #'extra_columns': [ + # {'name': _(u'Initial state'), 'attribute': encapsulate(lambda workflow: workflow.initial_state or _(u'None'))}, + #], + } + + 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)) From a3822a1836137f5bf94e33e8ca8a56f2270d11e2 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 16 Mar 2012 02:06:24 -0400 Subject: [PATCH 05/52] Add workflow states list view --- apps/workflows/__init__.py | 3 ++- apps/workflows/models.py | 4 ++-- apps/workflows/urls.py | 1 + apps/workflows/views.py | 19 ++++++++++++++++--- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/apps/workflows/__init__.py b/apps/workflows/__init__.py index 4521dc5142..83d2e6dfe3 100644 --- a/apps/workflows/__init__.py +++ b/apps/workflows/__init__.py @@ -18,13 +18,14 @@ setup_workflow_list_link = {'text': _(u'workflow list'), 'view': 'setup_workflow setup_workflow_create_link = {'text': _(u'create new'), 'view': 'setup_workflow_create', 'famfam': 'chart_organisation_add', 'permissions': [PERMISSION_WORKFLOW_SETUP_CREATE]} setup_workflow_edit_link = {'text': _(u'edit'), 'view': 'setup_workflow_edit', 'args': 'object.pk', 'famfam': 'chart_organisation', 'permissions': [PERMISSION_WORKFLOW_SETUP_EDIT]} setup_workflow_delete_link = {'text': _(u'delete'), 'view': 'setup_workflow_delete', 'args': 'object.pk', 'famfam': 'chart_organisation_delete', 'permissions': [PERMISSION_WORKFLOW_SETUP_DELETE]} +setup_workflow_states_list_link = {'text': _(u'states'), 'view': 'setup_workflow_states_list', 'args': 'object.pk', 'famfam': 'transmit_go', 'permissions': [PERMISSION_WORKFLOW_SETUP_EDIT]} setup_state_list_link = {'text': _(u'state list'), 'view': 'setup_state_list', 'famfam': 'transmit', 'permissions': [PERMISSION_STATE_SETUP_VIEW]} setup_state_create_link = {'text': _(u'create new'), 'view': 'setup_state_create', 'famfam': 'transmit_add', 'permissions': [PERMISSION_STATE_SETUP_CREATE]} setup_state_edit_link = {'text': _(u'edit'), 'view': 'setup_state_edit', 'args': 'object.pk', 'famfam': 'transmit_edit', 'permissions': [PERMISSION_STATE_SETUP_EDIT]} setup_state_delete_link = {'text': _(u'delete'), 'view': 'setup_state_delete', 'args': 'object.pk', 'famfam': 'transmit_delete', 'permissions': [PERMISSION_STATE_SETUP_DELETE]} -register_links(Workflow, [setup_workflow_edit_link, setup_workflow_delete_link]) +register_links(Workflow, [setup_workflow_states_list_link, setup_workflow_edit_link, setup_workflow_delete_link]) register_links([Workflow, State, 'setup_workflow_list', 'setup_workflow_create', 'setup_state_list'], [setup_workflow_list_link], menu_name=u'form_header') register_links([Workflow, 'setup_workflow_list', 'setup_workflow_create'], [setup_workflow_create_link], menu_name=u'secondary_menu') diff --git a/apps/workflows/models.py b/apps/workflows/models.py index 6824cd61d9..0359519553 100644 --- a/apps/workflows/models.py +++ b/apps/workflows/models.py @@ -62,8 +62,8 @@ class Transition(models.Model): class WorkflowState(models.Model): - workflow = models.ForeignKey(Workflow, related_name='workflow_state_workflow', verbose_name=_(u'workflow')) - state = models.ForeignKey(State, related_name='workflow_state_state', verbose_name=_(u'state')) + 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): diff --git a/apps/workflows/urls.py b/apps/workflows/urls.py index 78f0a1f229..7223c08e5d 100644 --- a/apps/workflows/urls.py +++ b/apps/workflows/urls.py @@ -5,6 +5,7 @@ urlpatterns = patterns('workflows.views', 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/state/list/$', 'setup_state_list', (), 'setup_state_list'), url(r'^setup/state/create/$', 'setup_state_create', (), 'setup_state_create'), diff --git a/apps/workflows/views.py b/apps/workflows/views.py index 1db556df9e..242de0206a 100644 --- a/apps/workflows/views.py +++ b/apps/workflows/views.py @@ -38,8 +38,6 @@ def setup_workflow_list(request): 'object_list': Workflow.objects.all(), 'title': _(u'workflows'), 'hide_link': True, - #'list_object_variable_name': 'source', - #'source_type': source_type, 'extra_columns': [ {'name': _(u'Initial state'), 'attribute': encapsulate(lambda workflow: workflow.initial_state or _(u'None'))}, ], @@ -52,7 +50,6 @@ def setup_workflow_list(request): def setup_workflow_create(request): Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_CREATE]) redirect_url = reverse('setup_workflow_list') - #previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', redirect_url))) if request.method == 'POST': form = WorkflowSetupForm(request.POST) @@ -142,6 +139,22 @@ def setup_workflow_delete(request, workflow_pk=None, workflow_pk_list=None): 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'workflows'), + 'hide_link': True, + 'object': workflow, + } + + 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]) From e2e9c074b79758340adc725a74d5f882dfd7072f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 16 Mar 2012 10:30:04 -0400 Subject: [PATCH 06/52] Add workflow state add and edit views --- apps/workflows/__init__.py | 16 +++++---- apps/workflows/forms.py | 7 +++- apps/workflows/urls.py | 2 ++ apps/workflows/views.py | 74 +++++++++++++++++++++++++++++++++----- 4 files changed, 84 insertions(+), 15 deletions(-) diff --git a/apps/workflows/__init__.py b/apps/workflows/__init__.py index 83d2e6dfe3..8474e43709 100644 --- a/apps/workflows/__init__.py +++ b/apps/workflows/__init__.py @@ -10,28 +10,32 @@ from .permissions import (PERMISSION_WORKFLOW_SETUP_VIEW, 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, Transition +from .models import Workflow, State, Transition, WorkflowState setup_workflow_link = {'text': _(u'workflows'), 'view': 'setup_workflow_list', 'icon': 'chart_organisation.png', 'permissions': [PERMISSION_WORKFLOW_SETUP_VIEW]} setup_workflow_list_link = {'text': _(u'workflow list'), 'view': 'setup_workflow_list', 'famfam': 'chart_organisation', 'permissions': [PERMISSION_WORKFLOW_SETUP_VIEW]} -setup_workflow_create_link = {'text': _(u'create new'), 'view': 'setup_workflow_create', 'famfam': 'chart_organisation_add', 'permissions': [PERMISSION_WORKFLOW_SETUP_CREATE]} -setup_workflow_edit_link = {'text': _(u'edit'), 'view': 'setup_workflow_edit', 'args': 'object.pk', 'famfam': 'chart_organisation', 'permissions': [PERMISSION_WORKFLOW_SETUP_EDIT]} -setup_workflow_delete_link = {'text': _(u'delete'), 'view': 'setup_workflow_delete', 'args': 'object.pk', 'famfam': 'chart_organisation_delete', 'permissions': [PERMISSION_WORKFLOW_SETUP_DELETE]} -setup_workflow_states_list_link = {'text': _(u'states'), 'view': 'setup_workflow_states_list', 'args': 'object.pk', 'famfam': 'transmit_go', 'permissions': [PERMISSION_WORKFLOW_SETUP_EDIT]} +setup_workflow_create_link = {'text': _(u'create new workflow'), 'view': 'setup_workflow_create', 'famfam': 'chart_organisation_add', 'permissions': [PERMISSION_WORKFLOW_SETUP_CREATE]} +setup_workflow_edit_link = {'text': _(u'edit'), 'view': 'setup_workflow_edit', 'args': 'workflow.pk', 'famfam': 'chart_organisation', 'permissions': [PERMISSION_WORKFLOW_SETUP_EDIT]} +setup_workflow_delete_link = {'text': _(u'delete'), 'view': 'setup_workflow_delete', 'args': 'workflow.pk', 'famfam': 'chart_organisation_delete', 'permissions': [PERMISSION_WORKFLOW_SETUP_DELETE]} +setup_workflow_states_list_link = {'text': _(u'states'), 'view': 'setup_workflow_states_list', 'args': 'workflow.pk', 'famfam': 'transmit_go', 'permissions': [PERMISSION_WORKFLOW_SETUP_EDIT]} +setup_workflow_states_add_link = {'text': _(u'add state'), 'view': 'setup_workflow_state_add', 'args': 'workflow.pk', 'famfam': 'transmit_add', 'permissions': [PERMISSION_WORKFLOW_SETUP_EDIT]} +setup_workflow_states_edit_link = {'text': _(u'edit state'), 'view': 'setup_workflow_state_edit', 'args': 'workflow_state.pk', 'famfam': 'transmit_edit', 'permissions': [PERMISSION_WORKFLOW_SETUP_EDIT]} setup_state_list_link = {'text': _(u'state list'), 'view': 'setup_state_list', 'famfam': 'transmit', 'permissions': [PERMISSION_STATE_SETUP_VIEW]} -setup_state_create_link = {'text': _(u'create new'), 'view': 'setup_state_create', 'famfam': 'transmit_add', 'permissions': [PERMISSION_STATE_SETUP_CREATE]} +setup_state_create_link = {'text': _(u'create new state'), 'view': 'setup_state_create', 'famfam': 'transmit_add', 'permissions': [PERMISSION_STATE_SETUP_CREATE]} setup_state_edit_link = {'text': _(u'edit'), 'view': 'setup_state_edit', 'args': 'object.pk', 'famfam': 'transmit_edit', 'permissions': [PERMISSION_STATE_SETUP_EDIT]} setup_state_delete_link = {'text': _(u'delete'), 'view': 'setup_state_delete', 'args': 'object.pk', 'famfam': 'transmit_delete', 'permissions': [PERMISSION_STATE_SETUP_DELETE]} register_links(Workflow, [setup_workflow_states_list_link, setup_workflow_edit_link, setup_workflow_delete_link]) register_links([Workflow, State, 'setup_workflow_list', 'setup_workflow_create', 'setup_state_list'], [setup_workflow_list_link], menu_name=u'form_header') register_links([Workflow, 'setup_workflow_list', 'setup_workflow_create'], [setup_workflow_create_link], menu_name=u'secondary_menu') +register_links(['setup_workflow_states_list', 'setup_workflow_states_add'], [setup_workflow_states_add_link], menu_name=u'sidebar') register_links(State, [setup_state_edit_link, setup_state_delete_link]) register_links([State, Workflow, 'setup_state_list', 'setup_workflow_list', 'setup_workflow_create'], [setup_state_list_link], menu_name=u'form_header') register_links([State, 'setup_state_list', 'setup_state_create'], [setup_state_create_link], menu_name=u'secondary_menu') +register_links([WorkflowState], [setup_workflow_states_edit_link]) register_setup(setup_workflow_link) diff --git a/apps/workflows/forms.py b/apps/workflows/forms.py index fd425d4883..b50a3b7cfd 100644 --- a/apps/workflows/forms.py +++ b/apps/workflows/forms.py @@ -3,7 +3,7 @@ from __future__ import absolute_import from django import forms from django.utils.translation import ugettext_lazy as _ -from .models import Workflow, State, Transition +from .models import Workflow, State, Transition, WorkflowState class WorkflowSetupForm(forms.ModelForm): @@ -14,3 +14,8 @@ class WorkflowSetupForm(forms.ModelForm): class StateSetupForm(forms.ModelForm): class Meta: model = State + + +class WorkflowStateSetupForm(forms.ModelForm): + class Meta: + model = WorkflowState diff --git a/apps/workflows/urls.py b/apps/workflows/urls.py index 7223c08e5d..3a9b79557f 100644 --- a/apps/workflows/urls.py +++ b/apps/workflows/urls.py @@ -6,6 +6,8 @@ urlpatterns = patterns('workflows.views', 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/create/$', '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/state/list/$', 'setup_state_list', (), 'setup_state_list'), url(r'^setup/state/create/$', 'setup_state_create', (), 'setup_state_create'), diff --git a/apps/workflows/views.py b/apps/workflows/views.py index 242de0206a..ceb7bef219 100644 --- a/apps/workflows/views.py +++ b/apps/workflows/views.py @@ -18,8 +18,8 @@ from common.utils import encapsulate #from common.widgets import two_state_template #from acls.models import AccessEntry -from .models import Workflow, State, Transition -from .forms import WorkflowSetupForm, StateSetupForm +from .models import Workflow, State, Transition, WorkflowState +from .forms import WorkflowSetupForm, StateSetupForm, WorkflowStateSetupForm from .permissions import (PERMISSION_WORKFLOW_SETUP_VIEW, PERMISSION_WORKFLOW_SETUP_CREATE, PERMISSION_WORKFLOW_SETUP_EDIT, PERMISSION_WORKFLOW_SETUP_DELETE, PERMISSION_STATE_SETUP_VIEW, @@ -41,6 +41,7 @@ def setup_workflow_list(request): '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, @@ -83,8 +84,10 @@ def setup_workflow_edit(request, workflow_pk): return render_to_response('generic_form.html', { 'title': _(u'edit workflow: %s') % workflow, 'form': form, - 'object': workflow, - 'object_name': _(u'workflow'), + 'workflow': workflow, + 'navigation_object_list': [ + {'object': 'workflow', 'name': _(u'workflow')}, + ], }, context_instance=RequestContext(request)) @@ -122,14 +125,16 @@ def setup_workflow_delete(request, workflow_pk=None, workflow_pk_list=None): return HttpResponseRedirect(next) context = { - 'object_name': _(u'workflow'), '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['object'] = workflows[0] + 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: @@ -146,15 +151,68 @@ def setup_workflow_states_list(request, workflow_pk): context = { 'object_list': workflow.workflowstate_set.all(), - 'title': _(u'workflows'), + 'title': _(u'states for workflow: %s') % workflow, 'hide_link': True, - 'object': workflow, + '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(request.POST) + if form.is_valid(): + state = form.save() + messages.success(request, _(u'worflow state created succesfully.')) + return HttpResponseRedirect(redirect_url) + else: + form = WorkflowStateSetupForm() + + 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(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(instance=workflow_state) + + return render_to_response('generic_form.html', { + 'title': _(u'edit worflow 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)) + # States def setup_state_list(request): Permission.objects.check_permissions(request.user, [PERMISSION_STATE_SETUP_VIEW]) From 4a3cdc3a5cea898b01ff49136d88304da3ad49f1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 16 Mar 2012 11:05:21 -0400 Subject: [PATCH 07/52] Avoid sidebar links from repeating --- apps/main/templates/base.html | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/main/templates/base.html b/apps/main/templates/base.html index 86fa6495d1..61efe93fca 100644 --- a/apps/main/templates/base.html +++ b/apps/main/templates/base.html @@ -299,7 +299,7 @@ {% endif %} {% get_object_navigation_links "secondary_menu" as object_navigation_links %} - {% if object_navigation_links %} + {% if object_navigation_links %}

{% trans "Secondary menu" %}

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

{% trans "Other available actions" %}

- -
- {% endif %} +
+

{% trans "Other available actions" %}

+ +
+ {% endif %} + {% endif %} {% get_sidebar_templates as sidebar_templates %} {% for template in sidebar_templates %} From d028f54c27bc4856ec48003ddf209af5f7e7017f Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 16 Mar 2012 12:56:49 -0400 Subject: [PATCH 08/52] Started navigation refatoring --- apps/acls/__init__.py | 36 +-- apps/common/__init__.py | 6 +- apps/django_gpg/__init__.py | 10 +- apps/document_acls/__init__.py | 4 +- apps/document_comments/__init__.py | 8 +- apps/document_indexing/__init__.py | 12 +- apps/documents/__init__.py | 144 ++++++------ apps/dynamic_search/__init__.py | 6 +- apps/feedback/__init__.py | 6 +- apps/folders/__init__.py | 10 +- apps/linking/__init__.py | 12 +- apps/main/__init__.py | 2 +- apps/metadata/__init__.py | 50 ++-- apps/navigation/api.py | 213 ++++++++++++++++-- .../templatetags/navigation_tags.py | 124 ++-------- apps/navigation/utils.py | 83 ++++++- apps/ocr/__init__.py | 12 +- apps/permissions/__init__.py | 23 +- apps/project_setup/api.py | 4 +- apps/sources/__init__.py | 38 ++-- apps/tags/__init__.py | 10 +- apps/user_management/__init__.py | 10 +- apps/workflows/__init__.py | 25 +- 23 files changed, 500 insertions(+), 348 deletions(-) diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index 7a83009b39..b87234b2a2 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,29 @@ 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') 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') +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') -register_links(ClassAccessHolder, [acl_class_acl_detail]) +bind_links([ClassAccessHolder], [acl_class_acl_detail]) -register_links(AccessObjectClass, [acl_class_acl_list, acl_class_new_holder_for]) +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]) diff --git a/apps/common/__init__.py b/apps/common/__init__.py index bc663d91d9..dfcd4066cd 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 from .conf import settings as common_settings from .utils import validate_path @@ -21,12 +21,12 @@ password_change_view = {'text': _(u'change password'), 'view': 'password_change_ 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'} -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(['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') +bind_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) diff --git a/apps/django_gpg/__init__.py b/apps/django_gpg/__init__.py index a49c0f26b9..f931c9c914 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 from project_setup.api import register_setup from hkp import Key as KeyServerKey @@ -18,10 +18,10 @@ key_query = {'text': _(u'query keyservers'), 'view': 'key_query', 'famfam': 'zoo 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_']} -#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..9c391380dc 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 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]} -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_comments/__init__.py b/apps/document_comments/__init__.py index 2356f36885..b0e30526dd 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 from common.utils import encapsulate from acls.api import class_permissions from documents.models import Document @@ -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..3111fe4412 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) from main.api import register_maintenance_links from documents.permissions import PERMISSION_DOCUMENT_VIEW @@ -58,17 +58,17 @@ register_maintenance_links([rebuild_index_instances], namespace='document_indexi register_sidebar_template(['index_instance_list'], 'indexing_help.html') -register_links(IndexInstanceNode, [index_parent]) +bind_links(IndexInstanceNode, [index_parent]) -register_links(Document, [document_index_list], menu_name='form_header') +bind_links(Document, [document_index_list], menu_name='form_header') register_setup(index_setup) -register_links([Index, 'index_setup_list', 'index_setup_create', 'template_node_edit', 'template_node_delete'], [index_setup_list, index_setup_create], menu_name='secondary_menu') +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') -register_links(Index, [index_setup_edit, index_setup_delete, index_setup_view]) +bind_links(Index, [index_setup_edit, index_setup_delete, index_setup_view]) -register_links(IndexTemplateNode, [template_node_create, template_node_edit, template_node_delete]) +bind_links(IndexTemplateNode, [template_node_create, template_node_edit, template_node_delete]) def delete_indexes_handler(sender, instance, **kwargs): diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index d3873ad600..7ef10fecfb 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,106 @@ 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.id'], 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'] +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') -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) @@ -188,10 +188,10 @@ register_top_menu( 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/dynamic_search/__init__.py b/apps/dynamic_search/__init__.py index 2d3d73c5f4..7bc581ee8d 100644 --- a/apps/dynamic_search/__init__.py +++ b/apps/dynamic_search/__init__.py @@ -1,6 +1,6 @@ from django.utils.translation import ugettext_lazy as _ -from navigation.api import register_sidebar_template, register_links +from navigation.api import register_sidebar_template, bind_links, Link search = {'text': _(u'search'), 'view': 'search', 'famfam': 'zoom'} search_advanced = {'text': _(u'advanced search'), 'view': 'search_advanced', 'famfam': 'zoom_in'} @@ -8,7 +8,7 @@ search_again = {'text': _(u'search again'), 'view': 'search_again', 'famfam': 'a register_sidebar_template(['search', 'search_advanced'], 'search_help.html') -register_links(['search', 'search_advanced', 'results'], [search, search_advanced], menu_name='form_header') -register_links(['results'], [search_again], menu_name='sidebar') +bind_links(['search', 'search_advanced', 'results'], [search, search_advanced], menu_name='form_header') +bind_links(['results'], [search_again], menu_name='sidebar') register_sidebar_template(['search', 'search_advanced', 'results'], 'recent_searches.html') diff --git a/apps/feedback/__init__.py b/apps/feedback/__init__.py index 8e6c005ae4..272dcb8601 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 from common import about_view, license_view form_view = {'text': _('Feedback'), 'view': 'form_view', 'famfam': '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..93bac9f808 100644 --- a/apps/folders/__init__.py +++ b/apps/folders/__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_top_menu, +from navigation.api import (bind_links, register_top_menu, register_multi_item_links, register_sidebar_template) from documents.models import Document from documents.permissions import PERMISSION_DOCUMENT_VIEW @@ -28,17 +28,17 @@ folder_acl_list = {'text': _(u'ACLs'), 'view': 'folder_acl_list', 'args': 'objec 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_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/linking/__init__.py b/apps/linking/__init__.py index b6608ca829..f8f45eb258 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 from project_setup.api import register_setup from documents.permissions import PERMISSION_DOCUMENT_VIEW from documents.models import Document @@ -30,13 +30,13 @@ smart_link_condition_delete = {'text': _(u'delete'), 'view': 'smart_link_conditi smart_link_acl_list = {'text': _(u'ACLs'), 'view': 'smart_link_acl_list', 'args': 'object.pk', 'famfam': '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/main/__init__.py b/apps/main/__init__.py index e057b7b219..34ab61d3e9 100644 --- a/apps/main/__init__.py +++ b/apps/main/__init__.py @@ -4,7 +4,7 @@ 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 from project_setup.api import register_setup from project_tools.api import register_tool 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/api.py b/apps/navigation/api.py index 56bb037245..bce7e4b865 100644 --- a/apps/navigation/api.py +++ b/apps/navigation/api.py @@ -1,9 +1,146 @@ +from __future__ import absolute_import + +from django.template import (TemplateSyntaxError, Library, + VariableDoesNotExist, Node, Variable) + +from common.utils import urlquote + +from .utils import (resolve_to_name, resolve_arguments, + resolve_template_variable, get_navigation_objects) + object_navigation = {} multi_object_navigation = {} model_list_columns = {} sidebar_templates = {} top_menu_entries = [] +link_binding = {} + + +class ResolvedLink(object): + active = False + + +class Link(object): + def __init__(self, text, view, args=None, kwargs=None, sprite=None, icon=None, permissions=None, condition=None): + 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 + + def resolve(self, context): + 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) + + # Check to see if link has conditional display + if self.condition: + condition_result = self.condition(context) + else: + condition_result = True + + if condition_result: + #new_link = {}#copy.copy(link) + resolved_link = ResolvedLink() + 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 + resolved_link.active = link['view'] == current_view + + try: + if kwargs: + #new_link['url'] = reverse(link['view'], kwargs=kwargs) + resolved_link.url = reverse(link['view'], kwargs=kwargs) + else: +# new_link['url'] = reverse(link['view'], args=args) + resolved_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) + resolved_link.url = urlquote(new_link['url'], parsed_query_string) + except NoReverseMatch, exc: + #new_link['url'] = '#' + resolved_link.url = '#' + #new_link['error'] = err + resolved_link.error = exc + elif 'url' in link: + if not link.get('dont_mark_active', False): + #new_link['active'] = link['url'] == current_path + resolved_link.url.active = link['url'] == current_path + + if kwargs: + #new_link['url'] = link['url'] % kwargs + resolved_link.url = link['url'] % kwargs + else: + #new_link['url'] = link['url'] % args + resolved_link.url = link['url'] % args + if link.get('keep_query', False): + #new_link['url'] = urlquote(new_link['url'], parsed_query_string) + resolved_link.url = urlquote(new_link['url'], parsed_query_string) + else: + #new_link['active'] = False + resolved_link.active = False + + if 'conditional_highlight' in link: + #new_link['active'] = link['conditional_highlight'](context) + resolved_link.active = link['conditional_highlight'](context) + + if 'conditional_disable' in link: + #new_link['disabled'] = link['conditional_disable'](context) + resolved_link.disabled = link['conditional_disable'](context) + else: + #new_link['disabled'] = False + resolved_link.disabled = False + + if current_view in link.get('children_views', []): + #new_link['active'] = True + resolved_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 + # resolved_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 + # resolved_link.active = True + + for cls in link.get('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 + #context_links.append(new_link) + + +def bind_links(sources, links, menu_name=None): + """ + 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_multi_item_links(src, links, menu_name=None): """ @@ -21,29 +158,6 @@ def register_multi_item_links(src, links, menu_name=None): multi_object_navigation[menu_name][src]['links'].extend(links) -def register_links(src, links, menu_name=None, position=None): - """ - Associate a link to a model a view, or an url - """ - - 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) - else: - object_navigation[menu_name][src]['links'].extend(links) - - def register_top_menu(name, link, children_views=None, children_path_regex=None, children_view_regex=None, position=None): @@ -91,3 +205,56 @@ def register_sidebar_template(source_list, template_name): for source in source_list: sidebar_templates.setdefault(source, []) sidebar_templates[source].append(template_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 + + for resolved_object in get_navigation_objects(context): + try: + links = links_dict[menu_name][type(resolved_object['object'])]['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 diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index d4533c09a3..633f76c3c5 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -4,11 +4,11 @@ import copy import re import urlparse import urllib +import logging from django.core.urlresolvers import reverse, NoReverseMatch from django.template import (TemplateSyntaxError, Library, VariableDoesNotExist, Node, Variable) -from django.utils.text import unescape_string_literal from django.utils.translation import ugettext as _ from django.utils.encoding import smart_str, force_unicode, smart_unicode @@ -17,9 +17,11 @@ from common.utils import urlquote from ..api import (object_navigation, multi_object_navigation, top_menu_entries, sidebar_templates) from ..forms import MultiItemForm -from ..utils import resolve_to_name +from ..utils import (resolve_to_name, resolve_arguments, resolve_template_variable, + get_navigation_objects, get_object_navigation_links) register = Library() +logger = logging.getLogger(__name__) class TopMenuNavigationNode(Node): @@ -51,28 +53,7 @@ class TopMenuNavigationNode(Node): 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 @@ -141,92 +122,14 @@ def resolve_links(context, links, current_view, current_path, parsed_query_strin 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 + 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 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'): @@ -236,9 +139,10 @@ class GetNavigationLinks(Node): 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_object_navigation_links(context, menu_name, links_dict=self.links_dict) + object_list = get_navigation_objects(context) + if object_list: + context['navigation_object'] = object_list[0]['object'] return '' diff --git a/apps/navigation/utils.py b/apps/navigation/utils.py index 6c008e5576..1f72cebd85 100644 --- a/apps/navigation/utils.py +++ b/apps/navigation/utils.py @@ -1,11 +1,89 @@ -#http://www.djangosnippets.org/snippets/1378/ +from __future__ import absolute_import from django.core.urlresolvers import RegexURLResolver, RegexURLPattern, Resolver404, get_resolver +from django.template import (TemplateSyntaxError, Library, + VariableDoesNotExist, Node, Variable) +from django.utils.text import unescape_string_literal -__all__ = ('resolve_to_name',) +#__all__ = ('resolve_to_name',) + +def get_navigation_objects(context): + object_list = [] + + # Try a simple 'object' search first, for lists templates + try: + resolved_object = Variable('object').resolve(context) + except VariableDoesNotExist: + try: + object_name_list = Variable('navigation_object_list').resolve(context) + except VariableDoesNotExist: + try: + object_name_list = [{'object': Variable('navigation_object_name').resolve(context)}] + except VariableDoesNotExist: + #try: + # object_name_list = [{'object': Variable('list_object_variable_name').resolve(context)}] + #except VariableDoesNotExist: + return [] + #object_name_list = [{'object': 'object'}] + #logger.debug('none found, falling back to "object"') + #else: + # logger.debug('found: list_object_variable_name') + else: + logger.debug('found: navigation_object_name') + else: + logger.debug('found: navigation_object_list') + else: + logger.debug('found single object') + return [{'object': resolved_object}]#, 'object_name': 'object'}] + + logger.debug('object_name_list: %s' % object_name_list) + + for object_name in object_name_list: + try: + resolved_object = Variable(object_name['object']).resolve(context) + except VariableDoesNotExist: + resolved_object = None + + object_list.append({'object': resolved_object})#, 'object_name': 'qwe'}) + + logger.debug('object_list: %s' % object_list) + return object_list +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: @@ -40,6 +118,5 @@ def _resolver_resolve_to_name(self, path): RegexURLPattern.resolve_to_name = _pattern_resolve_to_name RegexURLResolver.resolve_to_name = _resolver_resolve_to_name - def resolve_to_name(path, urlconf=None): return get_resolver(urlconf).resolve_to_name(path) diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py index 3a3b0ac7c9..ac29a340f9 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 from documents.models import Document, DocumentVersion from main.api import register_maintenance_links from project_tools.api import register_tool @@ -49,16 +49,16 @@ setup_queue_transformation_create = {'text': _(u'add transformation'), 'view': ' 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'} -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/project_setup/api.py b/apps/project_setup/api.py index 1d11179701..a03c89cb3e 100644 --- a/apps/project_setup/api.py +++ b/apps/project_setup/api.py @@ -9,5 +9,5 @@ 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', [])) + #setup_link.setdefault('children_view_regex', []) + #setup_link['children_view_regex'].extend(link.get('children_view_regex', [])) diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index aad255b28d..acfa2708b4 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__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, register_model_list_columns) from common.utils import encapsulate from project_setup.api import register_setup @@ -44,34 +44,34 @@ source_list = {'text': _(u'Document sources'), 'view': 'setup_web_form_list', 'f upload_version = {'text': _(u'upload new version'), 'view': 'upload_version', 'args': 'object.pk', 'famfam': '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/tags/__init__.py b/apps/tags/__init__.py index 2bfcb2f508..9239b3d765 100644 --- a/apps/tags/__init__.py +++ b/apps/tags/__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_top_menu, +from navigation.api import (bind_links, register_top_menu, register_model_list_columns, register_multi_item_links) from common.utils import encapsulate from documents.models import Document @@ -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') +bind_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)']) -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..71277535c0 100644 --- a/apps/user_management/__init__.py +++ b/apps/user_management/__init__.py @@ -3,7 +3,7 @@ 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 from project_setup.api import register_setup from .permissions import (PERMISSION_USER_CREATE, PERMISSION_USER_EDIT, @@ -27,12 +27,12 @@ group_delete = {u'text': _('delete'), 'view': 'group_delete', 'args': 'object.id 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]} -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 index 8474e43709..a6f85d3afe 100644 --- a/apps/workflows/__init__.py +++ b/apps/workflows/__init__.py @@ -2,8 +2,9 @@ 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 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, @@ -12,10 +13,10 @@ from .permissions import (PERMISSION_WORKFLOW_SETUP_VIEW, PERMISSION_STATE_SETUP_DELETE) from .models import Workflow, State, Transition, WorkflowState -setup_workflow_link = {'text': _(u'workflows'), 'view': 'setup_workflow_list', 'icon': 'chart_organisation.png', 'permissions': [PERMISSION_WORKFLOW_SETUP_VIEW]} setup_workflow_list_link = {'text': _(u'workflow list'), 'view': 'setup_workflow_list', 'famfam': 'chart_organisation', 'permissions': [PERMISSION_WORKFLOW_SETUP_VIEW]} setup_workflow_create_link = {'text': _(u'create new workflow'), 'view': 'setup_workflow_create', 'famfam': 'chart_organisation_add', 'permissions': [PERMISSION_WORKFLOW_SETUP_CREATE]} +setup_workflow_create_link2 = Link(text=_(u'create new workflow'), view='setup_workflow_create', sprite='chart_organisation_add', permissions=[PERMISSION_WORKFLOW_SETUP_CREATE]) setup_workflow_edit_link = {'text': _(u'edit'), 'view': 'setup_workflow_edit', 'args': 'workflow.pk', 'famfam': 'chart_organisation', 'permissions': [PERMISSION_WORKFLOW_SETUP_EDIT]} setup_workflow_delete_link = {'text': _(u'delete'), 'view': 'setup_workflow_delete', 'args': 'workflow.pk', 'famfam': 'chart_organisation_delete', 'permissions': [PERMISSION_WORKFLOW_SETUP_DELETE]} setup_workflow_states_list_link = {'text': _(u'states'), 'view': 'setup_workflow_states_list', 'args': 'workflow.pk', 'famfam': 'transmit_go', 'permissions': [PERMISSION_WORKFLOW_SETUP_EDIT]} @@ -27,15 +28,17 @@ setup_state_create_link = {'text': _(u'create new state'), 'view': 'setup_state_ setup_state_edit_link = {'text': _(u'edit'), 'view': 'setup_state_edit', 'args': 'object.pk', 'famfam': 'transmit_edit', 'permissions': [PERMISSION_STATE_SETUP_EDIT]} setup_state_delete_link = {'text': _(u'delete'), 'view': 'setup_state_delete', 'args': 'object.pk', 'famfam': 'transmit_delete', 'permissions': [PERMISSION_STATE_SETUP_DELETE]} -register_links(Workflow, [setup_workflow_states_list_link, setup_workflow_edit_link, setup_workflow_delete_link]) -register_links([Workflow, State, 'setup_workflow_list', 'setup_workflow_create', 'setup_state_list'], [setup_workflow_list_link], menu_name=u'form_header') -register_links([Workflow, 'setup_workflow_list', 'setup_workflow_create'], [setup_workflow_create_link], menu_name=u'secondary_menu') -register_links(['setup_workflow_states_list', 'setup_workflow_states_add'], [setup_workflow_states_add_link], menu_name=u'sidebar') +#bind_links(Workflow, [setup_workflow_states_list_link, setup_workflow_edit_link, setup_workflow_delete_link]) +#bind_links([Workflow, State, 'setup_workflow_list', 'setup_workflow_create', 'setup_state_list'], [setup_workflow_list_link], menu_name=u'form_header') +#bind_links([Workflow, 'setup_workflow_list', 'setup_workflow_create'], [setup_workflow_create_link], menu_name=u'secondary_menu') +#bind_links(['setup_workflow_states_list', 'setup_workflow_states_add'], [setup_workflow_states_add_link], menu_name=u'sidebar') -register_links(State, [setup_state_edit_link, setup_state_delete_link]) -register_links([State, Workflow, 'setup_state_list', 'setup_workflow_list', 'setup_workflow_create'], [setup_state_list_link], menu_name=u'form_header') -register_links([State, 'setup_state_list', 'setup_state_create'], [setup_state_create_link], menu_name=u'secondary_menu') +bind_links([Workflow, 'setup_workflow_list', 'setup_workflow_create'], [setup_workflow_create_link2], menu_name=u'secondary_menu') -register_links([WorkflowState], [setup_workflow_states_edit_link]) +#bind_links(State, [setup_state_edit_link, setup_state_delete_link]) +#bind_links([State, Workflow, 'setup_state_list', 'setup_workflow_list', 'setup_workflow_create'], [setup_state_list_link], menu_name=u'form_header') +#bind_links([State, 'setup_state_list', 'setup_state_create'], [setup_state_create_link], menu_name=u'secondary_menu') -register_setup(setup_workflow_link) +#bind_links([WorkflowState], [setup_workflow_states_edit_link]) + +register_setup({'text': _(u'workflows'), 'view': 'setup_workflow_list', 'icon': 'chart_organisation.png', 'permissions': [PERMISSION_WORKFLOW_SETUP_VIEW]}) From 568611927ba8d56d12bdbe6bcdb7fc4a2590ed4d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 16 Mar 2012 16:20:09 -0400 Subject: [PATCH 09/52] Updated all link references to the new class based links --- apps/document_indexing/__init__.py | 46 +++---- apps/documents/__init__.py | 11 +- apps/linking/forms.py | 4 +- apps/main/api.py | 4 +- apps/main/views.py | 2 +- apps/navigation/api.py | 84 ++++++++----- .../templatetags/navigation_tags.py | 116 +++--------------- apps/navigation/widgets.py | 2 +- apps/ocr/__init__.py | 38 +++--- apps/project_tools/api.py | 4 +- apps/sources/__init__.py | 28 ++--- 11 files changed, 137 insertions(+), 202 deletions(-) diff --git a/apps/document_indexing/__init__.py b/apps/document_indexing/__init__.py index 3111fe4412..b27687c221 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, - bind_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={'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') -bind_links(IndexInstanceNode, [index_parent]) - -bind_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) -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]) - def delete_indexes_handler(sender, instance, **kwargs): if isinstance(instance, DocumentVersion): diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index 7ef10fecfb..75701f5623 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -121,7 +121,8 @@ document_type_filename_create = Link(text=_(u'add filename to document type'), v 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 bind_links([DocumentType], [document_type_document_list, document_type_filename_list, document_type_edit, document_type_delete]) @@ -188,10 +189,10 @@ register_top_menu( register_sidebar_template(['document_list_recent'], 'recent_document_list_help.html') register_sidebar_template(['document_type_list'], 'document_types_help.html') -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') +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/linking/forms.py b/apps/linking/forms.py index 16400ece57..8801d0b574 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'), + 'famfam': link.getattr('famfam', u'link'), 'text': capfirst(link['text']), - 'action': reverse(link.get('view'), args=[value['current_document'].pk, value['smart_link_instance'].pk]) + 'action': reverse(link.view, args=[value['current_document'].pk, value['smart_link_instance'].pk]) }) output.append(u'') 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/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/navigation/api.py b/apps/navigation/api.py index bce7e4b865..1f65adb245 100644 --- a/apps/navigation/api.py +++ b/apps/navigation/api.py @@ -1,7 +1,12 @@ from __future__ import absolute_import +import urlparse +import urllib +import logging + from django.template import (TemplateSyntaxError, Library, VariableDoesNotExist, Node, Variable) +from django.utils.encoding import smart_str, force_unicode, smart_unicode from common.utils import urlquote @@ -16,21 +21,28 @@ top_menu_entries = [] link_binding = {} +logger = logging.getLogger(__name__) + class ResolvedLink(object): active = False - class Link(object): - def __init__(self, text, view, args=None, kwargs=None, sprite=None, icon=None, permissions=None, condition=None): + 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): self.text = text self.view = view - self.args = args or [] - self.kwargs = kwargs or {} + 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.children_view_regex = children_view_regex + self.klass = klass + self.keep_query = keep_query def resolve(self, context): request = Variable('request').resolve(context) @@ -52,62 +64,63 @@ class Link(object): #new_link = {}#copy.copy(link) resolved_link = ResolvedLink() try: - args, kwargs = resolve_arguments(context, link.get('args', {})) + #args, kwargs = resolve_arguments(context, self.get('args', {})) + args, kwargs = resolve_arguments(context, self.args) except VariableDoesNotExist: args = [] kwargs = {} - if 'view' in link: - if not link.get('dont_mark_active', False): + if self.view: + if not self.dont_mark_active: #new_link['active'] = link['view'] == current_view - resolved_link.active = link['view'] == current_view + resolved_link.active = self.view == current_view try: if kwargs: #new_link['url'] = reverse(link['view'], kwargs=kwargs) - resolved_link.url = reverse(link['view'], kwargs=kwargs) + resolved_link.url = reverse(self.view, kwargs=kwargs) else: # new_link['url'] = reverse(link['view'], args=args) - resolved_link.url = reverse(link['view'], args=args) - if link.get('keep_query', False): + resolved_link.url = reverse(self.view, args=args) + if self.keep_query: #print 'parsed_query_string', parsed_query_string #new_link['url'] = urlquote(new_link['url'], parsed_query_string) - resolved_link.url = urlquote(new_link['url'], parsed_query_string) + resolved_link.url = urlquote(resolved_link.url, parsed_query_string) except NoReverseMatch, exc: #new_link['url'] = '#' resolved_link.url = '#' #new_link['error'] = err resolved_link.error = exc - elif 'url' in link: - if not link.get('dont_mark_active', False): + elif self.url: + if not self.dont_mark_active: #new_link['active'] = link['url'] == current_path - resolved_link.url.active = link['url'] == current_path + resolved_link.url.active = self.url == current_path if kwargs: #new_link['url'] = link['url'] % kwargs - resolved_link.url = link['url'] % kwargs + resolved_link.url = self.url % kwargs else: #new_link['url'] = link['url'] % args - resolved_link.url = link['url'] % args - if link.get('keep_query', False): + resolved_link.url = self.url % args + if link.keep_query: #new_link['url'] = urlquote(new_link['url'], parsed_query_string) - resolved_link.url = urlquote(new_link['url'], parsed_query_string) + resolved_link.url = urlquote(resolved_link.url, parsed_query_string) else: #new_link['active'] = False resolved_link.active = False - if 'conditional_highlight' in link: + if self.conditional_highlight: #new_link['active'] = link['conditional_highlight'](context) - resolved_link.active = link['conditional_highlight'](context) + resolved_link.active = self.conditional_highlight(context) - if 'conditional_disable' in link: + if self.conditional_disable: #new_link['disabled'] = link['conditional_disable'](context) - resolved_link.disabled = link['conditional_disable'](context) + resolved_link.disabled = self.conditional_disable(context) else: #new_link['disabled'] = False resolved_link.disabled = False - if current_view in link.get('children_views', []): + if current_view in self.children_views: #new_link['active'] = True resolved_link.active = True @@ -121,7 +134,7 @@ class Link(object): # #new_link['active'] = True # resolved_link.active = True - for cls in link.get('children_classes', []): + 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: @@ -132,7 +145,7 @@ class Link(object): #context_links.append(new_link) -def bind_links(sources, links, menu_name=None): +def bind_links(sources, links, menu_name=None, position=0): """ Associate a link to a model, a view, or an url """ @@ -207,7 +220,7 @@ def register_sidebar_template(source_list, template_name): sidebar_templates[source].append(template_name) -def get_object_navigation_links(context, menu_name=None, links_dict=object_navigation): +def get_context_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) @@ -226,9 +239,10 @@ def get_object_navigation_links(context, menu_name=None, links_dict=object_navig 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)] + #navigation_object_links = Variable('overrided_object_links').resolve(context) + return 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 @@ -244,16 +258,18 @@ def get_object_navigation_links(context, menu_name=None, links_dict=object_navig 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) + #for link in resolve_links(context, links, current_view, current_path, parsed_query_string): + # context_links.append(link) + context_links.extend(links) except KeyError: pass for resolved_object in get_navigation_objects(context): try: links = links_dict[menu_name][type(resolved_object['object'])]['links'] - for link in resolve_links(context, links, current_view, current_path, parsed_query_string): - context_links.append(link) + #for link in resolve_links(context, links, current_view, current_path, parsed_query_string): + # context_links.append(link) + context_links.extend(links) except KeyError: pass diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index 633f76c3c5..ebd55723fa 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -15,10 +15,10 @@ 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) + top_menu_entries, sidebar_templates, get_context_object_navigation_links) from ..forms import MultiItemForm from ..utils import (resolve_to_name, resolve_arguments, resolve_template_variable, - get_navigation_objects, get_object_navigation_links) + get_navigation_objects) register = Library() logger = logging.getLogger(__name__) @@ -30,22 +30,23 @@ class TopMenuNavigationNode(Node): 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) + #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 + #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 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 + #for children_view_regex in link.get('children_view_regex', []): + # if re.compile(children_view_regex).match(current_view): + # menu_links[index]['active'] = True + pass - context['menu_links'] = menu_links + context['menu_links'] = []#menu_links return '' @@ -53,83 +54,6 @@ class TopMenuNavigationNode(Node): def get_top_menu_links(parser, token): return TopMenuNavigationNode() -""" -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', []): - 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 - - context_links.append(new_link) - return context_links -""" class GetNavigationLinks(Node): def __init__(self, menu_name=None, links_dict=object_navigation, var_name='object_navigation_links'): @@ -139,7 +63,7 @@ class GetNavigationLinks(Node): 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) + context[self.var_name] = get_context_object_navigation_links(context, menu_name, links_dict=self.links_dict) object_list = get_navigation_objects(context) if object_list: context['navigation_object'] = object_list[0]['object'] @@ -161,10 +85,10 @@ def get_object_navigation_links(parser, token): @register.inclusion_tag('generic_navigation.html', takes_context=True) def object_navigation_template(context): new_context = copy.copy(context) - new_context.update({ - 'horizontal': True, - 'object_navigation_links': _get_object_navigation_links(context) - }) + #new_context.update({ + # 'horizontal': True, + # 'object_navigation_links': get_object_navigation_links(context) + #}) return new_context @@ -183,7 +107,7 @@ def get_multi_item_links(parser, token): def get_multi_item_links_form(context): 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 get_context_object_navigation_links(context, links_dict=multi_object_navigation)]), 'title': _(u'Selected item actions:'), 'form_action': reverse('multi_object_action_view'), 'submit_method': 'get', diff --git a/apps/navigation/widgets.py b/apps/navigation/widgets.py index f587fc6ebb..702b1b0a32 100644 --- a/apps/navigation/widgets.py +++ b/apps/navigation/widgets.py @@ -42,7 +42,7 @@ def render_widget(request, link): link = links[0] return mark_safe(u'' % { 'url': reverse(link['view']) if 'view' in link else link['url'], - 'icon': link.get('icon', 'link_button.png'), + 'icon': link.getattr('icon', 'link_button.png'), 'static_url': settings.STATIC_URL, 'string': capfirst(link['text']), 'image_alt': _(u'icon'), diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py index ac29a340f9..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 bind_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,31 +29,31 @@ 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') -bind_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]) -bind_links(DocumentQueue, [document_queue_disable, document_queue_enable, setup_queue_transformation_list]) -bind_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]) diff --git a/apps/project_tools/api.py b/apps/project_tools/api.py index d8e66ab7d0..a8a20d92ec 100644 --- a/apps/project_tools/api.py +++ b/apps/project_tools/api.py @@ -8,5 +8,5 @@ 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', [])) + #tool_link.setdefault('children_view_regex', []) + #tool_link['children_view_regex'].extend(link.get('children_view_regex', [])) diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index acfa2708b4..b5de48de59 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -44,29 +44,29 @@ source_list = {'text': _(u'Document sources'), 'view': 'setup_web_form_list', 'f upload_version = {'text': _(u'upload new version'), 'view': 'upload_version', 'args': 'object.pk', 'famfam': 'page_add', 'permissions': [PERMISSION_DOCUMENT_NEW_VERSION]} -bind_links(StagingFile, [staging_file_delete]) +bind_links([StagingFile], [staging_file_delete]) -bind_links(SourceTransformation, [setup_source_transformation_edit, setup_source_transformation_delete]) +bind_links([SourceTransformation], [setup_source_transformation_edit, setup_source_transformation_delete]) 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') -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]) +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]) -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]) +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]) -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]) +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]) -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]) +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]) -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]) +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 bind_links(['document_version_list', 'upload_version', 'document_version_revert'], [upload_version], menu_name='sidebar') From 7ccab82fd42118f00d091eebf0b31bdbc7d70e85 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 16 Mar 2012 20:09:35 -0400 Subject: [PATCH 10/52] Convert all remaining apps to the new class based links --- apps/django_gpg/__init__.py | 18 ++++++++-------- apps/document_acls/__init__.py | 6 +++--- apps/document_comments/__init__.py | 14 ++++++------ apps/document_signatures/__init__.py | 14 ++++++------ apps/folders/__init__.py | 24 ++++++++++----------- apps/linking/__init__.py | 32 ++++++++++++++-------------- apps/mailer/__init__.py | 8 +++---- apps/navigation/api.py | 2 +- apps/navigation/widgets.py | 4 ++-- apps/tags/__init__.py | 28 ++++++++++++------------ 10 files changed, 75 insertions(+), 75 deletions(-) diff --git a/apps/django_gpg/__init__.py b/apps/django_gpg/__init__.py index f931c9c914..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 bind_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_']) #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') -bind_links(Key, [key_delete]) -bind_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 9c391380dc..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 bind_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]) -bind_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_comments/__init__.py b/apps/document_comments/__init__.py index b0e30526dd..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 bind_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, [ { @@ -37,8 +37,8 @@ register_model_list_columns(Comment, [ ]) 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') +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_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/folders/__init__.py b/apps/folders/__init__.py index 93bac9f808..06699a5265 100644 --- a/apps/folders/__init__.py +++ b/apps/folders/__init__.py @@ -3,7 +3,7 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ from navigation.api import (bind_links, register_top_menu, - register_multi_item_links, register_sidebar_template) + 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,26 +15,26 @@ 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]) -bind_links(Folder, [folder_view, folder_edit, folder_delete, folder_acl_list]) +bind_links([Folder], [folder_view, folder_edit, folder_delete, folder_acl_list]) 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']) -bind_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') diff --git a/apps/linking/__init__.py b/apps/linking/__init__.py index f8f45eb258..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 bind_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,28 +14,28 @@ 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]) -bind_links(Document, [smart_link_instances_for_document], menu_name='form_header') +bind_links([Document], [smart_link_instances_for_document], menu_name='form_header') -bind_links(SmartLink, [smart_link_edit, smart_link_delete, smart_link_condition_list, smart_link_acl_list]) +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') -bind_links(SmartLinkCondition, [smart_link_condition_edit, smart_link_condition_delete]) +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) 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/navigation/api.py b/apps/navigation/api.py index 1f65adb245..aaab05c45b 100644 --- a/apps/navigation/api.py +++ b/apps/navigation/api.py @@ -8,7 +8,7 @@ from django.template import (TemplateSyntaxError, Library, VariableDoesNotExist, Node, Variable) from django.utils.encoding import smart_str, force_unicode, smart_unicode -from common.utils import urlquote +#from common.utils import urlquote from .utils import (resolve_to_name, resolve_arguments, resolve_template_variable, get_navigation_objects) diff --git a/apps/navigation/widgets.py b/apps/navigation/widgets.py index 702b1b0a32..6695f16f70 100644 --- a/apps/navigation/widgets.py +++ b/apps/navigation/widgets.py @@ -12,7 +12,7 @@ from django.template import RequestContext, Variable from permissions.models import Permission -from .templatetags.navigation_tags import resolve_links +#from .templatetags.navigation_tags import resolve_links from .utils import resolve_to_name @@ -37,7 +37,7 @@ def render_widget(request, link): 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) + links = []#resolve_links(context, [link], current_view, current_path, parsed_query_string) if links: link = links[0] return mark_safe(u'' % { diff --git a/apps/tags/__init__.py b/apps/tags/__init__.py index 9239b3d765..0592046566 100644 --- a/apps/tags/__init__.py +++ b/apps/tags/__init__.py @@ -3,7 +3,7 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ from navigation.api import (bind_links, register_top_menu, - register_model_list_columns, register_multi_item_links) + 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,12 +46,12 @@ register_model_list_columns(Document, [ }, ]) -bind_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]) bind_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(Document, [tag_document_list], menu_name='form_header') +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]) From dcf568ead59dee1cf72d902a40e95c2308e03082 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 16 Mar 2012 21:07:53 -0400 Subject: [PATCH 11/52] Start top menu refactor, added elementtree to requirements --- apps/common/__init__.py | 18 +++--- apps/document_indexing/__init__.py | 2 +- apps/documents/__init__.py | 2 +- apps/folders/__init__.py | 2 +- apps/main/__init__.py | 17 +++--- apps/navigation/__init__.py | 5 ++ apps/navigation/api.py | 59 +++++++++++-------- .../templates/generic_link_instance.html | 4 +- .../templatetags/navigation_tags.py | 35 ++++++----- apps/navigation/utils.py | 4 ++ apps/navigation/widgets.py | 4 +- apps/project_setup/__init__.py | 4 +- apps/project_setup/api.py | 9 ++- apps/project_setup/views.py | 6 +- apps/project_tools/__init__.py | 4 +- apps/project_tools/api.py | 11 ++-- apps/project_tools/views.py | 6 +- apps/smart_settings/__init__.py | 3 +- apps/tags/__init__.py | 2 +- requirements/production.txt | 1 + 20 files changed, 113 insertions(+), 85 deletions(-) diff --git a/apps/common/__init__.py b/apps/common/__init__.py index dfcd4066cd..7ec60b2d04 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 bind_links, register_top_menu +from navigation.api import bind_links, register_top_menu, Link from .conf import settings as common_settings from .utils import validate_path @@ -17,18 +17,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'} - -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'} +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') 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') -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/document_indexing/__init__.py b/apps/document_indexing/__init__.py index b27687c221..579facc80d 100644 --- a/apps/document_indexing/__init__.py +++ b/apps/document_indexing/__init__.py @@ -52,7 +52,7 @@ document_index_list = Link(text= _(u'indexes'), view='document_index_list', args 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={'text': _('indexes'), 'sprite': 'tab', 'view': 'index_list', 'children_view_regex': [r'^index_[i,l]']}) +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') diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index 75701f5623..39530783aa 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -177,7 +177,7 @@ register_model_list_columns(Document, [ register_top_menu( 'documents', - link={'famfam': 'page', 'text': _(u'documents'), 'view': 'document_list_recent'}, + link=Link(sprite='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', ], diff --git a/apps/folders/__init__.py b/apps/folders/__init__.py index 06699a5265..e52dbe3359 100644 --- a/apps/folders/__init__.py +++ b/apps/folders/__init__.py @@ -32,7 +32,7 @@ bind_links([Folder], [folder_view, folder_edit, folder_delete, folder_acl_list]) 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']) bind_links([Document], [document_folder_list], menu_name='form_header') diff --git a/apps/main/__init__.py b/apps/main/__init__.py index 34ab61d3e9..ba92093567 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 bind_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_path_regex=[r'^search/']) def get_version(): diff --git a/apps/navigation/__init__.py b/apps/navigation/__init__.py index e69de29bb2..928ceef82a 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 aaab05c45b..4b851f7401 100644 --- a/apps/navigation/api.py +++ b/apps/navigation/api.py @@ -7,11 +7,15 @@ import logging from django.template import (TemplateSyntaxError, Library, VariableDoesNotExist, Node, Variable) from django.utils.encoding import smart_str, force_unicode, smart_unicode +from django.core.urlresolvers import reverse, NoReverseMatch + +from elementtree.ElementTree import Element, SubElement #from common.utils import urlquote from .utils import (resolve_to_name, resolve_arguments, resolve_template_variable, get_navigation_objects) +from . import main_menu object_navigation = {} multi_object_navigation = {} @@ -26,6 +30,7 @@ logger = logging.getLogger(__name__) class ResolvedLink(object): active = False + 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): @@ -43,6 +48,11 @@ class Link(object): self.children_view_regex = children_view_regex self.klass = klass self.keep_query = keep_query + + # + self.conditional_highlight = None + self.children_views = [] + self.children_classes = [] def resolve(self, context): request = Variable('request').resolve(context) @@ -63,6 +73,8 @@ class Link(object): if condition_result: #new_link = {}#copy.copy(link) resolved_link = ResolvedLink() + resolved_link.text = self.text + resolved_link.sprite = self.sprite try: #args, kwargs = resolve_arguments(context, self.get('args', {})) args, kwargs = resolve_arguments(context, self.args) @@ -171,37 +183,36 @@ def register_multi_item_links(src, links, menu_name=None): multi_object_navigation[menu_name][src]['links'].extend(links) -def register_top_menu(name, link, children_views=None, - children_path_regex=None, children_view_regex=None, - position=None): +def register_top_menu(name, link, children_views=None, children_path_regex=None, children_view_regex=None, position=None): """ Register a new menu entry for the main menu displayed at the top of the page """ + menu = SubElement(main_menu, name, link=link) + #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) - 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) - - sort_menu_entries() - - return entry + #sort_menu_entries() + # + #return entry + return menu -def sort_menu_entries(): - global top_menu_entries - top_menu_entries = sorted(top_menu_entries, key=lambda k: (k['position'] < 0, k['position'])) +#def sort_menu_entries(): +# global top_menu_entries +# top_menu_entries = sorted(top_menu_entries, key=lambda k: (k['position'] < 0, k['position'])) def register_model_list_columns(model, columns): 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/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index ebd55723fa..49df4df77a 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -19,6 +19,7 @@ from ..api import (object_navigation, multi_object_navigation, from ..forms import MultiItemForm from ..utils import (resolve_to_name, resolve_arguments, resolve_template_variable, get_navigation_objects) +from .. import main_menu register = Library() logger = logging.getLogger(__name__) @@ -26,27 +27,25 @@ 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) - + #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 - pass - - context['menu_links'] = []#menu_links + #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 + # pass + #context['menu_links'] = []#menu_links + context['menu_links'] = [menu.get('link').resolve(context) for menu in main_menu.getchildren()] return '' diff --git a/apps/navigation/utils.py b/apps/navigation/utils.py index 1f72cebd85..923af8112e 100644 --- a/apps/navigation/utils.py +++ b/apps/navigation/utils.py @@ -1,5 +1,7 @@ from __future__ import absolute_import +import logging + from django.core.urlresolvers import RegexURLResolver, RegexURLPattern, Resolver404, get_resolver from django.template import (TemplateSyntaxError, Library, @@ -7,6 +9,8 @@ from django.template import (TemplateSyntaxError, Library, from django.utils.text import unescape_string_literal #__all__ = ('resolve_to_name',) +logger = logging.getLogger(__name__) + def get_navigation_objects(context): object_list = [] diff --git a/apps/navigation/widgets.py b/apps/navigation/widgets.py index 6695f16f70..d17cd6574e 100644 --- a/apps/navigation/widgets.py +++ b/apps/navigation/widgets.py @@ -17,9 +17,9 @@ 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'' 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 a03c89cb3e..7b356f84cb 100644 --- a/apps/project_setup/api.py +++ b/apps/project_setup/api.py @@ -1,12 +1,15 @@ from __future__ import absolute_import -from . import setup_link +from elementtree.ElementTree import Element, SubElement -setup_items = [] +from . import setup_menu + +#setup_items = [] def register_setup(link): - setup_items.append(link) + #setup_items.append(link) + SubElement(setup_menu, 'a', link=link) # Append the link's children_view_regex to the setup main menu children view regex #setup_link.setdefault('children_view_regex', []) diff --git a/apps/project_setup/views.py b/apps/project_setup/views.py index 8ab0426572..c30809375f 100644 --- a/apps/project_setup/views.py +++ b/apps/project_setup/views.py @@ -6,12 +6,14 @@ from django.utils.translation import ugettext_lazy as _ from navigation.widgets import button_navigation_widget -from .api import setup_items +#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) for item in setup_items], + 'object_list': [button_navigation_widget(request, item.get('link')) for item in setup_menu.getchildren()], 'title': _(u'setup items'), } 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 a8a20d92ec..c38486c374 100644 --- a/apps/project_tools/api.py +++ b/apps/project_tools/api.py @@ -1,12 +1,15 @@ from __future__ import absolute_import -from . import tool_link +from elementtree.ElementTree import Element, SubElement -tool_items = [] +from . import tool_menu + +#tool_items = [] def register_tool(link): - tool_items.append(link) - + #tool_items.append(link) + SubElement(tool_menu, 'a', link=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', [])) diff --git a/apps/project_tools/views.py b/apps/project_tools/views.py index 61693a100c..b3f0fa3e2d 100644 --- a/apps/project_tools/views.py +++ b/apps/project_tools/views.py @@ -6,12 +6,14 @@ from django.utils.translation import ugettext_lazy as _ from navigation.widgets import button_navigation_widget -from .api import tool_items +#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) for item in tool_items], + 'object_list': [button_navigation_widget(request, item) for item in tool_menu.getchildren()], 'title': _(u'tools'), } 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/tags/__init__.py b/apps/tags/__init__.py index 0592046566..e024a7ad3f 100644 --- a/apps/tags/__init__.py +++ b/apps/tags/__init__.py @@ -49,7 +49,7 @@ register_model_list_columns(Document, [ bind_links([Tag], [tag_tagged_item_list, tag_edit, tag_delete, tag_acl_list]) register_multi_item_links(['tag_list'], [tag_multiple_delete]) bind_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)']) +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)']) 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') diff --git a/requirements/production.txt b/requirements/production.txt index 41ab10ed77..998045debd 100644 --- a/requirements/production.txt +++ b/requirements/production.txt @@ -17,3 +17,4 @@ South==0.7.3 python-gnupg==0.2.8 python-hkp==0.1.3 requests==0.10.1 +elementtree==1.2.7-20070827-preview From 28a3e209abed46b02e231f72f129fe97de874886 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 16 Mar 2012 21:42:03 -0400 Subject: [PATCH 12/52] Converted project_setup and project_tools apps to use new elementtree based menus --- apps/converter/__init__.py | 4 ++-- apps/documents/__init__.py | 8 +++---- apps/folders/__init__.py | 2 +- apps/history/__init__.py | 6 ++--- apps/main/__init__.py | 2 +- apps/navigation/api.py | 39 ++++++++++---------------------- apps/project_setup/api.py | 9 +------- apps/project_setup/views.py | 2 -- apps/project_tools/api.py | 8 +------ apps/project_tools/views.py | 4 +--- apps/sources/__init__.py | 38 +++++++++++++++---------------- apps/user_management/__init__.py | 32 +++++++++++++------------- apps/workflows/__init__.py | 3 +-- 13 files changed, 60 insertions(+), 97 deletions(-) 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/documents/__init__.py b/apps/documents/__init__.py index 39530783aa..c36f04e684 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -177,12 +177,10 @@ register_model_list_columns(Document, [ register_top_menu( 'documents', - link=Link(sprite='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 ) diff --git a/apps/folders/__init__.py b/apps/folders/__init__.py index e52dbe3359..f72c92fd4f 100644 --- a/apps/folders/__init__.py +++ b/apps/folders/__init__.py @@ -32,7 +32,7 @@ bind_links([Folder], [folder_view, folder_edit, folder_delete, folder_acl_list]) bind_links([Folder, 'folder_list', 'folder_create'], [folder_list, folder_create], menu_name='secondary_menu') -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_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'])) bind_links([Document], [document_folder_list], menu_name='form_header') 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/main/__init__.py b/apps/main/__init__.py index ba92093567..6044c27fcc 100644 --- a/apps/main/__init__.py +++ b/apps/main/__init__.py @@ -38,7 +38,7 @@ admin_site = Link(text=_(u'admin site'), view='admin:index', sprite='keyboard', if not DISABLE_HOME_VIEW: 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=Link(text=_(u'search'), view='search', sprite='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/navigation/api.py b/apps/navigation/api.py index 4b851f7401..3802cc72e1 100644 --- a/apps/navigation/api.py +++ b/apps/navigation/api.py @@ -33,7 +33,7 @@ class ResolvedLink(object): 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): + 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): self.text = text self.view = view self.args = args or {} @@ -172,7 +172,7 @@ def register_multi_item_links(src, links, menu_name=None): Register a multiple item action action to be displayed in the generic list template """ - + # TODO: simplify by removing __iter__ support multi_object_navigation.setdefault(menu_name, {}) if hasattr(src, '__iter__'): for one_src in src: @@ -183,36 +183,21 @@ def register_multi_item_links(src, links, menu_name=None): multi_object_navigation[menu_name][src]['links'].extend(links) -def register_top_menu(name, link, children_views=None, children_path_regex=None, children_view_regex=None, position=None): +#def register_top_menu(name, link, children_views=None, children_path_regex=None, children_view_regex=None, position=None): +def register_top_menu(name, link, children_view_regex=None, position=None): """ Register a new menu entry for the main menu displayed at the top of the page """ - menu = SubElement(main_menu, name, link=link) - #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) + new_menu = SubElement(main_menu, name, link=link, position=position) + + sorted_menus = sorted(main_menu.getchildren(), key=lambda k: (k.get('position') < 0, k.get('position'))) + main_menu.clear() - #sort_menu_entries() - # - #return entry - return menu - - -#def sort_menu_entries(): -# global top_menu_entries -# top_menu_entries = sorted(top_menu_entries, key=lambda k: (k['position'] < 0, k['position'])) + for menu in sorted_menus: + main_menu.append(menu) + + return new_menu def register_model_list_columns(model, columns): diff --git a/apps/project_setup/api.py b/apps/project_setup/api.py index 7b356f84cb..7535981277 100644 --- a/apps/project_setup/api.py +++ b/apps/project_setup/api.py @@ -4,13 +4,6 @@ from elementtree.ElementTree import Element, SubElement from . import setup_menu -#setup_items = [] - def register_setup(link): - #setup_items.append(link) - SubElement(setup_menu, 'a', link=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 c30809375f..1b38bceeb4 100644 --- a/apps/project_setup/views.py +++ b/apps/project_setup/views.py @@ -6,13 +6,11 @@ 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'), } diff --git a/apps/project_tools/api.py b/apps/project_tools/api.py index c38486c374..634d6590d9 100644 --- a/apps/project_tools/api.py +++ b/apps/project_tools/api.py @@ -4,12 +4,6 @@ from elementtree.ElementTree import Element, SubElement from . import tool_menu -#tool_items = [] def register_tool(link): - #tool_items.append(link) - SubElement(tool_menu, 'a', link=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 b3f0fa3e2d..e3544b5fd3 100644 --- a/apps/project_tools/views.py +++ b/apps/project_tools/views.py @@ -6,14 +6,12 @@ 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) for item in tool_menu.getchildren()], + 'object_list': [button_navigation_widget(request, item.get('link')) for item in tool_menu.getchildren()], 'title': _(u'tools'), } diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index b5de48de59..196f8cd02b 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -3,7 +3,7 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ from navigation.api import (bind_links, - register_model_list_columns) + 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,29 +20,29 @@ 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]) bind_links([StagingFile], [staging_file_delete]) diff --git a/apps/user_management/__init__.py b/apps/user_management/__init__.py index 71277535c0..4e04ca2c9c 100644 --- a/apps/user_management/__init__.py +++ b/apps/user_management/__init__.py @@ -3,29 +3,29 @@ 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 bind_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]) 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') diff --git a/apps/workflows/__init__.py b/apps/workflows/__init__.py index a6f85d3afe..120b625e26 100644 --- a/apps/workflows/__init__.py +++ b/apps/workflows/__init__.py @@ -2,7 +2,6 @@ from __future__ import absolute_import from django.utils.translation import ugettext_lazy as _ -#from navigation.api import bind_links, register_multi_item_links from project_setup.api import register_setup from navigation.api import Link, bind_links @@ -41,4 +40,4 @@ bind_links([Workflow, 'setup_workflow_list', 'setup_workflow_create'], [setup_wo #bind_links([WorkflowState], [setup_workflow_states_edit_link]) -register_setup({'text': _(u'workflows'), 'view': 'setup_workflow_list', 'icon': 'chart_organisation.png', 'permissions': [PERMISSION_WORKFLOW_SETUP_VIEW]}) +register_setup(Link(text=_(u'workflows'), view='setup_workflow_list', icon='chart_organisation.png', permissions=[PERMISSION_WORKFLOW_SETUP_VIEW])) From 6fd0854ac540dd09e89cd7f9b351a9b39e557418 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 16 Mar 2012 23:33:15 -0400 Subject: [PATCH 13/52] Fix templates link's famfam reference to sprite --- .../common/templates/generic_list_horizontal_subtemplate.html | 4 ++-- apps/common/templates/generic_list_subtemplate.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/common/templates/generic_list_horizontal_subtemplate.html b/apps/common/templates/generic_list_horizontal_subtemplate.html index 8b62536db7..852cf0a5b4 100644 --- a/apps/common/templates/generic_list_horizontal_subtemplate.html +++ b/apps/common/templates/generic_list_horizontal_subtemplate.html @@ -38,7 +38,7 @@ @@ -77,7 +77,7 @@ diff --git a/apps/common/templates/generic_list_subtemplate.html b/apps/common/templates/generic_list_subtemplate.html index d1494312bf..bc5bf5e5a1 100644 --- a/apps/common/templates/generic_list_subtemplate.html +++ b/apps/common/templates/generic_list_subtemplate.html @@ -39,7 +39,7 @@ @@ -165,7 +165,7 @@ From 895702cb53aa69b209ee6b487bd036b47b8a53d3 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 16 Mar 2012 23:36:40 -0400 Subject: [PATCH 14/52] Remove debug statement --- apps/documents/views.py | 2 -- 1 file changed, 2 deletions(-) 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() From 8d4ce81c3408cea2b0ef35cd2bc299c06307d576 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 16 Mar 2012 23:37:21 -0400 Subject: [PATCH 15/52] Fix horizontal list link widget rendering --- apps/navigation/api.py | 39 ++++++++++--------- .../templatetags/navigation_tags.py | 28 +++---------- apps/navigation/widgets.py | 29 ++++---------- apps/tags/__init__.py | 2 +- 4 files changed, 35 insertions(+), 63 deletions(-) diff --git a/apps/navigation/api.py b/apps/navigation/api.py index 3802cc72e1..15f0a2c8ad 100644 --- a/apps/navigation/api.py +++ b/apps/navigation/api.py @@ -75,6 +75,9 @@ class Link(object): 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) @@ -167,24 +170,7 @@ def bind_links(sources, links, menu_name=None, position=0): link_binding[menu_name][source]['links'].extend(links) -def register_multi_item_links(src, links, menu_name=None): - """ - Register a multiple item action action to be displayed in the - generic list template - """ - # TODO: simplify by removing __iter__ support - 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) - - -#def register_top_menu(name, link, children_views=None, children_path_regex=None, children_view_regex=None, position=None): -def register_top_menu(name, link, children_view_regex=None, position=None): +def register_top_menu(name, link, position=None): """ Register a new menu entry for the main menu displayed at the top of the page @@ -216,6 +202,23 @@ def register_sidebar_template(source_list, template_name): sidebar_templates[source].append(template_name) +# TODO +def register_multi_item_links(src, links, menu_name=None): + """ + Register a multiple item action action to be displayed in the + generic list template + """ + # TODO: simplify by removing __iter__ support + 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) + + def get_context_object_navigation_links(context, menu_name=None, links_dict=object_navigation): request = Variable('request').resolve(context) current_path = request.META['PATH_INFO'] diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index 49df4df77a..54bfcdbd00 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -27,24 +27,6 @@ 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 - # pass - #context['menu_links'] = []#menu_links context['menu_links'] = [menu.get('link').resolve(context) for menu in main_menu.getchildren()] return '' @@ -84,10 +66,10 @@ def get_object_navigation_links(parser, token): @register.inclusion_tag('generic_navigation.html', takes_context=True) def object_navigation_template(context): new_context = copy.copy(context) - #new_context.update({ - # 'horizontal': True, - # 'object_navigation_links': get_object_navigation_links(context) - #}) + new_context.update({ + 'horizontal': True, + 'object_navigation_links': get_context_object_navigation_links(context) + }) return new_context @@ -106,7 +88,7 @@ def get_multi_item_links(parser, token): def get_multi_item_links_form(context): new_context = copy.copy(context) new_context.update({ - 'form': MultiItemForm(actions=[(link['url'], link['text']) for link in get_context_object_navigation_links(context, links_dict=multi_object_navigation)]), + 'form': MultiItemForm(actions=[(link.url, link.text) for link in get_context_object_navigation_links(context, links_dict=multi_object_navigation)]), 'title': _(u'Selected item actions:'), 'form_action': reverse('multi_object_action_view'), 'submit_method': 'get', diff --git a/apps/navigation/widgets.py b/apps/navigation/widgets.py index d17cd6574e..21ead7e606 100644 --- a/apps/navigation/widgets.py +++ b/apps/navigation/widgets.py @@ -12,7 +12,6 @@ from django.template import RequestContext, Variable from permissions.models import Permission -#from .templatetags.navigation_tags import resolve_links from .utils import resolve_to_name @@ -29,23 +28,11 @@ 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] - return mark_safe(u'' % { - 'url': reverse(link['view']) if 'view' in link else link['url'], - 'icon': link.getattr('icon', 'link_button.png'), - 'static_url': settings.STATIC_URL, - 'string': capfirst(link['text']), - 'image_alt': _(u'icon'), - }) - else: - return u'' + resolved_link = link.resolve(context) + return mark_safe(u'' % { + 'url': resolved_link.url, + 'icon': getattr(resolved_link, 'icon', 'link_button.png'), + 'static_url': settings.STATIC_URL, + 'string': capfirst(resolved_link.text), + 'image_alt': _(u'icon'), + }) diff --git a/apps/tags/__init__.py b/apps/tags/__init__.py index e024a7ad3f..ec5df2c9db 100644 --- a/apps/tags/__init__.py +++ b/apps/tags/__init__.py @@ -49,7 +49,7 @@ register_model_list_columns(Document, [ bind_links([Tag], [tag_tagged_item_list, tag_edit, tag_delete, tag_acl_list]) register_multi_item_links(['tag_list'], [tag_multiple_delete]) 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_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)'])) 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') From d5ddd22861d32de490df5cfde64c9bc9d24288d0 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Mar 2012 00:13:01 -0400 Subject: [PATCH 16/52] Fix document history link --- apps/documents/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index c36f04e684..8294230856 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -79,7 +79,7 @@ document_update_page_count = Link(text=_(u'update office documents\' page count' 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.id'], sprite='book_go', permissions=[PERMISSION_HISTORY_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 From 68231227930c42e2e0fc3ec0881318265e097a35 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Mar 2012 00:13:20 -0400 Subject: [PATCH 17/52] Fix link properties get in linking app --- apps/linking/forms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/linking/forms.py b/apps/linking/forms.py index 8801d0b574..419945a8d7 100644 --- a/apps/linking/forms.py +++ b/apps/linking/forms.py @@ -35,8 +35,8 @@ class SmartLinkImageWidget(forms.widgets.Widget): %(text)s ''' % { - 'famfam': link.getattr('famfam', u'link'), - 'text': capfirst(link['text']), + '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'') From 4b457aa567072a0a25e5db7b3be1438157d12907 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Mar 2012 00:15:08 -0400 Subject: [PATCH 18/52] Fix context link resolution --- apps/navigation/api.py | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/apps/navigation/api.py b/apps/navigation/api.py index 15f0a2c8ad..bd4c30d80a 100644 --- a/apps/navigation/api.py +++ b/apps/navigation/api.py @@ -219,7 +219,7 @@ def register_multi_item_links(src, links, menu_name=None): multi_object_navigation[menu_name][src]['links'].extend(links) -def get_context_object_navigation_links(context, menu_name=None, links_dict=object_navigation): +def get_context_object_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) @@ -229,22 +229,23 @@ def get_context_object_navigation_links(context, menu_name=None, links_dict=obje 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) + #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) - return 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)] + navigation_object_links = Variable('overrided_object_links').resolve(context) + #return 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 is no one. try: """ Check for and inject a temporary navigation dictionary @@ -256,19 +257,15 @@ def get_context_object_navigation_links(context, menu_name=None, links_dict=obje 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) - context_links.extend(links) + for link in links_dict[menu_name][current_view]['links']: + context_links.append(link.resolve(context)) except KeyError: pass for resolved_object in get_navigation_objects(context): try: - links = links_dict[menu_name][type(resolved_object['object'])]['links'] - #for link in resolve_links(context, links, current_view, current_path, parsed_query_string): - # context_links.append(link) - context_links.extend(links) + for link in links_dict[menu_name][type(resolved_object['object'])]['links']: + context_links.append(link.resolve(context)) except KeyError: pass From 5d02ed4d08cc86f16350dee20c625b94401a40c3 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Mar 2012 00:15:29 -0400 Subject: [PATCH 19/52] Fix link resolution tag --- apps/navigation/templatetags/navigation_tags.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index 54bfcdbd00..2571ed6279 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -14,7 +14,7 @@ from django.utils.encoding import smart_str, force_unicode, smart_unicode from common.utils import urlquote -from ..api import (object_navigation, multi_object_navigation, +from ..api import (link_binding, multi_object_navigation, top_menu_entries, sidebar_templates, get_context_object_navigation_links) from ..forms import MultiItemForm from ..utils import (resolve_to_name, resolve_arguments, resolve_template_variable, @@ -37,15 +37,20 @@ def get_top_menu_links(parser, token): 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_context_object_navigation_links(context, menu_name, links_dict=self.links_dict) + logger.debug('link_list: %s' % get_context_object_navigation_links(context, menu_name, links_dict=self.links_dict)) object_list = get_navigation_objects(context) + logger.debug('object_list: %s' % object_list) + + # TODO: why only one navigation_object if object_list: context['navigation_object'] = object_list[0]['object'] return '' @@ -53,6 +58,7 @@ class GetNavigationLinks(Node): @register.tag def get_object_navigation_links(parser, token): + logger.debug('getting links') tag_name, arg = token.contents.split(None, 1) m = re.search(r'("?\w+"?)?.?as (\w+)', arg) From eaf0293dcf963b17354de0d9687276735ac20b75 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Mar 2012 01:02:26 -0400 Subject: [PATCH 20/52] Don't return references to deleted users as a members --- apps/permissions/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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): From 3e6632dfdce6bebc6e82a79ea96ad1535c2f0235 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Mar 2012 01:03:04 -0400 Subject: [PATCH 21/52] Convert source app dynamic link generation to the new class based links --- apps/sources/views.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/apps/sources/views.py b/apps/sources/views.py index 351a6e80e3..aede2f4e1a 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): From 22f009d0f7842c0e4f69e6556a67df31b045aa7b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Mar 2012 01:03:38 -0400 Subject: [PATCH 22/52] Enable children view regex --- apps/navigation/api.py | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/apps/navigation/api.py b/apps/navigation/api.py index bd4c30d80a..8575993e83 100644 --- a/apps/navigation/api.py +++ b/apps/navigation/api.py @@ -3,11 +3,14 @@ from __future__ import absolute_import import urlparse import urllib import logging +import re from django.template import (TemplateSyntaxError, Library, VariableDoesNotExist, Node, Variable) from django.utils.encoding import smart_str, force_unicode, smart_unicode from django.core.urlresolvers import reverse, NoReverseMatch +from django.utils.http import urlquote +from django.utils.http import urlencode from elementtree.ElementTree import Element, SubElement @@ -33,7 +36,12 @@ class ResolvedLink(object): 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): + 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): + self.text = text self.view = view self.args = args or {} @@ -45,14 +53,12 @@ class Link(object): self.conditional_disable = conditional_disable self.description = description self.dont_mark_active = dont_mark_active - self.children_view_regex = children_view_regex + self.children_view_regex = children_view_regex or [] self.klass = klass self.keep_query = keep_query - - # - self.conditional_highlight = None - self.children_views = [] - self.children_classes = [] + self.conditional_highlight = conditional_highlight # Used by dynamic sources + self.children_views = children_views or [] + self.children_classes = children_classes or [] def resolve(self, context): request = Variable('request').resolve(context) @@ -71,7 +77,6 @@ class Link(object): condition_result = True if condition_result: - #new_link = {}#copy.copy(link) resolved_link = ResolvedLink() resolved_link.text = self.text resolved_link.sprite = self.sprite @@ -92,19 +97,14 @@ class Link(object): try: if kwargs: - #new_link['url'] = reverse(link['view'], kwargs=kwargs) resolved_link.url = reverse(self.view, kwargs=kwargs) else: -# new_link['url'] = reverse(link['view'], args=args) resolved_link.url = reverse(self.view, args=args) if self.keep_query: - #print 'parsed_query_string', parsed_query_string - #new_link['url'] = urlquote(new_link['url'], parsed_query_string) - resolved_link.url = urlquote(resolved_link.url, parsed_query_string) + resolved_link.url = u'%s?%s' % (urlquote(resolved_link.url), urlencode(parsed_query_string, doseq=True)) + except NoReverseMatch, exc: - #new_link['url'] = '#' resolved_link.url = '#' - #new_link['error'] = err resolved_link.error = exc elif self.url: if not self.dont_mark_active: @@ -144,10 +144,9 @@ class Link(object): # #new_link['active'] = True # resolved_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 - # 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) @@ -239,13 +238,12 @@ def get_context_object_navigation_links(context, menu_name=None, links_dict=link link list """ navigation_object_links = Variable('overrided_object_links').resolve(context) - #return 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 is no one. + # TODO: who uses this? Remove if no one. try: """ Check for and inject a temporary navigation dictionary From 3c83334e30e3eb30fe55eb90a474c349c1e4e7c8 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Mar 2012 01:19:03 -0400 Subject: [PATCH 23/52] Update search app to the new class based links --- apps/dynamic_search/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/dynamic_search/__init__.py b/apps/dynamic_search/__init__.py index 7bc581ee8d..4a536691ae 100644 --- a/apps/dynamic_search/__init__.py +++ b/apps/dynamic_search/__init__.py @@ -2,9 +2,9 @@ from django.utils.translation import ugettext_lazy as _ from navigation.api import register_sidebar_template, bind_links, Link -search = {'text': _(u'search'), 'view': 'search', 'famfam': 'zoom'} -search_advanced = {'text': _(u'advanced search'), 'view': 'search_advanced', 'famfam': 'zoom_in'} -search_again = {'text': _(u'search again'), 'view': 'search_again', 'famfam': 'arrow_undo'} +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_advanced'], 'search_help.html') From a6f6637789bf7e9c6fac8928d1277aeac1b13e10 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Mar 2012 01:19:35 -0400 Subject: [PATCH 24/52] Cleanups --- apps/navigation/api.py | 24 ++++--------------- .../templatetags/navigation_tags.py | 2 +- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/apps/navigation/api.py b/apps/navigation/api.py index 8575993e83..2845d684ca 100644 --- a/apps/navigation/api.py +++ b/apps/navigation/api.py @@ -14,17 +14,13 @@ from django.utils.http import urlencode from elementtree.ElementTree import Element, SubElement -#from common.utils import urlquote - from .utils import (resolve_to_name, resolve_arguments, resolve_template_variable, get_navigation_objects) from . import main_menu -object_navigation = {} multi_object_navigation = {} model_list_columns = {} sidebar_templates = {} -top_menu_entries = [] link_binding = {} @@ -156,7 +152,6 @@ class Link(object): resolved_link.active = True return resolved_link - #context_links.append(new_link) def bind_links(sources, links, menu_name=None, position=0): @@ -201,21 +196,15 @@ def register_sidebar_template(source_list, template_name): sidebar_templates[source].append(template_name) -# TODO -def register_multi_item_links(src, links, menu_name=None): +def register_multi_item_links(sources, links, menu_name=None): """ Register a multiple item action action to be displayed in the generic list template """ - # TODO: simplify by removing __iter__ support 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) + for source in sources: + multi_object_navigation[menu_name].setdefault(source, {'links': []}) + multi_object_navigation[menu_name][source]['links'].extend(links) def get_context_object_navigation_links(context, menu_name=None, links_dict=link_binding): @@ -227,11 +216,6 @@ def get_context_object_navigation_links(context, menu_name=None, links_dict=link # 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 diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index 2571ed6279..61d3472715 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -15,7 +15,7 @@ from django.utils.encoding import smart_str, force_unicode, smart_unicode from common.utils import urlquote from ..api import (link_binding, multi_object_navigation, - top_menu_entries, sidebar_templates, get_context_object_navigation_links) + sidebar_templates, get_context_object_navigation_links) from ..forms import MultiItemForm from ..utils import (resolve_to_name, resolve_arguments, resolve_template_variable, get_navigation_objects) From 0870d8228b1ff8637212d096be1a96e267b69aba Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Mar 2012 01:19:59 -0400 Subject: [PATCH 25/52] Don't display multiselect checkbox for folders, they don't support multiple selection --- apps/folders/views.py | 1 - 1 file changed, 1 deletion(-) 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())} From 04cad6365c1e12b2e02eb660344e8d3c7cb2f62c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Mar 2012 01:30:37 -0400 Subject: [PATCH 26/52] Converted workflow app to new class based links --- apps/workflows/__init__.py | 41 ++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/apps/workflows/__init__.py b/apps/workflows/__init__.py index 120b625e26..c6bf4ab9ee 100644 --- a/apps/workflows/__init__.py +++ b/apps/workflows/__init__.py @@ -13,31 +13,28 @@ from .permissions import (PERMISSION_WORKFLOW_SETUP_VIEW, from .models import Workflow, State, Transition, WorkflowState -setup_workflow_list_link = {'text': _(u'workflow list'), 'view': 'setup_workflow_list', 'famfam': 'chart_organisation', 'permissions': [PERMISSION_WORKFLOW_SETUP_VIEW]} -setup_workflow_create_link = {'text': _(u'create new workflow'), 'view': 'setup_workflow_create', 'famfam': 'chart_organisation_add', 'permissions': [PERMISSION_WORKFLOW_SETUP_CREATE]} -setup_workflow_create_link2 = Link(text=_(u'create new workflow'), view='setup_workflow_create', sprite='chart_organisation_add', permissions=[PERMISSION_WORKFLOW_SETUP_CREATE]) -setup_workflow_edit_link = {'text': _(u'edit'), 'view': 'setup_workflow_edit', 'args': 'workflow.pk', 'famfam': 'chart_organisation', 'permissions': [PERMISSION_WORKFLOW_SETUP_EDIT]} -setup_workflow_delete_link = {'text': _(u'delete'), 'view': 'setup_workflow_delete', 'args': 'workflow.pk', 'famfam': 'chart_organisation_delete', 'permissions': [PERMISSION_WORKFLOW_SETUP_DELETE]} -setup_workflow_states_list_link = {'text': _(u'states'), 'view': 'setup_workflow_states_list', 'args': 'workflow.pk', 'famfam': 'transmit_go', 'permissions': [PERMISSION_WORKFLOW_SETUP_EDIT]} -setup_workflow_states_add_link = {'text': _(u'add state'), 'view': 'setup_workflow_state_add', 'args': 'workflow.pk', 'famfam': 'transmit_add', 'permissions': [PERMISSION_WORKFLOW_SETUP_EDIT]} -setup_workflow_states_edit_link = {'text': _(u'edit state'), 'view': 'setup_workflow_state_edit', 'args': 'workflow_state.pk', 'famfam': 'transmit_edit', 'permissions': [PERMISSION_WORKFLOW_SETUP_EDIT]} +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 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 state'), view='setup_workflow_state_edit', args='workflow_state.pk', sprite='transmit_edit', permissions=[PERMISSION_WORKFLOW_SETUP_EDIT]) -setup_state_list_link = {'text': _(u'state list'), 'view': 'setup_state_list', 'famfam': 'transmit', 'permissions': [PERMISSION_STATE_SETUP_VIEW]} -setup_state_create_link = {'text': _(u'create new state'), 'view': 'setup_state_create', 'famfam': 'transmit_add', 'permissions': [PERMISSION_STATE_SETUP_CREATE]} -setup_state_edit_link = {'text': _(u'edit'), 'view': 'setup_state_edit', 'args': 'object.pk', 'famfam': 'transmit_edit', 'permissions': [PERMISSION_STATE_SETUP_EDIT]} -setup_state_delete_link = {'text': _(u'delete'), 'view': 'setup_state_delete', 'args': 'object.pk', 'famfam': 'transmit_delete', 'permissions': [PERMISSION_STATE_SETUP_DELETE]} +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]) -#bind_links(Workflow, [setup_workflow_states_list_link, setup_workflow_edit_link, setup_workflow_delete_link]) -#bind_links([Workflow, State, 'setup_workflow_list', 'setup_workflow_create', 'setup_state_list'], [setup_workflow_list_link], menu_name=u'form_header') -#bind_links([Workflow, 'setup_workflow_list', 'setup_workflow_create'], [setup_workflow_create_link], menu_name=u'secondary_menu') -#bind_links(['setup_workflow_states_list', 'setup_workflow_states_add'], [setup_workflow_states_add_link], menu_name=u'sidebar') +bind_links([Workflow], [setup_workflow_states_list_link, setup_workflow_edit_link, setup_workflow_delete_link]) +bind_links([Workflow, State, 'setup_workflow_list', 'setup_workflow_create', 'setup_state_list'], [setup_workflow_list_link], menu_name=u'form_header') +bind_links([Workflow, 'setup_workflow_list', 'setup_workflow_create'], [setup_workflow_create_link], menu_name=u'secondary_menu') +bind_links(['setup_workflow_states_list', 'setup_workflow_states_add'], [setup_workflow_states_add_link], menu_name=u'sidebar') -bind_links([Workflow, 'setup_workflow_list', 'setup_workflow_create'], [setup_workflow_create_link2], menu_name=u'secondary_menu') +bind_links([State], [setup_state_edit_link, setup_state_delete_link]) +bind_links([State, Workflow, 'setup_state_list', 'setup_workflow_list', 'setup_workflow_create'], [setup_state_list_link], menu_name=u'form_header') +bind_links([State, 'setup_state_list', 'setup_state_create'], [setup_state_create_link], menu_name=u'secondary_menu') -#bind_links(State, [setup_state_edit_link, setup_state_delete_link]) -#bind_links([State, Workflow, 'setup_state_list', 'setup_workflow_list', 'setup_workflow_create'], [setup_state_list_link], menu_name=u'form_header') -#bind_links([State, 'setup_state_list', 'setup_state_create'], [setup_state_create_link], menu_name=u'secondary_menu') - -#bind_links([WorkflowState], [setup_workflow_states_edit_link]) +bind_links([WorkflowState], [setup_workflow_states_edit_link]) register_setup(Link(text=_(u'workflows'), view='setup_workflow_list', icon='chart_organisation.png', permissions=[PERMISSION_WORKFLOW_SETUP_VIEW])) From fa1ee6fec099902bff01dd07e7d0d856faa29fe6 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 17 Mar 2012 01:31:01 -0400 Subject: [PATCH 27/52] Remove the 'related' menu, only used by one view --- apps/documents/__init__.py | 2 +- apps/main/templates/base.html | 23 ----------------------- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index 8294230856..8fba2a2c32 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -153,7 +153,7 @@ bind_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') 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') diff --git a/apps/main/templates/base.html b/apps/main/templates/base.html index 61efe93fca..5e19d2be34 100644 --- a/apps/main/templates/base.html +++ b/apps/main/templates/base.html @@ -331,17 +331,6 @@ {% 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 %}
@@ -374,18 +363,6 @@
{% 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 %}
From cb23f94cdfb1d707a39e66119ecd0db0143ee36c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 18 Mar 2012 00:42:48 -0400 Subject: [PATCH 28/52] Convert feedback app to use new class based links --- apps/feedback/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/feedback/__init__.py b/apps/feedback/__init__.py index 272dcb8601..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 bind_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') 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') From c3f337898d97c1cb10d65713a5e5706bdf9fe8a7 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 18 Mar 2012 00:43:18 -0400 Subject: [PATCH 29/52] Reorder statement for readability --- apps/acls/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/acls/__init__.py b/apps/acls/__init__.py index b87234b2a2..fe2e4b2cf7 100644 --- a/apps/acls/__init__.py +++ b/apps/acls/__init__.py @@ -30,10 +30,11 @@ register_multi_item_links(['acl_detail'], [acl_grant, acl_revoke]) bind_links([AccessObject], [acl_holder_new], menu_name='sidebar') -register_setup(acl_setup_valid_classes) 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) From 9bcdb01b79618c161a83e34c51dc0269c022e570 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 18 Mar 2012 03:32:20 -0400 Subject: [PATCH 30/52] Fix source transformation edit and delete view secondary links --- apps/sources/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/sources/views.py b/apps/sources/views.py index aede2f4e1a..54d5fb7f43 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -697,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': [ @@ -729,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')} From ef33a780e02a7776514a3687b3c1b4bb2d22dc94 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 18 Mar 2012 03:33:15 -0400 Subject: [PATCH 31/52] Remove unnecesary extra_context from document_acl view --- apps/document_acls/views.py | 3 --- 1 file changed, 3 deletions(-) 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, - } ) From 892a7f77ae3225f2c7beaf4d5fc66b164936b4f4 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 18 Mar 2012 03:33:58 -0400 Subject: [PATCH 32/52] Simply and convert base tempalte navigation render code --- apps/main/templates/base.html | 164 +++++++++++++--------------------- 1 file changed, 61 insertions(+), 103 deletions(-) diff --git a/apps/main/templates/base.html b/apps/main/templates/base.html index 5e19d2be34..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 %} -
-
    - {% with form_navigation_links as object_navigation_links %} - {% with "true" as as_li %} - {% with "true" as hide_active_anchor %} - {% with "active" as li_class_active %} - {% with "first" as li_class_first %} - {% include "generic_navigation.html" %} - {% endwith %} - {% endwith %} - {% endwith %} - {% endwith %} - {% endwith %} -
-
- {% 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 %}
    - {% with form_navigation_links as object_navigation_links %} - {% with "true" as as_li %} - {% with "true" as hide_active_anchor %} - {% with "active" as li_class_active %} - {% with "first" as li_class_first %} - {% include "generic_navigation.html" %} - {% endwith %} - {% endwith %} - {% endwith %} - {% endwith %} - {% endwith %} + {% with object_links as links %} + {% with "true" as as_li %} + {% with "true" as hide_active_anchor %} + {% with "active" as li_class_active %} + {% with "first" as li_class_first %} + {% include "generic_navigation.html" %} + {% endwith %} + {% endwith %} + {% endwith %} + {% endwith %} + {% endwith %}
-
- {% endif %} +
+ {% endfor %} +
{% endif %} {% endblock %} @@ -298,84 +278,62 @@ {% 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 "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 "sidebar" as object_navigation_links %} - {% if object_navigation_links %} -
-

{% trans "Other available actions" %}

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

{% trans "Other available actions" %}

+ +
+ {% endif %} + {% get_sidebar_templates as sidebar_templates %} {% for template in sidebar_templates %} {% with "true" as side_bar %} From 2b123799deb01ef41931ce10d187e17a17f9913c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 18 Mar 2012 03:35:05 -0400 Subject: [PATCH 33/52] Update multi_item_links to use new link format --- .../templates/generic_list_subtemplate.html | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/common/templates/generic_list_subtemplate.html b/apps/common/templates/generic_list_subtemplate.html index bc5bf5e5a1..220f4e6d5f 100644 --- a/apps/common/templates/generic_list_subtemplate.html +++ b/apps/common/templates/generic_list_subtemplate.html @@ -37,10 +37,12 @@ {% if multi_select_as_buttons %} {% get_multi_item_links as multi_item_links %} {% else %} @@ -163,10 +165,12 @@ {% if multi_select_as_buttons %} {% get_multi_item_links as multi_item_links %} {% else %} From 9f22085eefdbf6c7bd0e4b2e27fec7a280528c99 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 18 Mar 2012 03:35:25 -0400 Subject: [PATCH 34/52] Update template to use new variable name --- apps/navigation/templates/generic_navigation.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 %} From 8ff1997ddabf700530580f7c45650795186e3fef Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 18 Mar 2012 03:50:28 -0400 Subject: [PATCH 35/52] Final updates for new class based link navigation --- apps/navigation/api.py | 56 ++++++----- .../templatetags/navigation_tags.py | 28 +++--- apps/navigation/utils.py | 94 ++++++++++++------- 3 files changed, 107 insertions(+), 71 deletions(-) diff --git a/apps/navigation/api.py b/apps/navigation/api.py index 2845d684ca..e43df44906 100644 --- a/apps/navigation/api.py +++ b/apps/navigation/api.py @@ -49,14 +49,16 @@ class Link(object): self.conditional_disable = conditional_disable self.description = description self.dont_mark_active = dont_mark_active - self.children_view_regex = children_view_regex or [] 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) @@ -88,7 +90,6 @@ class Link(object): if self.view: if not self.dont_mark_active: - #new_link['active'] = link['view'] == current_view resolved_link.active = self.view == current_view try: @@ -104,41 +105,32 @@ class Link(object): resolved_link.error = exc elif self.url: if not self.dont_mark_active: - #new_link['active'] = link['url'] == current_path resolved_link.url.active = self.url == current_path if kwargs: - #new_link['url'] = link['url'] % kwargs resolved_link.url = self.url % kwargs else: - #new_link['url'] = link['url'] % args resolved_link.url = self.url % args if link.keep_query: - #new_link['url'] = urlquote(new_link['url'], parsed_query_string) - resolved_link.url = urlquote(resolved_link.url, parsed_query_string) + resolved_link.url = u'%s?%s' % (urlquote(resolved_link.url), urlencode(parsed_query_string, doseq=True)) else: - #new_link['active'] = False resolved_link.active = False if self.conditional_highlight: - #new_link['active'] = link['conditional_highlight'](context) resolved_link.active = self.conditional_highlight(context) if self.conditional_disable: - #new_link['disabled'] = link['conditional_disable'](context) resolved_link.disabled = self.conditional_disable(context) else: - #new_link['disabled'] = False resolved_link.disabled = False if current_view in self.children_views: - #new_link['active'] = True resolved_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 - # 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): @@ -206,16 +198,19 @@ def register_multi_item_links(sources, links, menu_name=None): multi_object_navigation[menu_name].setdefault(source, {'links': []}) multi_object_navigation[menu_name][source]['links'].extend(links) - -def get_context_object_navigation_links(context, menu_name=None, links_dict=link_binding): +#TODO: new name: get_context_navigation_links, get_navigation_links_for_context +def get_context_object_navigation_links(context, menu_name=None, links_dict=link_binding):#, object_variable_name=None): request = Variable('request').resolve(context) current_path = request.META['PATH_INFO'] current_view = resolve_to_name(current_path) - context_links = [] + 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 @@ -226,8 +221,10 @@ def get_context_object_navigation_links(context, menu_name=None, links_dict=link 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 @@ -239,15 +236,24 @@ def get_context_object_navigation_links(context, menu_name=None, links_dict=link pass try: - for link in links_dict[menu_name][current_view]['links']: - context_links.append(link.resolve(context)) + 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 in get_navigation_objects(context): + for resolved_object, object_properties in get_navigation_objects(context).items(): try: - for link in links_dict[menu_name][type(resolved_object['object'])]['links']: - context_links.append(link.resolve(context)) + 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 diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index 61d3472715..0ba20469d7 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -46,13 +46,6 @@ class GetNavigationLinks(Node): def render(self, context): menu_name = resolve_template_variable(context, self.menu_name) context[self.var_name] = get_context_object_navigation_links(context, menu_name, links_dict=self.links_dict) - logger.debug('link_list: %s' % get_context_object_navigation_links(context, menu_name, links_dict=self.links_dict)) - object_list = get_navigation_objects(context) - logger.debug('object_list: %s' % object_list) - - # TODO: why only one navigation_object - if object_list: - context['navigation_object'] = object_list[0]['object'] return '' @@ -72,13 +65,15 @@ def get_object_navigation_links(parser, token): @register.inclusion_tag('generic_navigation.html', takes_context=True) def object_navigation_template(context): new_context = copy.copy(context) - new_context.update({ - 'horizontal': True, - 'object_navigation_links': get_context_object_navigation_links(context) - }) + + for object_reference, object_links in get_context_object_navigation_links(context).items(): + new_context.update({ + 'horizontal': True, + 'links': object_links + }) + return new_context - - + @register.tag def get_multi_item_links(parser, token): tag_name, arg = token.contents.split(None, 1) @@ -92,9 +87,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_context_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 923af8112e..a720883e03 100644 --- a/apps/navigation/utils.py +++ b/apps/navigation/utils.py @@ -8,51 +8,81 @@ from django.template import (TemplateSyntaxError, Library, VariableDoesNotExist, Node, Variable) from django.utils.text import unescape_string_literal -#__all__ = ('resolve_to_name',) logger = logging.getLogger(__name__) def get_navigation_objects(context): - object_list = [] + 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 a simple 'object' search first, for lists templates try: resolved_object = Variable('object').resolve(context) except VariableDoesNotExist: - try: - object_name_list = Variable('navigation_object_list').resolve(context) - except VariableDoesNotExist: - try: - object_name_list = [{'object': Variable('navigation_object_name').resolve(context)}] - except VariableDoesNotExist: - #try: - # object_name_list = [{'object': Variable('list_object_variable_name').resolve(context)}] - #except VariableDoesNotExist: - return [] - #object_name_list = [{'object': 'object'}] - #logger.debug('none found, falling back to "object"') - #else: - # logger.debug('found: list_object_variable_name') - else: - logger.debug('found: navigation_object_name') - else: - logger.debug('found: navigation_object_list') + pass else: logger.debug('found single object') - return [{'object': resolved_object}]#, 'object_name': 'object'}] - - logger.debug('object_name_list: %s' % object_name_list) - - for object_name in object_name_list: try: - resolved_object = Variable(object_name['object']).resolve(context) + object_label = Variable('object_name').resolve(context) except VariableDoesNotExist: - resolved_object = None - - object_list.append({'object': resolved_object})#, 'object_name': 'qwe'}) + object_label = None + finally: + objects.setdefault(resolved_object, {}) + objects[resolved_object]['label'] = object_label - logger.debug('object_list: %s' % object_list) - return object_list + logger.debug('objects: %s' % objects) + return objects def resolve_template_variable(context, name): From af49370870d3b055ee60f91a9afab12fa6e63f19 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 18 Mar 2012 04:02:03 -0400 Subject: [PATCH 36/52] PEP8 cleanups --- apps/navigation/__init__.py | 2 +- apps/navigation/api.py | 44 +++++++++---------- .../templatetags/navigation_tags.py | 19 +++----- apps/navigation/utils.py | 16 +++---- apps/navigation/widgets.py | 9 +--- 5 files changed, 40 insertions(+), 50 deletions(-) diff --git a/apps/navigation/__init__.py b/apps/navigation/__init__.py index 928ceef82a..5b5faffadc 100644 --- a/apps/navigation/__init__.py +++ b/apps/navigation/__init__.py @@ -1,4 +1,4 @@ -from __future__ import absolute_import +from __future__ import absolute_import from elementtree.ElementTree import Element diff --git a/apps/navigation/api.py b/apps/navigation/api.py index e43df44906..fc36decdc1 100644 --- a/apps/navigation/api.py +++ b/apps/navigation/api.py @@ -1,21 +1,20 @@ -from __future__ import absolute_import +from __future__ import absolute_import import urlparse import urllib import logging import re -from django.template import (TemplateSyntaxError, Library, - VariableDoesNotExist, Node, Variable) -from django.utils.encoding import smart_str, force_unicode, smart_unicode +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 from django.utils.http import urlencode -from elementtree.ElementTree import Element, SubElement +from elementtree.ElementTree import SubElement from .utils import (resolve_to_name, resolve_arguments, - resolve_template_variable, get_navigation_objects) + get_navigation_objects) from . import main_menu multi_object_navigation = {} @@ -29,15 +28,15 @@ logger = logging.getLogger(__name__) class ResolvedLink(object): active = False - - + + 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): - + self.text = text self.view = view self.args = args or {} @@ -62,12 +61,12 @@ class Link(object): 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) - + # Check to see if link has conditional display if self.condition: condition_result = self.condition(context) @@ -80,7 +79,7 @@ class Link(object): 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) @@ -98,7 +97,7 @@ class Link(object): 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)) + resolved_link.url = u'%s?%s' % (urlquote(resolved_link.url), urlencode(parsed_query_string, doseq=True)) except NoReverseMatch, exc: resolved_link.url = '#' @@ -106,13 +105,13 @@ class Link(object): 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 link.keep_query: - resolved_link.url = u'%s?%s' % (urlquote(resolved_link.url), urlencode(parsed_query_string, doseq=True)) + 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 @@ -162,13 +161,13 @@ def register_top_menu(name, link, position=None): of the page """ new_menu = SubElement(main_menu, name, link=link, position=position) - + sorted_menus = sorted(main_menu.getchildren(), key=lambda k: (k.get('position') < 0, k.get('position'))) main_menu.clear() for menu in sorted_menus: main_menu.append(menu) - + return new_menu @@ -198,8 +197,9 @@ def register_multi_item_links(sources, links, menu_name=None): multi_object_navigation[menu_name].setdefault(source, {'links': []}) multi_object_navigation[menu_name][source]['links'].extend(links) + #TODO: new name: get_context_navigation_links, get_navigation_links_for_context -def get_context_object_navigation_links(context, menu_name=None, links_dict=link_binding):#, object_variable_name=None): +def get_context_object_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) @@ -238,8 +238,8 @@ def get_context_object_navigation_links(context, menu_name=None, links_dict=link try: view_links = links_dict[menu_name][current_view]['links'] if view_links: - context_links.setdefault(None, []) - + context_links.setdefault(None, []) + for link in view_links: context_links[None].append(link.resolve(context)) except KeyError: @@ -251,7 +251,7 @@ def get_context_object_navigation_links(context, menu_name=None, links_dict=link 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: diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index 0ba20469d7..d09d71350e 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -1,24 +1,18 @@ -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) + Node, Variable) 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 (link_binding, multi_object_navigation, sidebar_templates, get_context_object_navigation_links) from ..forms import MultiItemForm -from ..utils import (resolve_to_name, resolve_arguments, resolve_template_variable, - get_navigation_objects) +from ..utils import resolve_to_name, resolve_template_variable from .. import main_menu register = Library() @@ -65,15 +59,16 @@ def get_object_navigation_links(parser, token): @register.inclusion_tag('generic_navigation.html', takes_context=True) def object_navigation_template(context): new_context = copy.copy(context) - + for object_reference, object_links in get_context_object_navigation_links(context).items(): new_context.update({ 'horizontal': True, - 'links': object_links + 'links': object_links }) return new_context + @register.tag def get_multi_item_links(parser, token): tag_name, arg = token.contents.split(None, 1) diff --git a/apps/navigation/utils.py b/apps/navigation/utils.py index a720883e03..89cd9ec9a2 100644 --- a/apps/navigation/utils.py +++ b/apps/navigation/utils.py @@ -1,11 +1,10 @@ -from __future__ import absolute_import +from __future__ import absolute_import import logging from django.core.urlresolvers import RegexURLResolver, RegexURLPattern, Resolver404, get_resolver -from django.template import (TemplateSyntaxError, Library, - VariableDoesNotExist, Node, Variable) +from django.template import (VariableDoesNotExist, Variable) from django.utils.text import unescape_string_literal logger = logging.getLogger(__name__) @@ -13,7 +12,7 @@ logger = logging.getLogger(__name__) def get_navigation_objects(context): objects = {} - + try: indirect_reference_list = Variable('navigation_object_list').resolve(context) except VariableDoesNotExist: @@ -38,13 +37,13 @@ def get_navigation_objects(context): try: object_label = Variable('object_name').resolve(context) except VariableDoesNotExist: - object_label = None + 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 @@ -57,7 +56,7 @@ def get_navigation_objects(context): try: object_label = Variable('object_name').resolve(context) except VariableDoesNotExist: - object_label = None + object_label = None finally: try: resolved_object = Variable(indirect_reference).resolve(context) @@ -94,7 +93,7 @@ def resolve_template_variable(context, name): return str(Variable(name).resolve(context)) except TypeError: return name - + def resolve_arguments(context, src_args): args = [] @@ -152,5 +151,6 @@ def _resolver_resolve_to_name(self, path): RegexURLPattern.resolve_to_name = _pattern_resolve_to_name RegexURLResolver.resolve_to_name = _resolver_resolve_to_name + def resolve_to_name(path, urlconf=None): return get_resolver(urlconf).resolve_to_name(path) diff --git a/apps/navigation/widgets.py b/apps/navigation/widgets.py index 21ead7e606..2370d4681b 100644 --- a/apps/navigation/widgets.py +++ b/apps/navigation/widgets.py @@ -1,19 +1,14 @@ -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 .utils import resolve_to_name - def button_navigation_widget(request, link): if link.permissions: From 663a5d5b3bc6c8431eb03ba6e1f76bda738e9b12 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 18 Mar 2012 04:11:14 -0400 Subject: [PATCH 37/52] Add test steps to the documentation --- docs/intro/installation.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/intro/installation.rst b/docs/intro/installation.rst index 3d9056fab7..6bf8dcfec4 100644 --- a/docs/intro/installation.rst +++ b/docs/intro/installation.rst @@ -49,8 +49,15 @@ Populate the database with the project's schema doing:: Collect the static files of the project into the ``static`` folder for serving via a webserver:: $ ./manage.py collectstatic + +To test your installation, create a file called settings_local.py with the following content:: + + DEBUG = True + DEVELOPMENT = True + +Execute Django's runserver command to launch a local instance of **Mayan EDMS** and point your browser to the URL: 127:0.0.1:8000, if everything was installed correctly you should see the login screen. +After making sure everything is running correctly, stop the runserver command, delete the settings_local.py and deploy **Mayan EDMS** using the webserver of your preference. If your are using Apache_, a sample site file is included under the contrib directory. -After that deploy it using the webserver of your preference. If your are using Apache_, a sample site file is included under the contrib directory. Webfaction ---------- From ffc71ea8b3d416686eda6bb8531ea67ceed66c12 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 18 Mar 2012 23:58:40 -0400 Subject: [PATCH 38/52] Add workflow state delete view and transition list, create and edit views --- apps/workflows/__init__.py | 25 ++++++- apps/workflows/forms.py | 11 +++ apps/workflows/urls.py | 7 ++ apps/workflows/views.py | 145 +++++++++++++++++++++++++++++++++++-- 4 files changed, 179 insertions(+), 9 deletions(-) diff --git a/apps/workflows/__init__.py b/apps/workflows/__init__.py index c6bf4ab9ee..6b712e5496 100644 --- a/apps/workflows/__init__.py +++ b/apps/workflows/__init__.py @@ -20,21 +20,38 @@ setup_workflow_delete_link = Link(text=_(u'delete'), view='setup_workflow_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 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 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 state'), view='setup_workflow_state_remove', args='workflow_state.pk', sprite='transmit_delete', 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_transition_list_link = Link(text=_(u'transition list'), view='setup_transition_list', sprite='chart_line', permissions=[PERMISSION_WORKFLOW_SETUP_VIEW]) +setup_transition_create_link = Link(text=_(u'create new transition'), view='setup_transition_create', sprite='chart_line_add', permissions=[PERMISSION_WORKFLOW_SETUP_CREATE]) +setup_transition_edit_link = Link(text=_(u'edit'), view='setup_transition_edit', args='transition.pk', sprite='chart_line', permissions=[PERMISSION_WORKFLOW_SETUP_EDIT]) +setup_transition_delete_link = Link(text=_(u'delete'), view='setup_transition_delete', args='transition.pk', sprite='chart_line_delete', permissions=[PERMISSION_WORKFLOW_SETUP_DELETE]) + +bind_links( + [ + Workflow, State, Transition, + 'setup_workflow_list', 'setup_workflow_create', + 'setup_state_list', 'setup_state_create', + 'setup_transition_list', '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_states_list_link, setup_workflow_edit_link, setup_workflow_delete_link]) -bind_links([Workflow, State, 'setup_workflow_list', 'setup_workflow_create', 'setup_state_list'], [setup_workflow_list_link], menu_name=u'form_header') bind_links([Workflow, 'setup_workflow_list', 'setup_workflow_create'], [setup_workflow_create_link], menu_name=u'secondary_menu') -bind_links(['setup_workflow_states_list', 'setup_workflow_states_add'], [setup_workflow_states_add_link], menu_name=u'sidebar') +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, Workflow, 'setup_state_list', 'setup_workflow_list', 'setup_workflow_create'], [setup_state_list_link], menu_name=u'form_header') bind_links([State, 'setup_state_list', 'setup_state_create'], [setup_state_create_link], menu_name=u'secondary_menu') -bind_links([WorkflowState], [setup_workflow_states_edit_link]) +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_states_edit_link, setup_workflow_states_remove_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 index b50a3b7cfd..cc2ac01210 100644 --- a/apps/workflows/forms.py +++ b/apps/workflows/forms.py @@ -17,5 +17,16 @@ class StateSetupForm(forms.ModelForm): 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 TransitionSetupForm(forms.ModelForm): + class Meta: + model = Transition diff --git a/apps/workflows/urls.py b/apps/workflows/urls.py index 3a9b79557f..1c12a9e89b 100644 --- a/apps/workflows/urls.py +++ b/apps/workflows/urls.py @@ -8,9 +8,16 @@ urlpatterns = patterns('workflows.views', url(r'^setup/workflow/(?P\d+)/state/list/$', 'setup_workflow_states_list', (), 'setup_workflow_states_list'), url(r'^setup/workflow/(?P\d+)/state/create/$', '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/transition/list/$', 'setup_transition_list', (), 'setup_transition_list'), + url(r'^setup/transition/create/$', 'setup_transition_create', (), 'setup_transition_create'), + url(r'^setup/transition/(?P\d+)/edit/$', 'setup_transition_edit', (), 'setup_transition_edit'), + #url(r'^setup/transition/(?P\d+)/delete/$', 'setup_transition_delete', (), 'setup_transition_delete'), + ) diff --git a/apps/workflows/views.py b/apps/workflows/views.py index ceb7bef219..c2cd175813 100644 --- a/apps/workflows/views.py +++ b/apps/workflows/views.py @@ -19,7 +19,8 @@ from common.utils import encapsulate #from acls.models import AccessEntry from .models import Workflow, State, Transition, WorkflowState -from .forms import WorkflowSetupForm, StateSetupForm, WorkflowStateSetupForm +from .forms import (WorkflowSetupForm, StateSetupForm, + WorkflowStateSetupForm, TransitionSetupForm) from .permissions import (PERMISSION_WORKFLOW_SETUP_VIEW, PERMISSION_WORKFLOW_SETUP_CREATE, PERMISSION_WORKFLOW_SETUP_EDIT, PERMISSION_WORKFLOW_SETUP_DELETE, PERMISSION_STATE_SETUP_VIEW, @@ -170,13 +171,13 @@ def setup_workflow_state_add(request, workflow_pk): workflow = get_object_or_404(Workflow, pk=workflow_pk) if request.method == 'POST': - form = WorkflowStateSetupForm(request.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() + form = WorkflowStateSetupForm(workflow=workflow) return render_to_response('generic_form.html', { 'title': _(u'add worflow state'), @@ -194,13 +195,13 @@ def setup_workflow_state_edit(request, workflow_state_pk): redirect_url = reverse('setup_workflow_states_list', args=[workflow_state.workflow.pk]) if request.method == 'POST': - form = WorkflowStateSetupForm(instance=workflow_state, data=request.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(instance=workflow_state) + form = WorkflowStateSetupForm(workflow=workflow_state.workflow, instance=workflow_state) return render_to_response('generic_form.html', { 'title': _(u'edit worflow state'), @@ -212,7 +213,79 @@ def setup_workflow_state_edit(request, workflow_state_pk): {'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_STATE_SETUP_DELETE]) + except PermissionDenied: + workflow_states = AccessEntry.objects.filter_objects_by_access(PERMISSION_STATE_SETUP_DELETE, 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)) + + +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]) @@ -323,3 +396,65 @@ def setup_state_delete(request, state_pk=None, state_pk_list=None): 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_WORKFLOW_SETUP_VIEW]) + + context = { + 'object_list': Transition.objects.all(), + 'title': _(u'transitions'), + 'hide_link': True, + #'extra_columns': [ + # {'name': _(u'Initial state'), 'attribute': encapsulate(lambda transition: transition.initial_state or _(u'None'))}, + #], + '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_WORKFLOW_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_WORKFLOW_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)) From 6cbe1301cae300f116e4069c225a1b3efaa27168 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 19 Mar 2012 00:04:33 -0400 Subject: [PATCH 39/52] Add transition delete view and transition setup permissions --- apps/workflows/__init__.py | 12 +++--- apps/workflows/permissions.py | 5 +++ apps/workflows/urls.py | 2 +- apps/workflows/views.py | 69 ++++++++++++++++++++++++++++++----- 4 files changed, 73 insertions(+), 15 deletions(-) diff --git a/apps/workflows/__init__.py b/apps/workflows/__init__.py index 6b712e5496..194b613727 100644 --- a/apps/workflows/__init__.py +++ b/apps/workflows/__init__.py @@ -9,7 +9,9 @@ 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) + PERMISSION_STATE_SETUP_DELETE, PERMISSION_TRANSITION_SETUP_VIEW, + PERMISSION_TRANSITION_SETUP_CREATE, PERMISSION_TRANSITION_SETUP_EDIT, + PERMISSION_TRANSITION_SETUP_DELETE) from .models import Workflow, State, Transition, WorkflowState @@ -27,10 +29,10 @@ setup_state_create_link = Link(text=_(u'create new state'), view='setup_state_cr 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_transition_list_link = Link(text=_(u'transition list'), view='setup_transition_list', sprite='chart_line', permissions=[PERMISSION_WORKFLOW_SETUP_VIEW]) -setup_transition_create_link = Link(text=_(u'create new transition'), view='setup_transition_create', sprite='chart_line_add', permissions=[PERMISSION_WORKFLOW_SETUP_CREATE]) -setup_transition_edit_link = Link(text=_(u'edit'), view='setup_transition_edit', args='transition.pk', sprite='chart_line', permissions=[PERMISSION_WORKFLOW_SETUP_EDIT]) -setup_transition_delete_link = Link(text=_(u'delete'), view='setup_transition_delete', args='transition.pk', sprite='chart_line_delete', permissions=[PERMISSION_WORKFLOW_SETUP_DELETE]) +setup_transition_list_link = Link(text=_(u'transition list'), view='setup_transition_list', sprite='chart_line', permissions=[PERMISSION_TRANSITION_SETUP_VIEW]) +setup_transition_create_link = Link(text=_(u'create new transition'), view='setup_transition_create', sprite='chart_line_add', permissions=[PERMISSION_TRANSITION_SETUP_CREATE]) +setup_transition_edit_link = Link(text=_(u'edit'), view='setup_transition_edit', args='transition.pk', sprite='chart_line', permissions=[PERMISSION_TRANSITION_SETUP_EDIT]) +setup_transition_delete_link = Link(text=_(u'delete'), view='setup_transition_delete', args='transition.pk', sprite='chart_line_delete', permissions=[PERMISSION_TRANSITION_SETUP_DELETE]) bind_links( [ diff --git a/apps/workflows/permissions.py b/apps/workflows/permissions.py index dcce9281bd..5f27a47854 100644 --- a/apps/workflows/permissions.py +++ b/apps/workflows/permissions.py @@ -16,3 +16,8 @@ PERMISSION_STATE_SETUP_CREATE = Permission.objects.register(namespace, 'state_se 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/urls.py b/apps/workflows/urls.py index 1c12a9e89b..f8e137e3b8 100644 --- a/apps/workflows/urls.py +++ b/apps/workflows/urls.py @@ -18,6 +18,6 @@ urlpatterns = patterns('workflows.views', url(r'^setup/transition/list/$', 'setup_transition_list', (), 'setup_transition_list'), url(r'^setup/transition/create/$', 'setup_transition_create', (), 'setup_transition_create'), url(r'^setup/transition/(?P\d+)/edit/$', 'setup_transition_edit', (), 'setup_transition_edit'), - #url(r'^setup/transition/(?P\d+)/delete/$', 'setup_transition_delete', (), 'setup_transition_delete'), + url(r'^setup/transition/(?P\d+)/delete/$', 'setup_transition_delete', (), 'setup_transition_delete'), ) diff --git a/apps/workflows/views.py b/apps/workflows/views.py index c2cd175813..d548078845 100644 --- a/apps/workflows/views.py +++ b/apps/workflows/views.py @@ -25,7 +25,9 @@ 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) + PERMISSION_STATE_SETUP_DELETE, PERMISSION_TRANSITION_SETUP_VIEW, + PERMISSION_TRANSITION_SETUP_CREATE, PERMISSION_TRANSITION_SETUP_EDIT, + PERMISSION_TRANSITION_SETUP_DELETE) logger = logging.getLogger(__name__) @@ -294,11 +296,6 @@ def setup_state_list(request): 'object_list': State.objects.all(), 'title': _(u'states'), 'hide_link': True, - #'list_object_variable_name': 'source', - #'source_type': source_type, - #'extra_columns': [ - # {'name': _(u'Initial state'), 'attribute': encapsulate(lambda workflow: workflow.initial_state or _(u'None'))}, - #], } return render_to_response('generic_list.html', context, @@ -400,7 +397,7 @@ def setup_state_delete(request, state_pk=None, state_pk_list=None): # Transitions def setup_transition_list(request): - Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_VIEW]) + Permission.objects.check_permissions(request.user, [PERMISSION_TRANSITION_SETUP_VIEW]) context = { 'object_list': Transition.objects.all(), @@ -417,7 +414,7 @@ def setup_transition_list(request): def setup_transition_create(request): - Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_CREATE]) + Permission.objects.check_permissions(request.user, [PERMISSION_TRANSITION_SETUP_CREATE]) redirect_url = reverse('setup_transition_list') if request.method == 'POST': @@ -437,7 +434,7 @@ def setup_transition_create(request): def setup_transition_edit(request, transition_pk): - Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT]) + Permission.objects.check_permissions(request.user, [PERMISSION_TRANSITION_SETUP_EDIT]) transition = get_object_or_404(Transition, pk=transition_pk) if request.method == 'POST': @@ -458,3 +455,57 @@ def setup_transition_edit(request, transition_pk): ], }, 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)) From 38426ed32f4ab2d05cf6ddc888daab4cbe9fc5cb Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 19 Mar 2012 01:12:16 -0400 Subject: [PATCH 40/52] Add the workflow state transition list and add views --- apps/workflows/__init__.py | 12 ++-- apps/workflows/forms.py | 15 +++- apps/workflows/models.py | 6 +- apps/workflows/urls.py | 7 +- apps/workflows/views.py | 139 +++++++++++++++++++++++++++++++++++-- 5 files changed, 165 insertions(+), 14 deletions(-) diff --git a/apps/workflows/__init__.py b/apps/workflows/__init__.py index 194b613727..7fbe25d8f3 100644 --- a/apps/workflows/__init__.py +++ b/apps/workflows/__init__.py @@ -20,9 +20,12 @@ setup_workflow_create_link = Link(text=_(u'create new workflow'), view='setup_wo 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 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 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 state'), view='setup_workflow_state_remove', args='workflow_state.pk', sprite='transmit_delete', 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_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]) @@ -54,6 +57,7 @@ bind_links([State, 'setup_state_list', 'setup_state_create'], [setup_state_creat 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_states_edit_link, setup_workflow_states_remove_link]) +bind_links([WorkflowState], [setup_workflow_state_transitions_list_link, setup_workflow_states_edit_link, setup_workflow_states_remove_link]) +bind_links([WorkflowState], [setup_workflow_state_transition_add_link], menu_name=u'sidebar') 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 index cc2ac01210..5179d9a3d6 100644 --- a/apps/workflows/forms.py +++ b/apps/workflows/forms.py @@ -3,7 +3,7 @@ from __future__ import absolute_import from django import forms from django.utils.translation import ugettext_lazy as _ -from .models import Workflow, State, Transition, WorkflowState +from .models import Workflow, State, Transition, WorkflowState, WorkflowStateTransition class WorkflowSetupForm(forms.ModelForm): @@ -30,3 +30,16 @@ class WorkflowStateSetupForm(forms.ModelForm): 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/models.py b/apps/workflows/models.py index 0359519553..5a755b010b 100644 --- a/apps/workflows/models.py +++ b/apps/workflows/models.py @@ -70,6 +70,10 @@ class WorkflowState(models.Model): #return '%s (%s)' % (self.label, self.workflow.label) return unicode(self.state) + @property + def transitions(self): + return self.workflowstatetransition_set + class Meta: verbose_name = _(u'workflow state') verbose_name_plural = _(u'workflows states') @@ -102,7 +106,7 @@ class WorkflowStateAbilityGrant(models.Model): class WorkflowStateTransition(models.Model): - workflow_state_source = models.ForeignKey(WorkflowState, related_name='workflow_state_transition_source', verbose_name=_(u'workflow state source')) + 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')) diff --git a/apps/workflows/urls.py b/apps/workflows/urls.py index f8e137e3b8..eb85c41b7a 100644 --- a/apps/workflows/urls.py +++ b/apps/workflows/urls.py @@ -5,11 +5,15 @@ urlpatterns = patterns('workflows.views', 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/create/$', 'setup_workflow_state_add', (), 'setup_workflow_state_add'), + 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/workflow/state/(?P\d+)/transition/list/$', 'setup_workflow_state_transitions_list', (), 'setup_workflow_state_transitions_list'), + url(r'^setup/workflow/state/(?P\d+)/transition/add/$', 'setup_workflow_state_transition_add', (), 'setup_workflow_state_transition_add'), + 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'), @@ -19,5 +23,4 @@ urlpatterns = patterns('workflows.views', url(r'^setup/transition/create/$', 'setup_transition_create', (), 'setup_transition_create'), url(r'^setup/transition/(?P\d+)/edit/$', 'setup_transition_edit', (), 'setup_transition_edit'), url(r'^setup/transition/(?P\d+)/delete/$', 'setup_transition_delete', (), 'setup_transition_delete'), - ) diff --git a/apps/workflows/views.py b/apps/workflows/views.py index d548078845..dc483c8ece 100644 --- a/apps/workflows/views.py +++ b/apps/workflows/views.py @@ -20,7 +20,8 @@ from common.utils import encapsulate from .models import Workflow, State, Transition, WorkflowState from .forms import (WorkflowSetupForm, StateSetupForm, - WorkflowStateSetupForm, TransitionSetupForm) + WorkflowStateSetupForm, TransitionSetupForm, + WorkflowStateTransitionSetupForm) from .permissions import (PERMISSION_WORKFLOW_SETUP_VIEW, PERMISSION_WORKFLOW_SETUP_CREATE, PERMISSION_WORKFLOW_SETUP_EDIT, PERMISSION_WORKFLOW_SETUP_DELETE, PERMISSION_STATE_SETUP_VIEW, @@ -230,9 +231,9 @@ def setup_workflow_state_remove(request, workflow_state_pk=None, workflow_state_ return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/')) try: - Permission.objects.check_permissions(request.user, [PERMISSION_STATE_SETUP_DELETE]) + Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT]) except PermissionDenied: - workflow_states = AccessEntry.objects.filter_objects_by_access(PERMISSION_STATE_SETUP_DELETE, request.user, workflow_states) + 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', '/'))) @@ -403,9 +404,6 @@ def setup_transition_list(request): 'object_list': Transition.objects.all(), 'title': _(u'transitions'), 'hide_link': True, - #'extra_columns': [ - # {'name': _(u'Initial state'), 'attribute': encapsulate(lambda transition: transition.initial_state or _(u'None'))}, - #], 'list_object_variable_name': 'transition', } @@ -509,3 +507,132 @@ def setup_transition_delete(request, transition_pk=None, transition_pk_list=None 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', + } + + 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_state_transition_edit(request, state_transition_pk): + Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT]) + state_transition = get_object_or_404(WorkflowState, pk=state_transition_pk) + redirect_url = reverse('setup_state_transitions_list', args=[state_transition.state.pk]) + + if request.method == 'POST': + form = WorkflowStateSetupForm(state=state_transition.state, instance=state_transition, 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(state=state_transition.state, instance=state_transition) + + return render_to_response('generic_form.html', { + 'title': _(u'edit worflow state'), + 'form': form, + 'state': state_transition.state, + 'state_transition': state_transition, + 'navigation_object_list': [ + {'object': 'state', 'name': _(u'state')}, + {'object': 'state_transition', 'name': _(u'state state')} + ], + }, 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)) +""" From 0ff0892b25c8069e1a0073719a9cc33ad087a805 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 19 Mar 2012 09:04:44 -0400 Subject: [PATCH 41/52] Remove Flattr button --- README.md | 1 - 1 file changed, 1 deletion(-) 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) From 55a6720a845e8c82667f3de2c89274e62a198b16 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 19 Mar 2012 12:03:51 -0400 Subject: [PATCH 42/52] Make sure only one variable and the correct variable's link are resolved for list items --- apps/navigation/api.py | 3 +- .../templatetags/navigation_tags.py | 33 ++++++++++++------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/apps/navigation/api.py b/apps/navigation/api.py index fc36decdc1..3e48e7a056 100644 --- a/apps/navigation/api.py +++ b/apps/navigation/api.py @@ -198,8 +198,7 @@ def register_multi_item_links(sources, links, menu_name=None): multi_object_navigation[menu_name][source]['links'].extend(links) -#TODO: new name: get_context_navigation_links, get_navigation_links_for_context -def get_context_object_navigation_links(context, menu_name=None, links_dict=link_binding): +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) diff --git a/apps/navigation/templatetags/navigation_tags.py b/apps/navigation/templatetags/navigation_tags.py index d09d71350e..aefcef42af 100644 --- a/apps/navigation/templatetags/navigation_tags.py +++ b/apps/navigation/templatetags/navigation_tags.py @@ -6,11 +6,11 @@ import logging from django.core.urlresolvers import reverse from django.template import (TemplateSyntaxError, Library, - Node, Variable) + Node, Variable, VariableDoesNotExist) from django.utils.translation import ugettext as _ from ..api import (link_binding, multi_object_navigation, - sidebar_templates, get_context_object_navigation_links) + sidebar_templates, get_context_navigation_links) from ..forms import MultiItemForm from ..utils import resolve_to_name, resolve_template_variable from .. import main_menu @@ -39,12 +39,12 @@ class GetNavigationLinks(Node): def render(self, context): menu_name = resolve_template_variable(context, self.menu_name) - context[self.var_name] = get_context_object_navigation_links(context, menu_name, links_dict=self.links_dict) + 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) @@ -58,13 +58,24 @@ 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) - - for object_reference, object_links in get_context_object_navigation_links(context).items(): - new_context.update({ - 'horizontal': True, - 'links': object_links - }) + 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 From 50ad0d9bf6b100dc7d6d9b376eb4c7f61c6a1b47 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Mon, 19 Mar 2012 16:41:34 -0400 Subject: [PATCH 43/52] Add the workflow state transition edit view --- apps/workflows/__init__.py | 9 ++++++--- apps/workflows/models.py | 2 +- apps/workflows/urls.py | 1 + apps/workflows/views.py | 34 ++++++++++++++++++++-------------- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/apps/workflows/__init__.py b/apps/workflows/__init__.py index 7fbe25d8f3..555950daeb 100644 --- a/apps/workflows/__init__.py +++ b/apps/workflows/__init__.py @@ -12,8 +12,8 @@ from .permissions import (PERMISSION_WORKFLOW_SETUP_VIEW, PERMISSION_STATE_SETUP_DELETE, PERMISSION_TRANSITION_SETUP_VIEW, PERMISSION_TRANSITION_SETUP_CREATE, PERMISSION_TRANSITION_SETUP_EDIT, PERMISSION_TRANSITION_SETUP_DELETE) -from .models import Workflow, State, Transition, WorkflowState - +from .models import (Workflow, State, Transition, WorkflowState, + WorkflowStateTransition) 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]) @@ -26,6 +26,7 @@ setup_workflow_states_remove_link = Link(text=_(u'remove workflow state'), view= 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]) @@ -39,7 +40,7 @@ setup_transition_delete_link = Link(text=_(u'delete'), view='setup_transition_de bind_links( [ - Workflow, State, Transition, + Workflow, State, Transition, WorkflowStateTransition, 'setup_workflow_list', 'setup_workflow_create', 'setup_state_list', 'setup_state_create', 'setup_transition_list', 'setup_transition_create', @@ -60,4 +61,6 @@ bind_links([Transition, 'setup_transition_list', 'setup_transition_create'], [se bind_links([WorkflowState], [setup_workflow_state_transitions_list_link, 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([WorkflowStateTransition], [setup_workflow_state_transition_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/models.py b/apps/workflows/models.py index 5a755b010b..55a3958402 100644 --- a/apps/workflows/models.py +++ b/apps/workflows/models.py @@ -67,7 +67,6 @@ class WorkflowState(models.Model): description = models.TextField(blank=True, verbose_name=_(u'description')) def __unicode__(self): - #return '%s (%s)' % (self.label, self.workflow.label) return unicode(self.state) @property @@ -75,6 +74,7 @@ class WorkflowState(models.Model): return self.workflowstatetransition_set class Meta: + #unique_together = ('workflow', 'state') verbose_name = _(u'workflow state') verbose_name_plural = _(u'workflows states') diff --git a/apps/workflows/urls.py b/apps/workflows/urls.py index eb85c41b7a..19a9dbcfd3 100644 --- a/apps/workflows/urls.py +++ b/apps/workflows/urls.py @@ -13,6 +13,7 @@ urlpatterns = patterns('workflows.views', url(r'^setup/workflow/state/(?P\d+)/transition/list/$', 'setup_workflow_state_transitions_list', (), 'setup_workflow_state_transitions_list'), url(r'^setup/workflow/state/(?P\d+)/transition/add/$', 'setup_workflow_state_transition_add', (), 'setup_workflow_state_transition_add'), + url(r'^setup/workflow/state/transition/(?P\d+)/edit/$', 'setup_workflow_state_transition_edit', (), 'setup_workflow_state_transition_edit'), url(r'^setup/state/list/$', 'setup_state_list', (), 'setup_state_list'), url(r'^setup/state/create/$', 'setup_state_create', (), 'setup_state_create'), diff --git a/apps/workflows/views.py b/apps/workflows/views.py index dc483c8ece..1373cfd8bc 100644 --- a/apps/workflows/views.py +++ b/apps/workflows/views.py @@ -525,6 +525,9 @@ def setup_workflow_state_transitions_list(request, workflow_state_pk): {'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, @@ -556,33 +559,36 @@ def setup_workflow_state_transition_add(request, workflow_state_pk): ], }, context_instance=RequestContext(request)) -""" -def setup_state_transition_edit(request, state_transition_pk): + +def setup_workflow_state_transition_edit(request, work_state_transition_pk): Permission.objects.check_permissions(request.user, [PERMISSION_WORKFLOW_SETUP_EDIT]) - state_transition = get_object_or_404(WorkflowState, pk=state_transition_pk) - redirect_url = reverse('setup_state_transitions_list', args=[state_transition.state.pk]) + 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 = WorkflowStateSetupForm(state=state_transition.state, instance=state_transition, data=request.POST) + form = WorkflowStateTransitionSetupForm(workflow_state=workflow_state_transition.workflow_state_source, instance=workflow_state_transition, data=request.POST) if form.is_valid(): - state = form.save() - messages.success(request, _(u'worflow state edited succesfully.')) + workflow_state_transition = form.save() + messages.success(request, _(u'worflow state transition edited succesfully.')) return HttpResponseRedirect(redirect_url) else: - form = WorkflowStateSetupForm(state=state_transition.state, instance=state_transition) + 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'), + 'title': _(u'edit worflow state transition: %s') % workflow_state_transition, 'form': form, - 'state': state_transition.state, - 'state_transition': state_transition, + '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': 'state', 'name': _(u'state')}, - {'object': 'state_transition', 'name': _(u'state state')} + {'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 From ebd5016990a283f11e7787748704db07b12e0bfa Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 27 Mar 2012 23:10:26 -0400 Subject: [PATCH 44/52] Simplify auto admin creation code --- apps/common/__init__.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/common/__init__.py b/apps/common/__init__.py index 7ec60b2d04..a92a834217 100644 --- a/apps/common/__init__.py +++ b/apps/common/__init__.py @@ -10,6 +10,8 @@ from django.db.models.signals import post_syncdb 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) from .conf import settings as common_settings from .utils import validate_path @@ -42,18 +44,16 @@ def create_superuser(sender, **kwargs): Create our own admin super user automatically. """ - if common_settings.AUTO_CREATE_ADMIN: - USERNAME = common_settings.AUTO_ADMIN_USERNAME - PASSWORD = common_settings.AUTO_ADMIN_PASSWORD + if AUTO_CREATE_ADMIN: try: - auth_models.User.objects.get(username=USERNAME) + auth_models.User.objects.get(username=AUTO_ADMIN_USERNAME) except auth_models.User.DoesNotExist: print '*' * 80 - print 'Creating super admin user -- login: %s, password: %s' % (USERNAME, PASSWORD) + print 'Creating super admin user -- login: %s, password: %s' % (AUTO_ADMIN_USERNAME, AUTO_ADMIN_PASSWORD) print '*' * 80 - assert auth_models.User.objects.create_superuser(USERNAME, 'x@x.com', PASSWORD) + assert auth_models.User.objects.create_superuser(AUTO_ADMIN_USERNAME, 'x@x.com', AUTO_ADMIN_PASSWORD) else: - print 'Super admin user already exists. -- login: %s, password: %s' % (USERNAME, PASSWORD) + print 'Super admin user already exists. -- login: %s' % AUTO_ADMIN_USERNAME -if (validate_path(common_settings.TEMPORARY_DIRECTORY) == False) or (not common_settings.TEMPORARY_DIRECTORY): +if (validate_path(TEMPORARY_DIRECTORY) == False) or (not TEMPORARY_DIRECTORY): setattr(common_settings, 'TEMPORARY_DIRECTORY', tempfile.mkdtemp()) From 8425cd6f7e04efcc955fec7a2c627a2f07510e8e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 29 Mar 2012 23:43:51 -0400 Subject: [PATCH 45/52] Properly initialize ResolvedLink class --- apps/navigation/api.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/navigation/api.py b/apps/navigation/api.py index 3e48e7a056..efdc441cfa 100644 --- a/apps/navigation/api.py +++ b/apps/navigation/api.py @@ -8,8 +8,8 @@ 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 -from django.utils.http import urlencode +from django.utils.http import urlquote, urlencode +from django.utils.translation import ugettext_lazy as _ from elementtree.ElementTree import SubElement @@ -28,6 +28,8 @@ logger = logging.getLogger(__name__) class ResolvedLink(object): active = False + url = '#' + text = _('Unnamed link') class Link(object): @@ -67,12 +69,16 @@ class Link(object): 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: condition_result = True + logger.debug('condition_result: %s', condition_result) + if condition_result: resolved_link = ResolvedLink() resolved_link.text = self.text From 41facf623a4fbd822185aeb63d8c52124b30936a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 29 Mar 2012 23:44:21 -0400 Subject: [PATCH 46/52] Only try to render resolved links --- apps/navigation/widgets.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/navigation/widgets.py b/apps/navigation/widgets.py index 2370d4681b..361daf77e7 100644 --- a/apps/navigation/widgets.py +++ b/apps/navigation/widgets.py @@ -24,10 +24,13 @@ def button_navigation_widget(request, link): def render_widget(request, link): context = RequestContext(request) resolved_link = link.resolve(context) - return mark_safe(u'' % { - 'url': resolved_link.url, - 'icon': getattr(resolved_link, 'icon', 'link_button.png'), - 'static_url': settings.STATIC_URL, - 'string': capfirst(resolved_link.text), - 'image_alt': _(u'icon'), - }) + if resolved_link: + return mark_safe(u'' % { + 'url': resolved_link.url, + 'icon': getattr(resolved_link, 'icon', 'link_button.png'), + 'static_url': settings.STATIC_URL, + 'string': capfirst(resolved_link.text), + 'image_alt': _(u'icon'), + }) + else: + return u'' From afac6e76670ed2e6c705d5f4f16e5c968ee5fa40 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 29 Mar 2012 23:45:04 -0400 Subject: [PATCH 47/52] Display message on empty horizontal list --- .../templates/generic_list_horizontal_subtemplate.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/common/templates/generic_list_horizontal_subtemplate.html b/apps/common/templates/generic_list_horizontal_subtemplate.html index 852cf0a5b4..43b3211d89 100644 --- a/apps/common/templates/generic_list_horizontal_subtemplate.html +++ b/apps/common/templates/generic_list_horizontal_subtemplate.html @@ -62,7 +62,11 @@ From 0717f346b070dbebc430298bbf8345fc3448ff36 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Thu, 29 Mar 2012 23:45:24 -0400 Subject: [PATCH 48/52] Remove empty items from project_setup and project_tools list of objects --- apps/project_setup/views.py | 3 +++ apps/project_tools/views.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/apps/project_setup/views.py b/apps/project_setup/views.py index 1b38bceeb4..cdb8d780ad 100644 --- a/apps/project_setup/views.py +++ b/apps/project_setup/views.py @@ -15,5 +15,8 @@ def setup_list(request): '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/views.py b/apps/project_tools/views.py index e3544b5fd3..033049b50d 100644 --- a/apps/project_tools/views.py +++ b/apps/project_tools/views.py @@ -15,5 +15,8 @@ def tools_list(request): '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)) From a5280870c250b3f962a9f93baafdd4204b86f88c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 30 Mar 2012 03:23:04 -0400 Subject: [PATCH 49/52] Removed transitions and move to a Node based workflow element --- apps/workflows/__init__.py | 38 +-- apps/workflows/forms.py | 49 +++- apps/workflows/literals.py | 10 + ...rant__del_workflowstatetransition__del_.py | 231 ++++++++++++++++++ apps/workflows/models.py | 217 ++++++++++++++-- apps/workflows/permissions.py | 8 +- apps/workflows/urls.py | 12 +- apps/workflows/views.py | 69 +++++- 8 files changed, 559 insertions(+), 75 deletions(-) create mode 100644 apps/workflows/migrations/0002_auto__del_workflowstateabilitygrant__del_workflowstatetransition__del_.py diff --git a/apps/workflows/__init__.py b/apps/workflows/__init__.py index 555950daeb..d4a714a21e 100644 --- a/apps/workflows/__init__.py +++ b/apps/workflows/__init__.py @@ -9,11 +9,9 @@ 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, PERMISSION_TRANSITION_SETUP_VIEW, - PERMISSION_TRANSITION_SETUP_CREATE, PERMISSION_TRANSITION_SETUP_EDIT, - PERMISSION_TRANSITION_SETUP_DELETE) -from .models import (Workflow, State, Transition, WorkflowState, - WorkflowStateTransition) + 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]) @@ -33,34 +31,38 @@ setup_state_create_link = Link(text=_(u'create new state'), view='setup_state_cr 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_transition_list_link = Link(text=_(u'transition list'), view='setup_transition_list', sprite='chart_line', permissions=[PERMISSION_TRANSITION_SETUP_VIEW]) -setup_transition_create_link = Link(text=_(u'create new transition'), view='setup_transition_create', sprite='chart_line_add', permissions=[PERMISSION_TRANSITION_SETUP_CREATE]) -setup_transition_edit_link = Link(text=_(u'edit'), view='setup_transition_edit', args='transition.pk', sprite='chart_line', permissions=[PERMISSION_TRANSITION_SETUP_EDIT]) -setup_transition_delete_link = Link(text=_(u'delete'), view='setup_transition_delete', args='transition.pk', sprite='chart_line_delete', permissions=[PERMISSION_TRANSITION_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, Transition, WorkflowStateTransition, + Workflow, State, 'setup_workflow_list', 'setup_workflow_create', 'setup_state_list', 'setup_state_create', - 'setup_transition_list', 'setup_transition_create', + #'setup_transition_list', 'setup_transition_create', + 'setup_transition_create', ], [ - setup_workflow_list_link, setup_state_list_link, setup_transition_list_link + setup_workflow_list_link, setup_state_list_link#, setup_transition_list_link ], menu_name=u'form_header') -bind_links([Workflow], [setup_workflow_states_list_link, setup_workflow_edit_link, setup_workflow_delete_link]) +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([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_state_transition_add_link], menu_name=u'sidebar') +#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([WorkflowStateTransition], [setup_workflow_state_transition_edit_link])#, setup_transition_delete_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 index 5179d9a3d6..5f0e897ebd 100644 --- a/apps/workflows/forms.py +++ b/apps/workflows/forms.py @@ -3,11 +3,26 @@ from __future__ import absolute_import from django import forms from django.utils.translation import ugettext_lazy as _ -from .models import Workflow, State, Transition, WorkflowState, WorkflowStateTransition +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 @@ -27,19 +42,29 @@ class WorkflowStateSetupForm(forms.ModelForm): model = WorkflowState -class TransitionSetupForm(forms.ModelForm): - class Meta: - model = Transition - - -class WorkflowStateTransitionSetupForm(forms.ModelForm): +class WorkflowNodeSetupForm(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() + 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 = WorkflowStateTransition + 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 index 8811669442..da3e4aeb23 100644 --- a/apps/workflows/literals.py +++ b/apps/workflows/literals.py @@ -7,3 +7,13 @@ 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/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/models.py b/apps/workflows/models.py index 55a3958402..a927d291be 100644 --- a/apps/workflows/models.py +++ b/apps/workflows/models.py @@ -4,11 +4,14 @@ 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')) @@ -24,44 +27,149 @@ class Ability(models.Model): 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 State(models.Model): + + +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 '%s (%s)' % (self.name, self.workflow.name) 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') + verbose_name_plural = _(u'starts') -class Transition(models.Model): +class End(Node): + class Meta(Node.Meta): + verbose_name = _(u'start') + verbose_name_plural = _(u'starts') + + +''' +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 '%s (%s)' % (self.name, self.workflow.name) return self.label class Meta: - verbose_name = _(u'transition') - verbose_name_plural = _(u'transitions') - - + 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')) @@ -69,17 +177,33 @@ class WorkflowState(models.Model): def __unicode__(self): return unicode(self.state) - @property - def transitions(self): - return self.workflowstatetransition_set - class Meta: - #unique_together = ('workflow', 'state') + 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) -class WorkflowStateAbilityGrant(models.Model): + #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) @@ -133,16 +257,69 @@ class WorkflowStateTransitionAbility(models.Model): verbose_name = _(u'transition') verbose_name_plural = _(u'transitions') - +""" class WorkflowInstance(models.Model): - workflow = models.ForeignKey(Workflow, verbose_name = _(u'workflow')) + 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') - workflow_state = models.ForeignKey(WorkflowState, related_name='workflow_instance_state', verbose_name=_(u'state')) 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: - unique_together = ('content_type', 'object_id', 'workflow') + 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 WorkflowInstanceActiveState(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 index 5f27a47854..be443bda66 100644 --- a/apps/workflows/permissions.py +++ b/apps/workflows/permissions.py @@ -16,8 +16,8 @@ PERMISSION_STATE_SETUP_CREATE = Permission.objects.register(namespace, 'state_se 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')) +#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/urls.py b/apps/workflows/urls.py index 19a9dbcfd3..29b54ab972 100644 --- a/apps/workflows/urls.py +++ b/apps/workflows/urls.py @@ -11,17 +11,11 @@ urlpatterns = patterns('workflows.views', 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/workflow/state/(?P\d+)/transition/list/$', 'setup_workflow_state_transitions_list', (), 'setup_workflow_state_transitions_list'), - url(r'^setup/workflow/state/(?P\d+)/transition/add/$', 'setup_workflow_state_transition_add', (), 'setup_workflow_state_transition_add'), - url(r'^setup/workflow/state/transition/(?P\d+)/edit/$', 'setup_workflow_state_transition_edit', (), 'setup_workflow_state_transition_edit'), - 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/transition/list/$', 'setup_transition_list', (), 'setup_transition_list'), - url(r'^setup/transition/create/$', 'setup_transition_create', (), 'setup_transition_create'), - url(r'^setup/transition/(?P\d+)/edit/$', 'setup_transition_edit', (), 'setup_transition_edit'), - url(r'^setup/transition/(?P\d+)/delete/$', 'setup_transition_delete', (), 'setup_transition_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 index 1373cfd8bc..33c5a778b9 100644 --- a/apps/workflows/views.py +++ b/apps/workflows/views.py @@ -18,18 +18,14 @@ from common.utils import encapsulate #from common.widgets import two_state_template #from acls.models import AccessEntry -from .models import Workflow, State, Transition, WorkflowState +from .models import Workflow, State, WorkflowState, WorkflowNode from .forms import (WorkflowSetupForm, StateSetupForm, - WorkflowStateSetupForm, TransitionSetupForm, - WorkflowStateTransitionSetupForm) + 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, PERMISSION_TRANSITION_SETUP_VIEW, - PERMISSION_TRANSITION_SETUP_CREATE, PERMISSION_TRANSITION_SETUP_EDIT, - PERMISSION_TRANSITION_SETUP_DELETE) - + PERMISSION_STATE_SETUP_DELETE) logger = logging.getLogger(__name__) @@ -207,7 +203,7 @@ def setup_workflow_state_edit(request, workflow_state_pk): form = WorkflowStateSetupForm(workflow=workflow_state.workflow, instance=workflow_state) return render_to_response('generic_form.html', { - 'title': _(u'edit worflow state'), + 'title': _(u'edit worflow state: %s') % workflow_state, 'form': form, 'workflow': workflow_state.workflow, 'workflow_state': workflow_state, @@ -272,6 +268,54 @@ def setup_workflow_state_remove(request, workflow_state_pk=None, workflow_state_ 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) @@ -289,6 +333,7 @@ def setup_workflow_transition_list(request, state_workflow_pk): 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]) @@ -395,7 +440,7 @@ def setup_state_delete(request, state_pk=None, state_pk_list=None): 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]) @@ -507,8 +552,8 @@ def setup_transition_delete(request, transition_pk=None, transition_pk_list=None 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]) @@ -587,7 +632,7 @@ def setup_workflow_state_transition_edit(request, work_state_transition_pk): ], '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 From 085d32e214e1741bca69573a28558ff2f0c9ad5d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 6 Apr 2012 01:06:35 -0400 Subject: [PATCH 50/52] Don't install python-gnupg from upstream but from my github fork --- requirements/production.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/production.txt b/requirements/production.txt index 998045debd..1a51f97722 100644 --- a/requirements/production.txt +++ b/requirements/production.txt @@ -14,7 +14,7 @@ django-compressor==1.1.1 -e git://github.com/rosarior/django-sendfile.git#egg=django-sendfile djangorestframework==0.2.3 South==0.7.3 -python-gnupg==0.2.8 +https://github.com/rosarior/python-gnupg/zipball/0.2.8 python-hkp==0.1.3 requests==0.10.1 elementtree==1.2.7-20070827-preview From 80488d0f96b3fabceadd06663938a80a1980387a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 23 May 2012 00:14:56 -0400 Subject: [PATCH 51/52] Rename model Workflow state model --- apps/workflows/models.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/workflows/models.py b/apps/workflows/models.py index a927d291be..509e317e3e 100644 --- a/apps/workflows/models.py +++ b/apps/workflows/models.py @@ -125,14 +125,14 @@ class Start(Node): return self.next_node class Meta(Node.Meta): - verbose_name = _(u'start') - verbose_name_plural = _(u'starts') + verbose_name = _(u'start node') + verbose_name_plural = _(u'start nodes') class End(Node): class Meta(Node.Meta): - verbose_name = _(u'start') - verbose_name_plural = _(u'starts') + verbose_name = _(u'end node') + verbose_name_plural = _(u'end nodes') ''' @@ -308,7 +308,7 @@ class WorkflowInstanceActiveNode(models.Model): verbose_name_plural = _(u'workflow instances active nodes') -class WorkflowInstanceActiveState(models.Model): +class WorkflowInstanceState(models.Model): """ This class holds the active state for the workflow instance """ From 15156b326bd619e4046a12af29e9ff329eef5bea Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Wed, 23 May 2012 00:15:20 -0400 Subject: [PATCH 52/52] Remark all state setup permissions, add workflow execution permission --- apps/workflows/permissions.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/workflows/permissions.py b/apps/workflows/permissions.py index be443bda66..eaece09a8a 100644 --- a/apps/workflows/permissions.py +++ b/apps/workflows/permissions.py @@ -11,10 +11,12 @@ PERMISSION_WORKFLOW_SETUP_CREATE = Permission.objects.register(namespace, 'workf 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_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_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'))