diff --git a/CHANGES.rst b/CHANGES.rst index 4e21113..4ce934a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,16 @@ Changelog 2.1.3 (unreleased) ------------------ +- Python 3 compatibility. + [thet] + +- Code cleanup: + - Remove bootstrap.py + - Format code according to Plone standards: black, isort. + Format zcml using zpretty. + Format xml using zpretty. + [thet] + - update to build on Plone 5.1 latest [tkimnguyen] diff --git a/base.cfg b/base.cfg index 2c001d0..21ce67f 100644 --- a/base.cfg +++ b/base.cfg @@ -23,7 +23,7 @@ eggs = plone.app.workflowmanager [code-analysis] recipe = plone.recipe.codeanalysis directory = ${buildout:directory}/src/plone/app/workflowmanager/ -flake8-exclude = bootstrap.py,bootstrap-buildout.py,docs,*.egg.,omelette +flake8-exclude = docs,*.egg.,omelette flake8-max-complexity = 15 diff --git a/bootstrap.py b/bootstrap.py deleted file mode 100644 index daeeef5..0000000 --- a/bootstrap.py +++ /dev/null @@ -1,127 +0,0 @@ -############################################################################## -# -# Copyright (c) 2006 Zope Foundation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Bootstrap a buildout-based project - -Simply run this script in a directory containing a buildout.cfg. -The script accepts buildout command-line options, so you can -use the -c option to specify an alternate configuration file. - -$Id$ -""" - -import os, shutil, sys, tempfile, urllib2 -from optparse import OptionParser - -tmpeggs = tempfile.mkdtemp() - -is_jython = sys.platform.startswith('java') - -# parsing arguments -parser = OptionParser( - 'This is a custom version of the zc.buildout %prog script. It is ' - 'intended to meet a temporary need if you encounter problems with ' - 'the zc.buildout 1.5 release.') -parser.add_option("-v", "--version", dest="version", default='1.4.4', - help='Use a specific zc.buildout version. *This ' - 'bootstrap script defaults to ' - '1.4.4, unlike usual buildpout bootstrap scripts.*') -parser.add_option("-d", "--distribute", - action="store_true", dest="distribute", default=False, - help="Use Disribute rather than Setuptools.") - -parser.add_option("-c", None, action="store", dest="config_file", - help=("Specify the path to the buildout configuration " - "file to be used.")) - -options, args = parser.parse_args() - -# if -c was provided, we push it back into args for buildout' main function -if options.config_file is not None: - args += ['-c', options.config_file] - -if options.version is not None: - VERSION = '==%s' % options.version -else: - VERSION = '' - -USE_DISTRIBUTE = options.distribute -args = args + ['bootstrap'] - -to_reload = False -try: - import pkg_resources - if not hasattr(pkg_resources, '_distribute'): - to_reload = True - raise ImportError -except ImportError: - ez = {} - if USE_DISTRIBUTE: - exec urllib2.urlopen('http://python-distribute.org/distribute_setup.py' - ).read() in ez - ez['use_setuptools'](to_dir=tmpeggs, download_delay=0, no_fake=True) - else: - exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py' - ).read() in ez - ez['use_setuptools'](to_dir=tmpeggs, download_delay=0) - - if to_reload: - reload(pkg_resources) - else: - import pkg_resources - -if sys.platform == 'win32': - def quote(c): - if ' ' in c: - return '"%s"' % c # work around spawn lamosity on windows - else: - return c -else: - def quote (c): - return c - -ws = pkg_resources.working_set - -if USE_DISTRIBUTE: - requirement = 'distribute' -else: - requirement = 'setuptools' - -env = dict(os.environ, - PYTHONPATH= - ws.find(pkg_resources.Requirement.parse(requirement)).location - ) - -cmd = [quote(sys.executable), - '-c', - quote('from setuptools.command.easy_install import main; main()'), - '-mqNxd', - quote(tmpeggs)] - -if 'bootstrap-testing-find-links' in os.environ: - cmd.extend(['-f', os.environ['bootstrap-testing-find-links']]) - -cmd.append('zc.buildout' + VERSION) - -if is_jython: - import subprocess - exitcode = subprocess.Popen(cmd, env=env).wait() -else: # Windows prefers this, apparently; otherwise we would prefer subprocess - exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env])) -assert exitcode == 0 - -ws.add_entry(tmpeggs) -ws.require('zc.buildout' + VERSION) -import zc.buildout.buildout -zc.buildout.buildout.main(args) -shutil.rmtree(tmpeggs) diff --git a/setup.py b/setup.py index 4a4ed1b..50c91f5 100644 --- a/setup.py +++ b/setup.py @@ -1,58 +1,58 @@ from setuptools import find_packages from setuptools import setup -version = '2.1.3.dev0' -setup(name='plone.app.workflowmanager', - version=version, - description="A workflow manager for Plone", - long_description=( - open("README.rst").read() + "\n" + - open("CHANGES.rst").read() - ), - # Get more strings from https://pypi.python.org/pypi?%3Aaction=list_classifiers - classifiers=[ - "Framework :: Plone", - "Framework :: Plone :: 4.3", - "Framework :: Plone :: 5.0", - "Framework :: Plone :: 5.1", - "Intended Audience :: Customer Service", - "Intended Audience :: Developers", - "License :: OSI Approved :: GNU General Public License (GPL)", - "Operating System :: OS Independent", - "Programming Language :: Other Scripting Engines", - "Programming Language :: Python", - "Topic :: Internet :: WWW/HTTP :: Site Management", - "Topic :: Software Development :: Libraries :: Python Modules", - ], - keywords='plone workflow manager gui', - author='Nathan Van Gheem', - author_email='nguyen@plone.org', - url='https://github.com/plone/plone.app.workflowmanager', - license='GPL', - packages=find_packages('src'), - package_dir={'': 'src'}, - namespace_packages=['plone', 'plone.app'], - include_package_data=True, - zip_safe=False, - install_requires=[ - 'Plone', - 'setuptools', - 'plone.api', - 'plone.app.jquery>=1.7', - 'plone.app.jquerytools', - ], - extras_require={ - 'test': [ - 'plone.app.testing', - 'plone.app.jquerytools', - 'plone.app.robotframework', - 'interlude', - 'unittest2', - ] - }, - entry_points=""" +version = "2.1.3.dev0" + +setup( + name="plone.app.workflowmanager", + version=version, + description="A workflow manager for Plone", + long_description=(open("README.rst").read() + "\n" + open("CHANGES.rst").read()), + # Get more strings from https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + "Framework :: Plone", + "Framework :: Plone :: 4.3", + "Framework :: Plone :: 5.0", + "Framework :: Plone :: 5.1", + "Framework :: Plone :: 5.2", + "Intended Audience :: Customer Service", + "Intended Audience :: Developers", + "License :: OSI Approved :: GNU General Public License (GPL)", + "Operating System :: OS Independent", + "Programming Language :: Other Scripting Engines", + "Programming Language :: Python", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Topic :: Internet :: WWW/HTTP :: Site Management", + "Topic :: Software Development :: Libraries :: Python Modules", + ], + keywords="plone workflow manager gui", + author="Nathan Van Gheem", + author_email="nguyen@plone.org", + url="https://github.com/plone/plone.app.workflowmanager", + license="GPL", + packages=find_packages("src"), + package_dir={"": "src"}, + namespace_packages=["plone", "plone.app"], + include_package_data=True, + zip_safe=False, + install_requires=[ + "Plone", + "setuptools", + "plone.api", + ], + extras_require={ + "test": [ + "plone.app.testing", + "plone.app.robotframework", + "interlude", + ] + }, + entry_points=""" [z3c.autoinclude.plugin] target = plone """, - ) +) diff --git a/src/plone/__init__.py b/src/plone/__init__.py index f48ad10..05f0beb 100644 --- a/src/plone/__init__.py +++ b/src/plone/__init__.py @@ -1,6 +1,7 @@ # See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages try: - __import__('pkg_resources').declare_namespace(__name__) + __import__("pkg_resources").declare_namespace(__name__) except ImportError: from pkgutil import extend_path + __path__ = extend_path(__path__, __name__) diff --git a/src/plone/app/__init__.py b/src/plone/app/__init__.py index f48ad10..05f0beb 100644 --- a/src/plone/app/__init__.py +++ b/src/plone/app/__init__.py @@ -1,6 +1,7 @@ # See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages try: - __import__('pkg_resources').declare_namespace(__name__) + __import__("pkg_resources").declare_namespace(__name__) except ImportError: from pkgutil import extend_path + __path__ = extend_path(__path__, __name__) diff --git a/src/plone/app/workflowmanager/__init__.py b/src/plone/app/workflowmanager/__init__.py index c32d387..f6f961a 100644 --- a/src/plone/app/workflowmanager/__init__.py +++ b/src/plone/app/workflowmanager/__init__.py @@ -1,3 +1,4 @@ -# from zope.i18nmessageid.message import MessageFactory -WMMessageFactory = MessageFactory('plone.app.workflowmanager') \ No newline at end of file + + +WMMessageFactory = MessageFactory("plone.app.workflowmanager") diff --git a/src/plone/app/workflowmanager/actionmanager.py b/src/plone/app/workflowmanager/actionmanager.py index 6d7f022..b3876c7 100644 --- a/src/plone/app/workflowmanager/actionmanager.py +++ b/src/plone/app/workflowmanager/actionmanager.py @@ -1,23 +1,23 @@ -from zope.component import queryUtility - -from plone.memoize.instance import memoize -from plone.contentrules.engine.interfaces import IRuleStorage -from plone.contentrules.engine.interfaces import IRuleAssignmentManager -from plone.app.contentrules.conditions.wftransition import \ - WorkflowTransitionCondition +from plone.app.contentrules.conditions.wftransition import WorkflowTransitionCondition +from plone.app.contentrules.rule import get_assignments +from plone.app.contentrules.rule import Rule +from plone.app.workflowmanager.utils import generateRuleName +from plone.app.workflowmanager.utils import generateRuleNameOld from plone.contentrules.engine import utils -from plone.app.contentrules.rule import Rule, get_assignments from plone.contentrules.engine.assignments import RuleAssignment +from plone.contentrules.engine.interfaces import IRuleAssignmentManager +from plone.contentrules.engine.interfaces import IRuleStorage +from plone.memoize.instance import memoize from Products.CMFCore.interfaces._events import IActionSucceededEvent from Products.CMFCore.utils import getToolByName -from plone.app.workflowmanager.utils import generateRuleName, generateRuleNameOld - +from zope.component import queryUtility from zope.i18nmessageid import MessageFactory + + _ = MessageFactory(u"plone") class RuleAdapter(object): - def __init__(self, rule, transition): self.rule = rule self.transition = transition @@ -25,7 +25,7 @@ def __init__(self, rule, transition): @property @memoize def portal(self): - return getToolByName(self.transition, 'portal_url').getPortalObject() + return getToolByName(self.transition, "portal_url").getPortalObject() def activate(self): """ @@ -39,9 +39,10 @@ def activate(self): self.rule.event = IActionSucceededEvent assignable = IRuleAssignmentManager(self.portal) - path = '/'.join(self.portal.getPhysicalPath()) - assignable[self.rule.__name__] = RuleAssignment(self.rule.id, - enabled=True, bubbles=True) + path = "/".join(self.portal.getPhysicalPath()) + assignable[self.rule.__name__] = RuleAssignment( + self.rule.id, enabled=True, bubbles=True + ) assignments = get_assignments(self.rule) if not path in assignments: assignments.insert(path) @@ -57,10 +58,11 @@ def action_index(self, action): return self.rule.actions.index(action) def action_url(self, action): - return '%s/%s/++action++%d/edit' % ( + return "%s/%s/++action++%d/edit" % ( self.portal.absolute_url(), self.rule.id, - self.action_index(action), ) + self.action_index(action), + ) def delete_action(self, index): self.rule.actions.remove(self.rule.actions[index]) @@ -71,7 +73,6 @@ def actions(self): class ActionManager(object): - def get_rule(self, transition): rulename = generateRuleName(transition) rulename_old = generateRuleNameOld(transition) @@ -87,11 +88,13 @@ def create(self, transition): rule_id = generateRuleName(transition) r = Rule() r.title = _(u"%s transition content rule") % transition.id - r.description = _(u"This content rule was automatically created " - u"the workflow manager to create actions on " - u"workflow events. If you want the behavior to " - u"work as expected, do not modify this out of " - u"the workflow manager.") + r.description = _( + u"This content rule was automatically created " + u"the workflow manager to create actions on " + u"workflow events. If you want the behavior to " + u"work as expected, do not modify this out of " + u"the workflow manager." + ) self.storage[rule_id] = r rule = RuleAdapter(r, transition) rule.activate() diff --git a/src/plone/app/workflowmanager/browser/actions.py b/src/plone/app/workflowmanager/browser/actions.py index f45121e..53d2f0b 100644 --- a/src/plone/app/workflowmanager/browser/actions.py +++ b/src/plone/app/workflowmanager/browser/actions.py @@ -1,27 +1,31 @@ -from controlpanel import Base -from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile +from .controlpanel import Base from plone.app.contentrules.rule import Rule -from plone.app.workflowmanager.actionmanager import RuleAdapter, ActionManager -from urllib import urlencode -from zope.i18nmessageid import MessageFactory +from plone.app.workflowmanager.actionmanager import ActionManager +from plone.app.workflowmanager.actionmanager import RuleAdapter from plone.app.workflowmanager.utils import generateRuleName +from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile +from six.moves.urllib.parse import urlencode +from zope.i18nmessageid import MessageFactory + + _ = MessageFactory(u"plone") class DeleteActionView(Base): - template = ViewPageTemplateFile('templates/delete-action.pt') + template = ViewPageTemplateFile("templates/delete-action.pt") def __call__(self): self.errors = {} - if self.request.get('form.actions.delete', False): + if self.request.get("form.actions.delete", False): self.authorize() rule = self.actions.get_rule(self.selected_transition) - rule.delete_action(int(self.request.get('action_index'))) + rule.delete_action(int(self.request.get("action_index"))) return self.handle_response( - message=_(u"Action has been deleted successfully.")) + message=_(u"Action has been deleted successfully.") + ) - elif self.request.get('form.actions.cancel', False): + elif self.request.get("form.actions.cancel", False): return self.handle_response() else: return self.handle_response(tmpl=self.template) @@ -29,20 +33,19 @@ def __call__(self): class AddActionView(Base): - template = ViewPageTemplateFile('templates/add-action.pt') + template = ViewPageTemplateFile("templates/add-action.pt") def __call__(self): self.errors = {} - if self.request.get('form.actions.add', False): + if self.request.get("form.actions.add", False): self.authorize() am = ActionManager() rule = am.get_rule(self.selected_transition) if rule is None: rule_id = generateRuleName(self.selected_transition) r = Rule() - r.title = u"%s transition content rule" % ( - self.selected_transition.id) + r.title = u"%s transition content rule" % (self.selected_transition.id) r.description = """This content rule was automatically created by the workflow manager to support actions on workflow transitions. If you want the behavior to work as expected, do not modify this outside of the workflow @@ -51,12 +54,14 @@ def __call__(self): rule = RuleAdapter(r, self.selected_transition) rule.activate() - editurl = '%s/%s/+action' % (self.portal.absolute_url(), rule.id) - data = urlencode({ - ':action': self.request.get('action-type', - 'plone.actions.Mail'), - 'form.button.AddAction': 'Add'}) + editurl = "%s/%s/+action" % (self.portal.absolute_url(), rule.id) + data = urlencode( + { + ":action": self.request.get("action-type", "plone.actions.Mail"), + "form.button.AddAction": "Add", + } + ) - return self.handle_response(load=editurl + '?' + data) + return self.handle_response(load=editurl + "?" + data) else: return self.handle_response(tmpl=self.template) diff --git a/src/plone/app/workflowmanager/browser/configure.zcml b/src/plone/app/workflowmanager/browser/configure.zcml index c028acd..841a16d 100644 --- a/src/plone/app/workflowmanager/browser/configure.zcml +++ b/src/plone/app/workflowmanager/browser/configure.zcml @@ -2,197 +2,205 @@ xmlns="http://namespaces.zope.org/zope" xmlns:browser="http://namespaces.zope.org/browser" xmlns:zcml="http://namespaces.zope.org/zcml" - i18n_domain="plone.app.workflowmanager"> - - - - - - - - + i18n_domain="plone.app.workflowmanager" + > + + + name="workflowmanager-content" + attribute="render_content_template" + /> + name="workflowmanage-item" + attribute="retrieve_item" + /> - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + class=".workflow.UpdateSecuritySettings" + /> - + + + + + + - - - - - - - - - - - - - - - - - + class=".actions.DeleteActionView" + /> + + + + + + + + + + + + + + + + + diff --git a/src/plone/app/workflowmanager/browser/controlpanel.py b/src/plone/app/workflowmanager/browser/controlpanel.py index 30eeab3..3a57a41 100644 --- a/src/plone/app/workflowmanager/browser/controlpanel.py +++ b/src/plone/app/workflowmanager/browser/controlpanel.py @@ -1,39 +1,45 @@ -from urllib import urlencode -try: - import json -except: - import simplejson as json - -from Acquisition import aq_get from AccessControl import Unauthorized +from Acquisition import aq_get +from plone.app.workflowmanager import WMMessageFactory as _ +from plone.app.workflowmanager.actionmanager import ActionManager +from plone.app.workflowmanager.browser.layout import GraphLayout +from plone.app.workflowmanager.graphviz import HAS_GRAPHVIZ +from plone.app.workflowmanager.permissions import allowed_guard_permissions +from plone.app.workflowmanager.permissions import managed_permissions +from plone.memoize.view import memoize +from Products.CMFCore.utils import getToolByName from Products.Five.browser import BrowserView from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile - -from zope.component import getUtility +from six.moves.urllib.parse import urlencode from zope.component import getMultiAdapter +from zope.component import getUtility from zope.schema.interfaces import IVocabularyFactory + import zope.i18n +import six + + +try: + import json +except: + import simplejson as json + + -from Products.CMFCore.utils import getToolByName -from plone.memoize.view import memoize -from plone.app.workflowmanager.browser.layout import GraphLayout -from plone.app.workflowmanager.permissions import managed_permissions -from plone.app.workflowmanager.permissions import allowed_guard_permissions -from plone.app.workflowmanager.graphviz import HAS_GRAPHVIZ -from plone.app.workflowmanager.actionmanager import ActionManager -from plone.app.workflowmanager import WMMessageFactory as _ plone_shipped_workflows = [ - 'folder_workflow', - 'intranet_folder_workflow', - 'intranet_workflow', - 'one_state_workflow', - 'plone_workflow', - 'simple_publication_workflow', - 'comment_review_workflow'] + "folder_workflow", + "intranet_folder_workflow", + "intranet_workflow", + "one_state_workflow", + "plone_workflow", + "simple_publication_workflow", + "comment_review_workflow", +] + class Base(BrowserView): """ @@ -58,10 +64,9 @@ class Base(BrowserView): errors = {} next_id = None # the id of the next workflow to be viewed - label = _(u'Workflow Manager') - description = _(u'Manage your custom workflows TTW.') - wrapped_dialog_template = ViewPageTemplateFile( - 'templates/wrapped-dialog.pt') + label = _(u"Workflow Manager") + description = _(u"Manage your custom workflows TTW.") + wrapped_dialog_template = ViewPageTemplateFile("templates/wrapped-dialog.pt") @property @memoize @@ -81,19 +86,18 @@ def allowed_guard_permissions(self): @property @memoize def portal(self): - utool = getToolByName(self.context, 'portal_url') + utool = getToolByName(self.context, "portal_url") return utool.getPortalObject() @property @memoize def portal_workflow(self): - return getToolByName(self.context, 'portal_workflow') + return getToolByName(self.context, "portal_workflow") @property @memoize def available_workflows(self): - return [w for w in self.workflows - if w.id not in plone_shipped_workflows] + return [w for w in self.workflows if w.id not in plone_shipped_workflows] @property @memoize @@ -105,7 +109,7 @@ def workflows(self): @property @memoize def selected_workflow(self): - selected = self.request.get('selected-workflow') + selected = self.request.get("selected-workflow") if type(selected) == list and len(selected) > 0: selected = selected[0] @@ -115,7 +119,7 @@ def selected_workflow(self): @property @memoize def selected_state(self): - state = self.request.get('selected-state') + state = self.request.get("selected-state") if type(state) == list and len(state) > 0: state = state[0] @@ -125,7 +129,7 @@ def selected_state(self): @property @memoize def selected_transition(self): - transition = self.request.get('selected-transition') + transition = self.request.get("selected-transition") if type(transition) == list and len(transition) > 0: transition = transition[0] @@ -136,36 +140,38 @@ def selected_transition(self): @memoize def available_states(self): wf = self.selected_workflow - if wf is not None: - states = [wf.states[state] for state in wf.states.objectIds()] - states.sort(lambda x, y: cmp(x.title.lower(), y.title.lower())) - return states - else: + if wf is None: return [] + states = sorted( + wf.states.objectValues(), + key=lambda x: x.title.lower(), + ) + return states @property @memoize def available_transitions(self): wf = self.selected_workflow - if wf is not None: - transitions = wf.transitions.objectIds() - transitions = [wf.transitions[t] for t in transitions] - transitions.sort( - lambda x, y: cmp(x.title.lower(), y.title.lower())) - return transitions - else: + if wf is None: return [] + transitions = sorted( + wf.transitions.objectValues(), + key=lambda x: x.title.lower(), + ) + return transitions def authorize(self): - authenticator = getMultiAdapter((self.context, self.request), - name=u"authenticator") + authenticator = getMultiAdapter( + (self.context, self.request), name=u"authenticator" + ) if not authenticator.verify(): raise Unauthorized def render_transitions_template(self): return self.workflow_transitions_template( available_states=self.available_states, - available_transitions=self.available_transitions) + available_transitions=self.available_transitions, + ) def get_transition(self, id): if id in self.selected_workflow.transitions.objectIds(): @@ -174,14 +180,15 @@ def get_transition(self, id): @property @memoize def assignable_types(self): - vocab_factory = getUtility(IVocabularyFactory, - name="plone.app.vocabularies.ReallyUserFriendlyTypes") + vocab_factory = getUtility( + IVocabularyFactory, name="plone.app.vocabularies.ReallyUserFriendlyTypes" + ) types = [] for v in vocab_factory(self.context): types.append(dict(id=v.value, title=v.title)) def _key(v): - return v['title'] + return v["title"] types.sort(key=_key) return types @@ -193,11 +200,9 @@ def assigned_types(self): chain = self.portal_workflow.listChainOverrides() nondefault = [info[0] for info in chain] for type_ in self.assignable_types: - if type_['id'] in nondefault: - chain = self.portal_workflow.getChainForPortalType( - type_['id']) - if len(chain) > 0 and chain[0] == \ - self.selected_workflow.id: + if type_["id"] in nondefault: + chain = self.portal_workflow.getChainForPortalType(type_["id"]) + if len(chain) > 0 and chain[0] == self.selected_workflow.id: types.append(type_) except: pass @@ -217,7 +222,9 @@ def get_state(self, id): def get_transition_paths(self, state=None): if state is not None: - states = [state,] + states = [ + state, + ] else: states = self.available_states @@ -230,7 +237,10 @@ def get_transition_paths(self, state=None): for trans in state.transitions: current_transition = self.get_transition(trans) if current_transition is not None: - if current_transition.id is not None and current_transition.new_state_id is not None: + if ( + current_transition.id is not None + and current_transition.new_state_id is not None + ): nextState = current_transition.new_state_id @@ -238,9 +248,11 @@ def get_transition_paths(self, state=None): paths[stateId] = dict() if nextState not in paths[stateId]: - paths[stateId][nextState] = dict() + paths[stateId][nextState] = dict() - paths[state.id][nextState][current_transition.id] = current_transition.title + paths[state.id][nextState][ + current_transition.id + ] = current_transition.title return json.dumps(paths) @@ -256,28 +268,29 @@ def get_debug_mode(self): def next_url(self): return self.get_url() - def get_url(self, relative=None, workflow=None, transition=None, - state=None, **kwargs): + def get_url( + self, relative=None, workflow=None, transition=None, state=None, **kwargs + ): url = self.context.absolute_url() if relative: - url = url + '/' + relative.lstrip('/') + url = url + "/" + relative.lstrip("/") else: - url = url + '/@@workflowmanager' + url = url + "/@@workflowmanager" params = {} if not workflow: if self.next_id: - params['selected-workflow'] = self.next_id + params["selected-workflow"] = self.next_id elif self.selected_workflow: - params['selected-workflow'] = self.selected_workflow.id + params["selected-workflow"] = self.selected_workflow.id else: - params['selected-workflow'] = workflow.id + params["selected-workflow"] = workflow.id if transition: - params['selected-transition'] = transition.id + params["selected-transition"] = transition.id if state: - params['selected-state'] = state.id + params["selected-state"] = state.id params.update(kwargs) @@ -288,7 +301,7 @@ def get_url(self, relative=None, workflow=None, transition=None, @memoize def getGroups(self): - gf = aq_get(self.context, '__allow_groups__', None, 1) + gf = aq_get(self.context, "__allow_groups__", None, 1) if gf is None: return () try: @@ -301,11 +314,10 @@ def getGroups(self): @property @memoize def context_state(self): - return getMultiAdapter((self.context, self.request), - name=u'plone_portal_state') + return getMultiAdapter((self.context, self.request), name=u"plone_portal_state") def wrap_template(self, tmpl, **options): - ajax = self.request.get('ajax', None) + ajax = self.request.get("ajax", None) if ajax: return tmpl(options=options) else: @@ -315,51 +327,59 @@ def wrap_template(self, tmpl, **options): def has_graphviz(self): return HAS_GRAPHVIZ - def handle_response(self, message=None, tmpl=None, redirect=None, - load=None, justdoerrors=False, - **kwargs): - ajax = self.request.get('ajax', None) - status = {'status': 'ok'} + def handle_response( + self, + message=None, + tmpl=None, + redirect=None, + load=None, + justdoerrors=False, + **kwargs + ): + ajax = self.request.get("ajax", None) + status = {"status": "ok"} if len(self.errors) > 0: - status['status'] = 'error' + status["status"] = "error" if ajax: - status['errors'] = [[k, v] for k, v in self.errors.items()] + status["errors"] = [[k, v] for k, v in self.errors.items()] else: - status['errors'] = self.errors + status["errors"] = self.errors elif redirect: - status['status'] = 'redirect' + status["status"] = "redirect" - if type(redirect) in (str, unicode): - status['location'] = redirect + if type(redirect) in (str, six.text_type): + status["location"] = redirect else: - status['location'] = self.next_url + status["location"] = self.next_url elif load: - status['status'] = 'load' - status['url'] = load + status["status"] = "load" + status["url"] = load else: - status['status'] = 'ok' + status["status"] = "ok" if message: - status['message'] = zope.i18n.translate(message, context=self.request) + status["message"] = zope.i18n.translate(message, context=self.request) if ajax: - self.request.response.setHeader('X-Theme-Disabled', 'True') + self.request.response.setHeader("X-Theme-Disabled", "True") if tmpl and not justdoerrors: return tmpl.__of__(self.context)(**kwargs) else: - if 'graph_updates' in kwargs: - #The response will default to HTML (not JSON) if we try to pass HTML back - self.request.response.setHeader('Content-Type', 'application/JSON;;charset="utf-8"') + if "graph_updates" in kwargs: + # The response will default to HTML (not JSON) if we try to pass HTML back + self.request.response.setHeader( + "Content-Type", 'application/JSON;;charset="utf-8"' + ) - status['graph_updates'] = kwargs['graph_updates'] + status["graph_updates"] = kwargs["graph_updates"] return json.dumps(status) else: if redirect: - return self.request.response.redirect(status['location']) - elif status['status'] == 'load': - return self.request.response.redirect(status['url']) + return self.request.response.redirect(status["location"]) + elif status["status"] == "load": + return self.request.response.redirect(status["url"]) elif tmpl: return self.wrap_template(tmpl, **kwargs) else: @@ -367,18 +387,15 @@ def handle_response(self, message=None, tmpl=None, redirect=None, class ControlPanel(Base): - template = ViewPageTemplateFile('templates/controlpanel.pt') - content_template = ViewPageTemplateFile('templates/content.pt') - workflow_state_template = \ - ViewPageTemplateFile('templates/workflow-state.pt') - workflow_transition_template = \ - ViewPageTemplateFile('templates/workflow-transition.pt') - workflow_graph_template = \ - ViewPageTemplateFile('templates/workflow-graph.pt') - state_template = \ - ViewPageTemplateFile('templates/state.pt') - transition_template = \ - ViewPageTemplateFile('templates/transition.pt') + template = ViewPageTemplateFile("templates/controlpanel.pt") + content_template = ViewPageTemplateFile("templates/content.pt") + workflow_state_template = ViewPageTemplateFile("templates/workflow-state.pt") + workflow_transition_template = ViewPageTemplateFile( + "templates/workflow-transition.pt" + ) + workflow_graph_template = ViewPageTemplateFile("templates/workflow-graph.pt") + state_template = ViewPageTemplateFile("templates/state.pt") + transition_template = ViewPageTemplateFile("templates/transition.pt") def __call__(self): return self.template() @@ -394,11 +411,13 @@ def retrieve_item(self): transition = self.selected_transition if state: - return self.workflow_state_template(state=state, - available_transitions=self.available_transitions) + return self.workflow_state_template( + state=state, available_transitions=self.available_transitions + ) elif transition: - return self.workflow_transition_template(transition=transition, - available_states=self.available_states) + return self.workflow_transition_template( + transition=transition, available_states=self.available_states + ) def render_states(self): return self.state_template(states=self.available_states) @@ -406,12 +425,13 @@ def render_states(self): def render_transitions(self): return self.transition_template(transitions=self.available_transitions) -class Path(): + +class Path: """Very simple class to represent a single path from state->transition->state""" - start = '' - transition = '' - end = '' + start = "" + transition = "" + end = "" def __init__(self, start, transition, end): self.start = start diff --git a/src/plone/app/workflowmanager/browser/layout.py b/src/plone/app/workflowmanager/browser/layout.py index 57f76e0..74e25ca 100644 --- a/src/plone/app/workflowmanager/browser/layout.py +++ b/src/plone/app/workflowmanager/browser/layout.py @@ -1,7 +1,8 @@ +from plone import api from Products.Five.browser import BrowserView import json -from plone import api +import six class GraphLayout(BrowserView): @@ -22,7 +23,7 @@ def __init__(self, context, request, workflow=None): self.REGISTRY_KEY = "plone.app.workflowmanager.layouts" if workflow is None: - self.workflow = self.request.form['workflow'] or None + self.workflow = self.request.form["workflow"] or None else: self.workflow = workflow self.layout = {} @@ -32,12 +33,12 @@ def __init__(self, context, request, workflow=None): layouts = {} if self.workflow not in layouts: - layouts[unicode(self.workflow)] = u'{}' + layouts[six.text_type(self.workflow)] = u"{}" else: self.layout = json.loads(layouts[self.workflow]) def __call__(self): - self.layout = json.loads(self.request.form['layout']) + self.layout = json.loads(self.request.form["layout"]) self.saveLayout() def getLayouts(self): @@ -45,11 +46,11 @@ def getLayouts(self): def saveLayout(self): layouts = self.getLayouts() or {} - layouts[unicode(self.workflow)] = unicode(json.dumps(self.layout)) + layouts[six.text_type(self.workflow)] = six.text_type(json.dumps(self.layout)) api.portal.set_registry_record(self.REGISTRY_KEY, layouts) def getLayout(self): - if(self.workflow == ''): + if self.workflow == "": return False return json.dumps(self.layout) diff --git a/src/plone/app/workflowmanager/browser/resources/fix-bootstrap.py b/src/plone/app/workflowmanager/browser/resources/fix-bootstrap.py index 706f6a5..6acb16b 100644 --- a/src/plone/app/workflowmanager/browser/resources/fix-bootstrap.py +++ b/src/plone/app/workflowmanager/browser/resources/fix-bootstrap.py @@ -4,24 +4,28 @@ # one area of the site # -_input = open('bootstrap.css') -_output = open('bootstrap-fixed.css', 'w') -_prefix = '.wm' +_input = open("bootstrap.css") +_output = open("bootstrap-fixed.css", "w") +_prefix = ".wm" _ignored_rules = ( - '.tooltip', - '.popover', - '.top', - '.right', - '.left', - '.bottom', - '.modal') + ".tooltip", + ".popover", + ".top", + ".right", + ".left", + ".bottom", + ".modal", +) for line in _input.readlines(): # starts with class rule stripped = line.strip() - if line and not stripped.startswith('@') and \ - (stripped.endswith('{') or stripped.endswith(',')): + if ( + line + and not stripped.startswith("@") + and (stripped.endswith("{") or stripped.endswith(",")) + ): valid = True for ignored in _ignored_rules: if ignored in line: @@ -31,9 +35,9 @@ # find replacement position pos = 0 try: - while line[pos] in (' ', '\t'): + while line[pos] in (" ", "\t"): pos += 1 - line = line[:pos] + _prefix + ' ' + line[pos:] + line = line[:pos] + _prefix + " " + line[pos:] except IndexError: pass _output.write(line) diff --git a/src/plone/app/workflowmanager/browser/state.py b/src/plone/app/workflowmanager/browser/state.py index 406d89d..1d34ac1 100644 --- a/src/plone/app/workflowmanager/browser/state.py +++ b/src/plone/app/workflowmanager/browser/state.py @@ -1,31 +1,28 @@ from Persistence import PersistentMapping -from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile - -from plone.app.workflowmanager.utils import clone_state from plone.app.workflow.remap import remap_workflow - +from plone.app.workflowmanager import WMMessageFactory as _ from plone.app.workflowmanager.browser import validators -from plone.app.workflowmanager.permissions import managed_permissions from plone.app.workflowmanager.browser.controlpanel import Base -from plone.app.workflowmanager import WMMessageFactory as _ +from plone.app.workflowmanager.permissions import managed_permissions +from plone.app.workflowmanager.utils import clone_state +from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile + import json -from sets import Set class AddState(Base): - template = ViewPageTemplateFile('templates/add-new-state.pt') - new_state_template = ViewPageTemplateFile('templates/state.pt') + template = ViewPageTemplateFile("templates/add-new-state.pt") + new_state_template = ViewPageTemplateFile("templates/state.pt") def __call__(self): self.errors = {} - if not self.request.get('form.actions.add', False): + if not self.request.get("form.actions.add", False): return self.handle_response(tmpl=self.template) else: self.authorize() - state = validators.not_empty(self, 'state-name') - state_id = validators.id(self, 'state-name', - self.selected_workflow.states) + state = validators.not_empty(self, "state-name") + state_id = validators.id(self, "state-name", self.selected_workflow.states) if not self.errors: # must have state to go on @@ -33,7 +30,7 @@ def __call__(self): workflow.states.addState(state_id) new_state = workflow.states[state_id] - clone_of_id = self.request.get('clone-from-state') + clone_of_id = self.request.get("clone-from-state") if clone_of_id: # manage_copy|paste|clone doesn't work? clone_state(new_state, workflow.states[clone_of_id]) @@ -41,15 +38,17 @@ def __call__(self): new_state.title = state # if added from transition screen - referenced_transition = self.request.get( - 'referenced-transition', None) + referenced_transition = self.request.get("referenced-transition", None) if referenced_transition: - new_state.transitions = \ - new_state.transitions + (referenced_transition, ) + new_state.transitions = new_state.transitions + ( + referenced_transition, + ) - msg = _('msg_state_created', - default=u'"${state_id}" state successfully created.', - mapping={'state_id': new_state.id}) + msg = _( + "msg_state_created", + default=u'"${state_id}" state successfully created.', + mapping={"state_id": new_state.id}, + ) arbitraryStateList = [] arbitraryStateList.append(new_state) @@ -58,23 +57,21 @@ def __call__(self): updates = dict() - updates['element'] = new_elements - updates['type'] = u'state' - updates['action'] = u'add' - updates['objectId'] = new_state.id - updates['transitions'] = new_state.transitions + updates["element"] = new_elements + updates["type"] = u"state" + updates["action"] = u"add" + updates["objectId"] = new_state.id + updates["transitions"] = new_state.transitions return self.handle_response( - message=msg, - graph_updates=updates, - state=new_state) + message=msg, graph_updates=updates, state=new_state + ) else: - return self.handle_response(tmpl=self.template, - justdoerrors=True) + return self.handle_response(tmpl=self.template, justdoerrors=True) class DeleteState(Base): - template = ViewPageTemplateFile('templates/delete-state.pt') + template = ViewPageTemplateFile("templates/delete-state.pt") def __call__(self): self.errors = {} @@ -88,78 +85,94 @@ def __call__(self): self.is_using_state = True break - if self.request.get('form.actions.delete', False): + if self.request.get("form.actions.delete", False): self.authorize() if self.is_using_state: - replacement = self.request.get('replacement-state', - self.available_states[0].id) + replacement = self.request.get( + "replacement-state", self.available_states[0].id + ) for transition in self.available_transitions: if state_id == transition.new_state_id: transition.new_state_id = replacement chains = self.portal_workflow.listChainOverrides() - types_ids = [c[0] for c in chains - if self.selected_workflow.id in c[1]] - remap_workflow(self.context, types_ids, - (self.selected_workflow.id, ), {state_id: replacement}) + types_ids = [c[0] for c in chains if self.selected_workflow.id in c[1]] + remap_workflow( + self.context, + types_ids, + (self.selected_workflow.id,), + {state_id: replacement}, + ) self.selected_workflow.states.deleteStates([state_id]) updates = dict() - updates['objectId'] = state_id - updates['action'] = u'delete' - updates['type'] = u'state' + updates["objectId"] = state_id + updates["action"] = u"delete" + updates["type"] = u"state" try: - updates['replacement'] = replacement + updates["replacement"] = replacement except UnboundLocalError: pass return self.handle_response( - message=_('msg_state_deleted', + message=_( + "msg_state_deleted", default=u'"${id}" state has been successfully deleted.', - mapping={'id': state_id}), - graph_updates=updates) - elif self.request.get('form.actions.cancel', False) == 'Cancel': + mapping={"id": state_id}, + ), + graph_updates=updates, + ) + elif self.request.get("form.actions.cancel", False) == "Cancel": return self.handle_response( - message=_('msg_state_deletion_canceled', + message=_( + "msg_state_deletion_canceled", default=u'Deleting the "${id}" state has been canceled.', - mapping={'id': state_id})) + mapping={"id": state_id}, + ) + ) else: return self.handle_response(tmpl=self.template) class SaveState(Base): - updated_state_template = ViewPageTemplateFile('templates/state.pt') + updated_state_template = ViewPageTemplateFile("templates/state.pt") + def update_selected_transitions(self): wf = self.selected_workflow - state = wf.states[self.request.get('selected-state')] + state = wf.states[self.request.get("selected-state")] transitions = wf.transitions.objectIds() selected_transitions = [] for transition in transitions: - key = 'transition-%s-state-%s' % (transition, state.id) + key = "transition-%s-state-%s" % (transition, state.id) if key in self.request: selected_transitions.append(transition) state.transitions = tuple(selected_transitions) def update_state_permissions(self): wf = self.selected_workflow - state = wf.states[self.request.get('selected-state')] + state = wf.states[self.request.get("selected-state")] perm_roles = PersistentMapping() available_roles = state.getAvailableRoles() for managed_perm in managed_permissions(wf.id): selected_roles = [] for role in available_roles: - key = 'permission-%s-role-%s-state-%s' % ( - managed_perm['name'], role, state.id) + key = "permission-%s-role-%s-state-%s" % ( + managed_perm["name"], + role, + state.id, + ) if key in self.request: selected_roles.append(role) - acquire_key = 'permission-acquire-%s-state-%s' % ( - managed_perm['name'], state.id) + acquire_key = "permission-acquire-%s-state-%s" % ( + managed_perm["name"], + state.id, + ) if acquire_key in self.request: acquired = True else: @@ -168,43 +181,42 @@ def update_state_permissions(self): if len(selected_roles) > 0: if not acquired: selected_roles = tuple(selected_roles) - perm_roles[managed_perm['perm']] = selected_roles - if managed_perm['perm'] not in wf.permissions: - wf.permissions = wf.permissions + (managed_perm['perm'], ) - elif managed_perm['perm'] in wf.permissions: + perm_roles[managed_perm["perm"]] = selected_roles + if managed_perm["perm"] not in wf.permissions: + wf.permissions = wf.permissions + (managed_perm["perm"],) + elif managed_perm["perm"] in wf.permissions: # it's managed, no perms set, but still could save acquired if acquired: - perm_roles[managed_perm['perm']] = [] + perm_roles[managed_perm["perm"]] = [] else: - perm_roles[managed_perm['perm']] = () + perm_roles[managed_perm["perm"]] = () elif not acquired: # not already managing perms, but no longer acquire permissions - if managed_perm['perm'] not in wf.permissions: - wf.permissions = wf.permissions + (managed_perm['perm'], ) - perm_roles[managed_perm['perm']] = () + if managed_perm["perm"] not in wf.permissions: + wf.permissions = wf.permissions + (managed_perm["perm"],) + perm_roles[managed_perm["perm"]] = () state.permission_roles = perm_roles def update_state_properties(self): wf = self.selected_workflow - state = wf.states[self.request.get('selected-state')] + state = wf.states[self.request.get("selected-state")] - if ('state-%s-initial-state' % state.id) in self.request: + if ("state-%s-initial-state" % state.id) in self.request: wf.initial_state = state.id - title = self.request.get('state-%s-title' % state.id, False) + title = self.request.get("state-%s-title" % state.id, False) if title: state.title = title - description = self.request.get('state-%s-description' % state.id, - False) + description = self.request.get("state-%s-description" % state.id, False) if description: state.description = description def update_state_group_roles(self): wf = self.selected_workflow - state = wf.states[self.request.get('selected-state')] + state = wf.states[self.request.get("selected-state")] group_roles = PersistentMapping() available_roles = state.getAvailableRoles() @@ -214,30 +226,29 @@ def update_state_group_roles(self): selected_roles = [] for role in available_roles: - key = "group-%s-role-%s-state-%s" % ( - group['id'], role, state.id) + key = "group-%s-role-%s-state-%s" % (group["id"], role, state.id) if key in self.request: selected_roles.append(role) if len(selected_roles) > 0: - group_roles[group['id']] = tuple(selected_roles) + group_roles[group["id"]] = tuple(selected_roles) - if group['id'] not in wf.groups: - wf.groups = wf.groups + (group['id'], ) + if group["id"] not in wf.groups: + wf.groups = wf.groups + (group["id"],) state.group_roles = group_roles def __call__(self): - if self.request.get('form-box') is not None: - form_data = self.request.get('form-box') + if self.request.get("form-box") is not None: + form_data = self.request.get("form-box") form_data = json.loads(form_data) - for name in form_data: + for name in form_data: self.request[name] = form_data[name] self.authorize() self.errors = {} wf = self.selected_workflow - state = wf.states[self.request.get('selected-state')] + state = wf.states[self.request.get("selected-state")] oldTransitions = state.transitions @@ -253,35 +264,35 @@ def __call__(self): updated_state = self.updated_state_template(states=arbitraryStateList) - #transitions that were added... - add = list( Set(newTransitions) - Set(oldTransitions) ) + # transitions that were added... + add = list(set(newTransitions) - set(oldTransitions)) - #transitions that were removed - remove = list( Set(oldTransitions) - Set(newTransitions) ) + # transitions that were removed + remove = list(set(oldTransitions) - set(newTransitions)) update = dict() - update['objectId']=state.id - update['action']=u'update' - update['type']=u'state' - update['element']=updated_state - update['add'] = add - update['remove'] = remove + update["objectId"] = state.id + update["action"] = u"update" + update["type"] = u"state" + update["element"] = updated_state + update["add"] = add + update["remove"] = remove + + return self.handle_response(graph_updates=update) - return self.handle_response( - graph_updates=update) class EditState(Base): - template = ViewPageTemplateFile('templates/workflow-state.pt') + template = ViewPageTemplateFile("templates/workflow-state.pt") def __call__(self): wf = self.selected_workflow - if (wf == None): + if wf == None: return self.handle_response() state = self.selected_state - if( state == None ): + if state == None: return self.handle_response() transitions = self.available_transitions @@ -289,5 +300,4 @@ def __call__(self): return self.render_state_template(state, transitions) def render_state_template(self, state, transitions): - return self.template(state=state, - available_transitions=transitions) + return self.template(state=state, available_transitions=transitions) diff --git a/src/plone/app/workflowmanager/browser/transition.py b/src/plone/app/workflowmanager/browser/transition.py index 4c7e63a..648b203 100644 --- a/src/plone/app/workflowmanager/browser/transition.py +++ b/src/plone/app/workflowmanager/browser/transition.py @@ -1,31 +1,30 @@ -from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile - -from Products.DCWorkflow.Transitions import TRIGGER_AUTOMATIC -from Products.DCWorkflow.Transitions import TRIGGER_USER_ACTION - -from plone.app.workflowmanager.browser.controlpanel import Base -from plone.app.workflowmanager.utils import clone_transition +from plone.app.workflowmanager import WMMessageFactory as _ from plone.app.workflowmanager.browser import validators +from plone.app.workflowmanager.browser.controlpanel import Base from plone.app.workflowmanager.permissions import allowed_guard_permissions +from plone.app.workflowmanager.utils import clone_transition +from Products.DCWorkflow.Transitions import TRIGGER_AUTOMATIC +from Products.DCWorkflow.Transitions import TRIGGER_USER_ACTION +from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile -from plone.app.workflowmanager import WMMessageFactory as _ import json class AddTransition(Base): - template = ViewPageTemplateFile('templates/add-new-transition.pt') - new_transition_template = ViewPageTemplateFile('templates/transition.pt') + template = ViewPageTemplateFile("templates/add-new-transition.pt") + new_transition_template = ViewPageTemplateFile("templates/transition.pt") def __call__(self): self.errors = {} - if not self.request.get('form.actions.add', False): + if not self.request.get("form.actions.add", False): return self.handle_response(tmpl=self.template) else: self.authorize() - transition = validators.not_empty(self, 'transition-name') - transition_id = validators.id(self, 'transition-name', - self.selected_workflow.transitions) + transition = validators.not_empty(self, "transition-name") + transition_id = validators.id( + self, "transition-name", self.selected_workflow.transitions + ) if not self.errors: # must have transition to go on @@ -33,52 +32,58 @@ def __call__(self): workflow.transitions.addTransition(transition_id) new_transition = workflow.transitions[transition_id] - clone_of_id = self.request.get('clone-from-transition') + clone_of_id = self.request.get("clone-from-transition") new_transition.title = transition if clone_of_id: # manage_copy|paste|clone doesn't work? - clone_transition(new_transition, - workflow.transitions[clone_of_id]) + clone_transition(new_transition, workflow.transitions[clone_of_id]) else: new_transition.actbox_name = transition - new_transition.actbox_url = \ - "%(content_url)s/content_status_modify?workflow_action=" + transition_id - new_transition.actbox_category = 'workflow' - new_transition.script_name = '' - new_transition.after_script_name = '' + new_transition.actbox_url = ( + "%(content_url)s/content_status_modify?workflow_action=" + + transition_id + ) + new_transition.actbox_category = "workflow" + new_transition.script_name = "" + new_transition.after_script_name = "" # if added from state screen - referenced_state = self.request.get('referenced-state', None) + referenced_state = self.request.get("referenced-state", None) if referenced_state: state = self.selected_workflow.states[referenced_state] - state.transitions += (new_transition.id, ) + state.transitions += (new_transition.id,) arbitraryTransitionList = [] arbitraryTransitionList.append(new_transition) - new_element = self.new_transition_template(transitions=arbitraryTransitionList) + new_element = self.new_transition_template( + transitions=arbitraryTransitionList + ) updates = dict() - updates['objectId'] = new_transition.id - updates['element'] = new_element - updates['action'] = u'add' - updates['type'] = u'transition' + updates["objectId"] = new_transition.id + updates["element"] = new_element + updates["action"] = u"add" + updates["type"] = u"transition" return self.handle_response( - message=_('msg_transition_created', + message=_( + "msg_transition_created", default=u'"${transition_id}" transition successfully created.', - mapping={'transition_id': new_transition.id}), + mapping={"transition_id": new_transition.id}, + ), graph_updates=updates, - transition=new_transition) + transition=new_transition, + ) else: - return self.handle_response(tmpl=self.template, - justdoerrors=True) + return self.handle_response(tmpl=self.template, justdoerrors=True) class SaveTransition(Base): - transition_template = ViewPageTemplateFile('templates/transition.pt') + transition_template = ViewPageTemplateFile("templates/transition.pt") + def update_guards(self): wf = self.selected_workflow transition = self.selected_transition @@ -86,20 +91,21 @@ def update_guards(self): perms = [] for key, perm in allowed_guard_permissions(wf.getId()).items(): - key = 'transition-%s-guard-permission-%s' % (transition.id, key) + key = "transition-%s-guard-permission-%s" % (transition.id, key) if key in self.request and perm not in guard.permissions: perms.append(perm) guard.permissions = tuple(perms) - roles = validators.parse_set_value(self, 'transition-%s-guard-roles' % - transition.id) + roles = validators.parse_set_value( + self, "transition-%s-guard-roles" % transition.id + ) okay_roles = set(wf.getAvailableRoles()) guard.roles = tuple(roles & okay_roles) - groups = validators.parse_set_value(self, - 'transition-%s-guard-groups' % - transition.id) - okay_groups = set([g['id'] for g in self.getGroups()]) + groups = validators.parse_set_value( + self, "transition-%s-guard-groups" % transition.id + ) + okay_groups = set([g["id"] for g in self.getGroups()]) guard.groups = tuple(groups & okay_groups) transition.guard = guard @@ -107,32 +113,34 @@ def update_guards(self): def update_transition_properties(self): transition = self.selected_transition - if ('transition-%s-autotrigger' % transition.id) in self.request: + if ("transition-%s-autotrigger" % transition.id) in self.request: transition.trigger_type = TRIGGER_AUTOMATIC else: transition.trigger_type = TRIGGER_USER_ACTION - if ('transition-%s-display-name' % transition.id) in self.request: - transition.actbox_name = \ - self.request.get('transition-%s-display-name' % transition.id) + if ("transition-%s-display-name" % transition.id) in self.request: + transition.actbox_name = self.request.get( + "transition-%s-display-name" % transition.id + ) - if ('transition-%s-new-state' % transition.id) in self.request: - transition.new_state_id = \ - self.request.get('transition-%s-new-state' % transition.id) + if ("transition-%s-new-state" % transition.id) in self.request: + transition.new_state_id = self.request.get( + "transition-%s-new-state" % transition.id + ) - if ('transition-%s-title' % transition.id) in self.request: - transition.title = \ - self.request.get('transition-%s-title' % transition.id) + if ("transition-%s-title" % transition.id) in self.request: + transition.title = self.request.get("transition-%s-title" % transition.id) - if ('transition-%s-description' % transition.id) in self.request: - transition.description = \ - self.request.get('transition-%s-description' % transition.id) + if ("transition-%s-description" % transition.id) in self.request: + transition.description = self.request.get( + "transition-%s-description" % transition.id + ) for state in self.available_states: - key = 'transition-%s-state-%s-selected' % (transition.id, state.id) + key = "transition-%s-state-%s-selected" % (transition.id, state.id) if key in self.request: if transition.id not in state.transitions: - state.transitions += (transition.id, ) + state.transitions += (transition.id,) else: if transition.id in state.transitions: transitions = list(state.transitions) @@ -140,11 +148,11 @@ def update_transition_properties(self): state.transitions = transitions def __call__(self): - if self.request.get('form-box') is not None: - form_data = self.request.get('form-box') + if self.request.get("form-box") is not None: + form_data = self.request.get("form-box") form_data = json.loads(form_data) - for name in form_data: + for name in form_data: self.request[name] = form_data[name] self.authorize() @@ -162,26 +170,25 @@ def __call__(self): element = self.transition_template(transitions=arbitraryTransitionList) updates = dict() - updates['objectId'] = transition.id - updates['element'] = element - updates['type'] = u'transition' - updates['action'] = u'update' + updates["objectId"] = transition.id + updates["element"] = element + updates["type"] = u"transition" + updates["action"] = u"update" - return self.handle_response( - graph_updates=updates) + return self.handle_response(graph_updates=updates) class DeleteTransition(Base): - template = ViewPageTemplateFile('templates/delete-transition.pt') + template = ViewPageTemplateFile("templates/delete-transition.pt") def __call__(self): self.errors = {} transition = self.selected_transition transition_id = transition.id - if self.request.get('form.actions.delete', False): + if self.request.get("form.actions.delete", False): self.authorize() - #delete any associated rules also. + # delete any associated rules also. self.actions.delete_rule_for(self.selected_transition) self.selected_workflow.transitions.deleteTransitions([transition_id]) @@ -193,35 +200,39 @@ def __call__(self): state.transitions = tuple(transitions) updates = dict() - updates['objectId'] = transition_id - updates['action'] = u'delete' - updates['type'] = u'transition' - - msg = _('msg_transition_deleted', - default=u'"${id}" transition has been successfully deleted.', - mapping={'id': transition_id}) - return self.handle_response(message=msg, - graph_updates=updates) - elif self.request.get('form.actions.cancel', False) == 'Cancel': - msg = _('msg_deleting_canceled', - default=u'Deleting the "${id}" transition has been canceled.', - mapping={'id': transition_id}) + updates["objectId"] = transition_id + updates["action"] = u"delete" + updates["type"] = u"transition" + + msg = _( + "msg_transition_deleted", + default=u'"${id}" transition has been successfully deleted.', + mapping={"id": transition_id}, + ) + return self.handle_response(message=msg, graph_updates=updates) + elif self.request.get("form.actions.cancel", False) == "Cancel": + msg = _( + "msg_deleting_canceled", + default=u'Deleting the "${id}" transition has been canceled.', + mapping={"id": transition_id}, + ) return self.handle_response(message=msg) else: return self.handle_response(tmpl=self.template) + class EditTransition(Base): - template = ViewPageTemplateFile('templates/workflow-transition.pt') + template = ViewPageTemplateFile("templates/workflow-transition.pt") def __call__(self): wf = self.selected_workflow - if (wf == None): + if wf == None: return self.handle_response() transition = self.selected_transition - if( transition == None ): + if transition == None: return self.handle_response() states = self.available_states @@ -229,6 +240,4 @@ def __call__(self): return self.render_transition_template(transition, states) def render_transition_template(self, transition, states): - return self.template(transition=transition, - available_states=states) - + return self.template(transition=transition, available_states=states) diff --git a/src/plone/app/workflowmanager/browser/validators.py b/src/plone/app/workflowmanager/browser/validators.py index 8070e91..3a6d634 100644 --- a/src/plone/app/workflowmanager/browser/validators.py +++ b/src/plone/app/workflowmanager/browser/validators.py @@ -1,30 +1,37 @@ from OFS.ObjectManager import checkValidId -from zope.i18n import translate -from Products.CMFCore.utils import getToolByName -from plone.app.workflowmanager.utils import generate_id from plone.app.workflowmanager import WMMessageFactory as _ +from plone.app.workflowmanager.utils import generate_id +from Products.CMFCore.utils import getToolByName +from zope.i18n import translate +import six def not_empty(form, name): - v = form.request.get(name, '').strip() - if v is None or (type(v) in (str, unicode) and \ - len(v) == 0) or (type(v) in (tuple, set, list) and len(v) == 0): - form.errors[name] = translate(_(u'This field is required.'), - context=form.request) + v = form.request.get(name, "").strip() + if ( + v is None + or (type(v) in (str, six.text_type) and len(v) == 0) + or (type(v) in (tuple, set, list) and len(v) == 0) + ): + form.errors[name] = translate( + _(u"This field is required."), context=form.request + ) return v def id(form, name, container): - elt_id = form.request.get(name, '').strip() - putils = getToolByName(form.context, 'plone_utils') - elt_id = generate_id(putils.normalizeString(unicode(elt_id, encoding='utf-8')), - container.objectIds()) + elt_id = form.request.get(name, "").strip() + putils = getToolByName(form.context, "plone_utils") + elt_id = generate_id( + putils.normalizeString(six.text_type(elt_id, encoding="utf-8")), container.objectIds() + ) try: checkValidId(container, elt_id) except: - form.errors[name] = translate(_(u'Invalid name. Please try another.'), - context=form.request) + form.errors[name] = translate( + _(u"Invalid name. Please try another."), context=form.request + ) return elt_id @@ -32,8 +39,8 @@ def id(form, name, container): def parse_set_value(form, key): val = form.request.get(key) if val: - if type(val) in (str, unicode): - return set(val.split(',')) + if type(val) in (str, six.text_type): + return set(val.split(",")) elif type(val) in (tuple, list): return set(val) else: diff --git a/src/plone/app/workflowmanager/browser/workflow.py b/src/plone/app/workflowmanager/browser/workflow.py index 8c5adcb..60ecbfe 100644 --- a/src/plone/app/workflowmanager/browser/workflow.py +++ b/src/plone/app/workflowmanager/browser/workflow.py @@ -1,17 +1,15 @@ -from random import randint -from urllib import urlencode - from DateTime import DateTime -from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile - +from plone.app.workflowmanager import WMMessageFactory as _ +from plone.app.workflowmanager.browser import validators from plone.app.workflowmanager.browser.controlpanel import Base from plone.app.workflowmanager.graphviz import getGraph -from plone.app.workflowmanager.browser import validators -from plone.app.workflowmanager import WMMessageFactory as _ +from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile +from random import randint +from six.moves.urllib.parse import urlencode class DeleteWorkflow(Base): - template = ViewPageTemplateFile('templates/delete-workflow.pt') + template = ViewPageTemplateFile("templates/delete-workflow.pt") def __call__(self): self.errors = {} @@ -21,43 +19,45 @@ def __call__(self): if not self.can_delete: return self.handle_response( tmpl=self.template, - message=_(u'You can not delete this workflow until no content ' - u'types are specified to use this workflow.')) - elif self.request.get('form.actions.delete', False) == 'Delete': + message=_( + u"You can not delete this workflow until no content " + u"types are specified to use this workflow." + ), + ) + elif self.request.get("form.actions.delete", False) == "Delete": self.authorize() - #delete all rules also. + # delete all rules also. for transition in self.available_transitions: self.actions.delete_rule_for(transition) self.portal_workflow.manage_delObjects([self.selected_workflow.id]) return self.handle_response(redirect=True) - elif self.request.get('form.actions.cancel', False) == 'Cancel': + elif self.request.get("form.actions.cancel", False) == "Cancel": return self.handle_response() else: return self.handle_response(tmpl=self.template) class AddWorkflow(Base): - template = ViewPageTemplateFile('templates/add-new-workflow.pt') + template = ViewPageTemplateFile("templates/add-new-workflow.pt") def __call__(self): self.errors = {} - workflow = validators.not_empty(self, 'workflow-name') - workflow_id = validators.id(self, 'workflow-name', - self.portal_workflow) + workflow = validators.not_empty(self, "workflow-name") + workflow_id = validators.id(self, "workflow-name", self.portal_workflow) - if not self.request.get('form.actions.add', False): + if not self.request.get("form.actions.add", False): return self.handle_response(tmpl=self.template) elif self.errors: return self.handle_response(tmpl=self.template, justdoerrors=True) else: self.authorize() # must have state to go on - cloned_from_workflow = \ - self.portal_workflow[self.request.get('clone-from-workflow')] + cloned_from_workflow = self.portal_workflow[ + self.request.get("clone-from-workflow") + ] - self.context.portal_workflow.manage_clone(cloned_from_workflow, - workflow_id) + self.context.portal_workflow.manage_clone(cloned_from_workflow, workflow_id) new_workflow = self.context.portal_workflow[workflow_id] new_workflow.title = workflow self.next_id = new_workflow.id @@ -66,47 +66,57 @@ def __call__(self): class UpdateSecuritySettings(Base): - template = ViewPageTemplateFile('templates/update-security-settings.pt') + template = ViewPageTemplateFile("templates/update-security-settings.pt") def __call__(self): - if self.request.get('form.actions.confirm', False): + if self.request.get("form.actions.confirm", False): self.authorize() count = self.portal_workflow._recursiveUpdateRoleMappings( - self.portal, - {self.selected_workflow.id: self.selected_workflow}) + self.portal, {self.selected_workflow.id: self.selected_workflow} + ) return self.handle_response( - message=_('msg_updated_objects', - default="Updated ${count} objects.", - mapping={'count': count})) + message=_( + "msg_updated_objects", + default="Updated ${count} objects.", + mapping={"count": count}, + ) + ) else: return self.handle_response(tmpl=self.template) class Assign(Base): - template = ViewPageTemplateFile('templates/assign.pt') + template = ViewPageTemplateFile("templates/assign.pt") def __call__(self): self.errors = {} - if self.request.get('form.actions.next', False): + if self.request.get("form.actions.next", False): self.authorize() - params = urlencode({'type_id': self.request.get('type_id'), - 'new_workflow': self.selected_workflow.id}) - return self.handle_response(load=self.context_state.portal_url() + - '/@@content-controlpanel?' + params) + params = urlencode( + { + "type_id": self.request.get("type_id"), + "new_workflow": self.selected_workflow.id, + } + ) + return self.handle_response( + load=self.context_state.portal_url() + + "/@@content-controlpanel?" + + params + ) else: return self.handle_response(tmpl=self.template) class SanityCheck(Base): - template = ViewPageTemplateFile('templates/sanity-check.pt') + template = ViewPageTemplateFile("templates/sanity-check.pt") def __call__(self): self.errors = {} states = self.available_states transitions = self.available_transitions - self.errors['state-errors'] = [] - self.errors['transition-errors'] = [] + self.errors["state-errors"] = [] + self.errors["transition-errors"] = [] for state in states: found = False @@ -115,12 +125,14 @@ def __call__(self): found = True break - if self.selected_workflow.initial_state == state.id and \ - len(state.transitions) > 0: + if ( + self.selected_workflow.initial_state == state.id + and len(state.transitions) > 0 + ): found = True if not found: - self.errors['state-errors'].append(state) + self.errors["state-errors"].append(state) for transition in transitions: found = False @@ -133,22 +145,26 @@ def __call__(self): break if not found: - self.errors['transition-errors'].append(transition) + self.errors["transition-errors"].append(transition) state_ids = [s.id for s in states] - if not self.selected_workflow.initial_state or \ - self.selected_workflow.initial_state not in state_ids: - self.errors['initial-state-error'] = True - - self.has_errors = len(self.errors['state-errors']) > 0 or \ - len(self.errors['transition-errors']) > 0 or \ - 'initial-state-error' in self.errors + if ( + not self.selected_workflow.initial_state + or self.selected_workflow.initial_state not in state_ids + ): + self.errors["initial-state-error"] = True + + self.has_errors = ( + len(self.errors["state-errors"]) > 0 + or len(self.errors["transition-errors"]) > 0 + or "initial-state-error" in self.errors + ) return self.handle_response(tmpl=self.template) class Graph(Base): - template = ViewPageTemplateFile('templates/diagram.pt') + template = ViewPageTemplateFile("templates/diagram.pt") def __call__(self): # generate a random number ot prevent browser from caching this... @@ -157,8 +173,8 @@ def __call__(self): def image(self): resp = self.request.response - resp.setHeader('Content-Type', 'image/gif') - resp.setHeader('Last-Modified', DateTime().rfc822()) + resp.setHeader("Content-Type", "image/gif") + resp.setHeader("Last-Modified", DateTime().rfc822()) graph = getGraph(self.selected_workflow) resp.setHeader("Content-Length", len(graph)) return graph diff --git a/src/plone/app/workflowmanager/configure.zcml b/src/plone/app/workflowmanager/configure.zcml index d91cc58..52b2d98 100644 --- a/src/plone/app/workflowmanager/configure.zcml +++ b/src/plone/app/workflowmanager/configure.zcml @@ -1,32 +1,35 @@ + xmlns="http://namespaces.zope.org/zope" + xmlns:genericsetup="http://namespaces.zope.org/genericsetup" + xmlns:i18n="http://namespaces.zope.org/i18n" + xmlns:zcml="http://namespaces.zope.org/zcml" + i18n_domain="plone.app.workflowmanager" + > - - - + - + + name="default" + title="Workflow Manager" + description="Workflow Manager for Plone." + provides="Products.GenericSetup.interfaces.EXTENSION" + for="Products.CMFPlone.interfaces.IPloneSiteRoot" + directory="profiles/default" + /> + name="uninstall" + title="Workflow Manager (uninstall)" + description="Uninstalls the Workflow Manager for Plone." + provides="Products.GenericSetup.interfaces.EXTENSION" + directory="profiles/uninstall" + /> diff --git a/src/plone/app/workflowmanager/graphviz.py b/src/plone/app/workflowmanager/graphviz.py index 03d7c58..96ae1c6 100644 --- a/src/plone/app/workflowmanager/graphviz.py +++ b/src/plone/app/workflowmanager/graphviz.py @@ -2,17 +2,19 @@ # This code is directly adapted from # DCWorkflowGraph and isn't change much at all. # -import os -from tempfile import mktemp from os.path import join - from Products.CMFCore.utils import getToolByName +from tempfile import mktemp -DOT_EXE = 'dot' -bin_search_path = '' +import os +import six -if os.name == 'nt': - DOT_EXE = 'dot.exe' + +DOT_EXE = "dot" +bin_search_path = "" + +if os.name == "nt": + DOT_EXE = "dot.exe" # patch from Joachim Bauch bauch@struktur.de # on Windows, the path to the ATT Graphviz installation @@ -20,13 +22,15 @@ try: import win32api import win32con + # make sure that "key" is defined in our except block key = None try: key = win32api.RegOpenKeyEx( - win32con.HKEY_LOCAL_MACHINE, r'SOFTWARE\ATT\Graphviz') - value, type = win32api.RegQueryValueEx(key, 'InstallPath') - bin_search_path = [join(str(value), 'bin')] + win32con.HKEY_LOCAL_MACHINE, r"SOFTWARE\ATT\Graphviz" + ) + value, type = win32api.RegQueryValueEx(key, "InstallPath") + bin_search_path = [join(str(value), "bin")] except: if key: win32api.RegCloseKey(key) @@ -37,7 +41,7 @@ pass else: # for posix systems - DOT_EXE = 'dot' + DOT_EXE = "dot" path = os.getenv("PATH") bin_search_path = path.split(":") @@ -62,6 +66,7 @@ def bin_search(binary): raise MissingBinary('Unable to find binary "%s"' % binary) return result + try: bin = bin_search(DOT_EXE) HAS_GRAPHVIZ = True @@ -80,21 +85,21 @@ def getObjectTitle(object): if not title: title = id else: - title = '%s\\n(id: %s)' % (title, id) + title = "%s\\n(id: %s)" % (title, id) return title def getGuardTitle(guard): - out = '' + out = "" if guard is not None: if guard.expr: - out += 'Expression: %s; ' % guard.expr.text + out += "Expression: %s; " % guard.expr.text if guard.permissions: - out += 'Permissions: %s; ' % ','.join(guard.permissions) + out += "Permissions: %s; " % ",".join(guard.permissions) if guard.roles: - out += 'Roles: %s; ' % ','.join(guard.roles) + out += "Roles: %s; " % ",".join(guard.roles) if guard.groups: - out += 'Groups: %s; ' % ','.join(guard.groups) + out += "Groups: %s; " % ",".join(guard.groups) return out @@ -114,15 +119,17 @@ def getPOT(wf): s_id = s.getId() s_title = getObjectTitle(s) out.append( - '"%s" [shape=box,label="%s",style="filled",fillcolor="#ffcc99"];' % ( - s_id, s_title)) + '"%s" [shape=box,label="%s",style="filled",fillcolor="#ffcc99"];' + % (s_id, s_title) + ) for t_id in s.transitions: transitions_with_init_state.append(t_id) try: t = wf.transitions[t_id] except KeyError: - out.append(('# transition "%s" from state "%s" ' - 'is missing' % (t_id, s_id))) + out.append( + ('# transition "%s" from state "%s" ' "is missing" % (t_id, s_id)) + ) continue new_state_id = t.new_state_id @@ -153,11 +160,10 @@ def getPOT(wf): transitions[key] = value for k, v in transitions.items(): - out.append('"%s" -> "%s" [label="%s"];' % (k[0], k[1], - ',\\n'.join(v))) + out.append('"%s" -> "%s" [label="%s"];' % (k[0], k[1], ",\\n".join(v))) - out.append('}') - return '\n'.join(out) + out.append("}") + return "\n".join(out) def getGraph(workflow, format="gif"): @@ -166,19 +172,18 @@ def getGraph(workflow, format="gif"): http://www.openflow.it/wwwopenflow/Download/OpenFlowEditor_0_4.tgz """ pot = getPOT(workflow) - portal_properties = getToolByName(workflow, 'portal_properties') - encoding = portal_properties.site_properties.getProperty( - 'default_charset', 'utf-8') - if isinstance(pot, unicode): + portal_properties = getToolByName(workflow, "portal_properties") + encoding = portal_properties.site_properties.getProperty("default_charset", "utf-8") + if isinstance(pot, six.text_type): pot = pot.encode(encoding) - infile = mktemp('.dot') - f = open(infile, 'w') + infile = mktemp(".dot") + f = open(infile, "wb") f.write(pot) f.close() - outfile = mktemp('.gif') - os.system('%s -Tgif -o %s %s' % (bin, outfile, infile)) - out = open(outfile, 'rb') + outfile = mktemp(".gif") + os.system("%s -Tgif -o %s %s" % (bin, outfile, infile)) + out = open(outfile, "rb") result = out.read() out.close() os.remove(outfile) diff --git a/src/plone/app/workflowmanager/permissions.py b/src/plone/app/workflowmanager/permissions.py index 68121d5..dc26365 100644 --- a/src/plone/app/workflowmanager/permissions.py +++ b/src/plone/app/workflowmanager/permissions.py @@ -8,14 +8,14 @@ def managed_permissions(wfid=None): return [] site = getSite() - wtool = getToolByName(site, 'portal_workflow') + wtool = getToolByName(site, "portal_workflow") wf = wtool.get(wfid) items = [] for permission in wf.permissions: data = {} - data['perm'] = permission - data['name'] = _(permission) - data['description'] = u'' + data["perm"] = permission + data["name"] = _(permission) + data["description"] = u"" items.append(data) return items @@ -24,6 +24,6 @@ def managed_permissions(wfid=None): def allowed_guard_permissions(wfid=None): res = {} for item in managed_permissions(wfid): - res[item.get('name')] = item.get('name') + res[item.get("name")] = item.get("name") return res diff --git a/src/plone/app/workflowmanager/profiles/default/controlpanel.xml b/src/plone/app/workflowmanager/profiles/default/controlpanel.xml index 4c66457..11f9b58 100644 --- a/src/plone/app/workflowmanager/profiles/default/controlpanel.xml +++ b/src/plone/app/workflowmanager/profiles/default/controlpanel.xml @@ -1,15 +1,21 @@ - + name="portal_controlpanel" + i18n:domain="plone.app.workflowmanager" +> - + plone.app.workflowmanager: Manage Workflows - - \ No newline at end of file + + diff --git a/src/plone/app/workflowmanager/profiles/default/metadata.xml b/src/plone/app/workflowmanager/profiles/default/metadata.xml index 5476488..a036d4b 100644 --- a/src/plone/app/workflowmanager/profiles/default/metadata.xml +++ b/src/plone/app/workflowmanager/profiles/default/metadata.xml @@ -1,7 +1,5 @@ 1 - - profile-plone.app.jquerytools:default - + diff --git a/src/plone/app/workflowmanager/profiles/default/registry.xml b/src/plone/app/workflowmanager/profiles/default/registry.xml index 123a0cf..a66c262 100644 --- a/src/plone/app/workflowmanager/profiles/default/registry.xml +++ b/src/plone/app/workflowmanager/profiles/default/registry.xml @@ -1,10 +1,10 @@ - - - Layouts - - - - + + + Layouts + + + + diff --git a/src/plone/app/workflowmanager/profiles/uninstall/controlpanel.xml b/src/plone/app/workflowmanager/profiles/uninstall/controlpanel.xml index 707f351..e438ad0 100644 --- a/src/plone/app/workflowmanager/profiles/uninstall/controlpanel.xml +++ b/src/plone/app/workflowmanager/profiles/uninstall/controlpanel.xml @@ -1,15 +1,22 @@ - + name="portal_controlpanel" + i18n:domain="plone.app.workflowmanager" +> - + plone.app.workflowmanager: Manage Workflows - \ No newline at end of file + diff --git a/src/plone/app/workflowmanager/profiles/uninstall/registry.xml b/src/plone/app/workflowmanager/profiles/uninstall/registry.xml index c4deda6..1d4f2db 100644 --- a/src/plone/app/workflowmanager/profiles/uninstall/registry.xml +++ b/src/plone/app/workflowmanager/profiles/uninstall/registry.xml @@ -1,9 +1,11 @@ - - - Layouts - - - - + + + Layouts + + + + diff --git a/src/plone/app/workflowmanager/testing.py b/src/plone/app/workflowmanager/testing.py index 45d7035..4cc7c16 100644 --- a/src/plone/app/workflowmanager/testing.py +++ b/src/plone/app/workflowmanager/testing.py @@ -1,87 +1,106 @@ -from plone.app.testing import TEST_USER_NAME, PLONE_FIXTURE, login, \ - IntegrationTesting, PloneSandboxLayer, applyProfile, setRoles, \ - TEST_USER_ID, TEST_USER_PASSWORD, FunctionalTesting - -#from Products.CMFCore.utils import getToolByName -from zope.interface.declarations import alsoProvides +from plone.app.contentrules.actions.notify import NotifyAction +from plone.app.testing import applyProfile +from plone.app.testing import FunctionalTesting +from plone.app.testing import IntegrationTesting +from plone.app.testing import login +from plone.app.testing import PLONE_FIXTURE +from plone.app.testing import PloneSandboxLayer +from plone.app.testing import setRoles +from plone.app.testing import TEST_USER_ID +from plone.app.testing import TEST_USER_NAME +from plone.app.testing import TEST_USER_PASSWORD +from plone.app.workflowmanager.actionmanager import ActionManager +from plone.app.workflowmanager.browser.actions import AddActionView +from plone.app.workflowmanager.browser.workflow import AddWorkflow +from plone.keyring.interfaces import IKeyManager +from plone.protect.authenticator import createToken +from zope.annotation.interfaces import IAttributeAnnotatable from zope.component import getUtility from zope.configuration import xmlconfig +# from Products.CMFCore.utils import getToolByName +from zope.interface.declarations import alsoProvides from zope.publisher.browser import TestRequest -from zope.annotation.interfaces import IAttributeAnnotatable - -from plone.app.workflowmanager.browser.workflow import AddWorkflow -from plone.app.workflowmanager.browser.actions import AddActionView -from plone.app.workflowmanager.actionmanager import ActionManager -from plone.app.contentrules.actions.notify import NotifyAction -from plone.keyring.interfaces import IKeyManager -from plone.protect.authenticator import createToken +import hmac +import unittest -import unittest2 as unittest try: from hashlib import sha1 as sha except ImportError: import sha -import hmac class ManagerFixture(PloneSandboxLayer): - defaultBases = (PLONE_FIXTURE, ) + defaultBases = (PLONE_FIXTURE,) def setUpZope(self, app, configurationContext): # Load ZCML import plone.app.workflowmanager - xmlconfig.file('configure.zcml', - plone.app.workflowmanager, context=configurationContext) + + xmlconfig.file( + "configure.zcml", plone.app.workflowmanager, context=configurationContext + ) def setUpPloneSite(self, portal): - applyProfile(portal, 'plone.app.workflowmanager:default') - setRoles(portal, TEST_USER_ID, ['Manager', 'Owner']) + applyProfile(portal, "plone.app.workflowmanager:default") + setRoles(portal, TEST_USER_ID, ["Manager", "Owner"]) import transaction + transaction.commit() login(portal, TEST_USER_NAME) MANAGER_FIXTURE = ManagerFixture() INTEGRATION_MANAGER_TESTING = IntegrationTesting( - bases=(MANAGER_FIXTURE, ), name='INTEGRATION_MANAGER_TESTING') + bases=(MANAGER_FIXTURE,), name="INTEGRATION_MANAGER_TESTING" +) FUNCTIONAL_MANAGER_TESTING = FunctionalTesting( - bases=(MANAGER_FIXTURE,), name="FUNCTIONAL_MANAGER_TESTING") + bases=(MANAGER_FIXTURE,), name="FUNCTIONAL_MANAGER_TESTING" +) def browserLogin(portal, browser, username=None, password=None): handleErrors = browser.handleErrors try: browser.handleErrors = False - browser.open(portal.absolute_url() + '/login_form') + browser.open(portal.absolute_url() + "/login_form") if username is None: username = TEST_USER_NAME if password is None: password = TEST_USER_PASSWORD - browser.addHeader('Authorization', - 'Basic %s:%s' % (TEST_USER_NAME, TEST_USER_PASSWORD,)) + browser.addHeader( + "Authorization", "Basic %s:%s" % (TEST_USER_NAME, TEST_USER_PASSWORD,) + ) finally: browser.handleErrors = handleErrors class BaseTest(unittest.TestCase): - def setUp(self): - portal = self.layer['portal'] - - req = self.getRequest({'workflow-name': 'workflow-1', - 'form.actions.add': 'create', - 'clone-from-workflow': 'simple_publication_workflow'}, True) + portal = self.layer["portal"] + + req = self.getRequest( + { + "workflow-name": "workflow-1", + "form.actions.add": "create", + "clone-from-workflow": "simple_publication_workflow", + }, + True, + ) alsoProvides(req, IAttributeAnnotatable) AddWorkflow(portal, req)() # add some rules/actions - req = self.getRequest({ - 'form.actions.add': 'Add', - 'selected-transition': 'publish', - 'selected-state': 'published', - 'selected-workflow': 'workflow-1'}, True) + req = self.getRequest( + { + "form.actions.add": "Add", + "selected-transition": "publish", + "selected-state": "published", + "selected-workflow": "workflow-1", + }, + True, + ) view = AddActionView(portal, req) view() self.selected_workflow = view.selected_workflow @@ -91,17 +110,16 @@ def setUp(self): am = ActionManager() rule = am.get_rule(self.selected_transition) action = NotifyAction() - action.message = 'foobar' - action.message_type = 'info' + action.message = "foobar" + action.message_type = "info" rule.actions.append(action) def getRequest(self, form={}, authentic=False): if authentic: - form['_authenticator'] = createToken() + form["_authenticator"] = createToken() - req = TestRequest(form=form, environ={ - 'SERVER_URL': 'http://nohost', - 'HTTP_HOST': 'nohost' - }) + req = TestRequest( + form=form, environ={"SERVER_URL": "http://nohost", "HTTP_HOST": "nohost"} + ) alsoProvides(req, IAttributeAnnotatable) return req diff --git a/src/plone/app/workflowmanager/tests/__init__.py b/src/plone/app/workflowmanager/tests/__init__.py index 1023dcd..188517f 100644 --- a/src/plone/app/workflowmanager/tests/__init__.py +++ b/src/plone/app/workflowmanager/tests/__init__.py @@ -1,7 +1,4 @@ - - class TestResponse(object): - def __init__(self): self.headers = {} self.redirect = False diff --git a/src/plone/app/workflowmanager/tests/robot/CustomSeleniumLibrary.py b/src/plone/app/workflowmanager/tests/robot/CustomSeleniumLibrary.py index bd73de4..5c26d02 100644 --- a/src/plone/app/workflowmanager/tests/robot/CustomSeleniumLibrary.py +++ b/src/plone/app/workflowmanager/tests/robot/CustomSeleniumLibrary.py @@ -1,10 +1,11 @@ +from __future__ import print_function from Selenium2Library import Selenium2Library -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.ui import WebDriverWait -class CustomSeleniumLibrary(Selenium2Library): +class CustomSeleniumLibrary(Selenium2Library): def clear_element(self, element): self._current_browser().find_element_by_id(element).clear() return True @@ -15,21 +16,29 @@ def get_newest_tinyMCE_window(self): return True def get_new_window_id(self): - frame = self._current_browser().execute_script('return tinyMCE.activeEditor.windowManager._frontWindow().iframeElement.id') + frame = self._current_browser().execute_script( + "return tinyMCE.activeEditor.windowManager._frontWindow().iframeElement.id" + ) return frame def handle_prompts(self): # Thanks to nemesys on StackOverflow :) try: - WebDriverWait(self._current_browser(), 3).until(EC.alert_is_present(), 'Failure') + WebDriverWait(self._current_browser(), 3).until( + EC.alert_is_present(), "Failure" + ) alert = self._current_browser().switch_to_alert() alert.accept() - print "alert accepted" + print("alert accepted") except TimeoutException: raise AssertionError("No confirmation alert.") def wait_for_new_window(self): wait = WebDriverWait(self._current_browser(), 10) - wait.until(lambda driver: self._current_browser().find_element_by_id(self.get_new_window_id())) + wait.until( + lambda driver: self._current_browser().find_element_by_id( + self.get_new_window_id() + ) + ) return True diff --git a/src/plone/app/workflowmanager/tests/test_actions.py b/src/plone/app/workflowmanager/tests/test_actions.py index d42c23a..baf1504 100644 --- a/src/plone/app/workflowmanager/tests/test_actions.py +++ b/src/plone/app/workflowmanager/tests/test_actions.py @@ -1,20 +1,17 @@ -import unittest2 as unittest - -from zope.component import getUtility, getMultiAdapter - -from Products.CMFCore.utils import getToolByName - -from plone.app.testing import TEST_USER_NAME from plone.app.testing import login - -from plone.contentrules.rule.interfaces import IRuleAction - -from plone.app.workflowmanager.testing import INTEGRATION_MANAGER_TESTING -from plone.app.workflowmanager.testing import BaseTest -from plone.app.workflowmanager.browser.actions import AddActionView -from plone.app.workflowmanager.browser.actions import DeleteActionView +from plone.app.testing import TEST_USER_NAME from plone.app.workflowmanager.actionmanager import ActionManager from plone.app.workflowmanager.actionmanager import RuleAdapter +from plone.app.workflowmanager.browser.actions import AddActionView +from plone.app.workflowmanager.browser.actions import DeleteActionView +from plone.app.workflowmanager.testing import BaseTest +from plone.app.workflowmanager.testing import INTEGRATION_MANAGER_TESTING +from plone.contentrules.rule.interfaces import IRuleAction +from Products.CMFCore.utils import getToolByName +from zope.component import getMultiAdapter +from zope.component import getUtility + +import unittest class TestActions(BaseTest): @@ -22,12 +19,16 @@ class TestActions(BaseTest): layer = INTEGRATION_MANAGER_TESTING def test_adding_action(self): - portal = self.layer['portal'] + portal = self.layer["portal"] login(portal, TEST_USER_NAME) - req = self.getRequest({ - 'form.actions.add': 'Add', - 'selected-transition': 'retract', - 'selected-workflow': 'workflow-1'}, True) + req = self.getRequest( + { + "form.actions.add": "Add", + "selected-transition": "retract", + "selected-workflow": "workflow-1", + }, + True, + ) view = AddActionView(portal, req) view() am = ActionManager() @@ -36,48 +37,54 @@ def test_adding_action(self): @unittest.skip("'rule' is None before and after calling view.") def test_adding_action_fails(self): - portal = self.layer['portal'] + portal = self.layer["portal"] login(portal, TEST_USER_NAME) - req = self.getRequest({ - 'selected-transition': 'retract', - 'selected-workflow': 'workflow-1'}, True) + req = self.getRequest( + {"selected-transition": "retract", "selected-workflow": "workflow-1"}, True + ) view = AddActionView(portal, req) try: view() - except AttributeError, ex: - self.assertTrue("'TestRequest' object has no attribute 'RESPONSE'" - in str(ex)) + except AttributeError as ex: + self.assertTrue( + "'TestRequest' object has no attribute 'RESPONSE'" in str(ex) + ) am = ActionManager() rule = am.get_rule(view.selected_transition) self.assertTrue(rule is None) @unittest.skip("'rule' is None before and after calling view.") def test_accessing_adding_action(self): - portal = self.layer['portal'] + portal = self.layer["portal"] login(portal, TEST_USER_NAME) - req = self.getRequest({ - 'selected-transition': 'publish', - 'selected-workflow': 'workflow-1'}, True) + req = self.getRequest( + {"selected-transition": "publish", "selected-workflow": "workflow-1"}, True + ) view = DeleteActionView(portal, req) try: view() - except AttributeError, ex: - self.assertTrue("'TestRequest' object has no attribute 'RESPONSE'" - in str(ex)) + except AttributeError as ex: + self.assertTrue( + "'TestRequest' object has no attribute 'RESPONSE'" in str(ex) + ) am = ActionManager() rule = am.get_rule(view.selected_transition) self.assertTrue(len(rule.actions) == 1) def test_removing_action(self): - portal = self.layer['portal'] + portal = self.layer["portal"] login(portal, TEST_USER_NAME) - req = self.getRequest({ - 'form.actions.delete': 'Delete', - 'selected-transition': 'publish', - 'selected-workflow': 'workflow-1', - 'action_index': '0'}, True) + req = self.getRequest( + { + "form.actions.delete": "Delete", + "selected-transition": "publish", + "selected-workflow": "workflow-1", + "action_index": "0", + }, + True, + ) view = DeleteActionView(portal, req) view() am = ActionManager() @@ -85,13 +92,17 @@ def test_removing_action(self): self.assertEquals(len(rule.actions), 0) def test_cancel_removing_action(self): - portal = self.layer['portal'] + portal = self.layer["portal"] login(portal, TEST_USER_NAME) - req = self.getRequest({ - 'form.actions.cancel': 'Cancel', - 'selected-transition': 'publish', - 'selected-workflow': 'workflow-1'}, True) + req = self.getRequest( + { + "form.actions.cancel": "Cancel", + "selected-transition": "publish", + "selected-workflow": "workflow-1", + }, + True, + ) view = DeleteActionView(portal, req) view() am = ActionManager() @@ -99,115 +110,117 @@ def test_cancel_removing_action(self): self.assertEquals(len(rule.actions), 1) def test_action_manager_to_create_action(self): - portal = self.layer['portal'] + portal = self.layer["portal"] am = ActionManager() - pw = getToolByName(portal, 'portal_workflow') - workflow = pw['simple_publication_workflow'] - transition = workflow.transitions['publish'] + pw = getToolByName(portal, "portal_workflow") + workflow = pw["simple_publication_workflow"] + transition = workflow.transitions["publish"] am.delete_rule_for(transition) rule = am.create(transition) - element = getUtility(IRuleAction, name='plone.actions.Copy') - adding = getMultiAdapter((rule.rule, self.layer['request']), - name='+action') - addview = getMultiAdapter((adding, self.layer['request']), - name=element.addview) + element = getUtility(IRuleAction, name="plone.actions.Copy") + adding = getMultiAdapter((rule.rule, self.layer["request"]), name="+action") + addview = getMultiAdapter((adding, self.layer["request"]), name=element.addview) try: createAndAdd = addview.form_instance.createAndAdd except AttributeError: createAndAdd = addview.createAndAdd - createAndAdd(data={'target_folder': '/target'}) + createAndAdd(data={"target_folder": "/target"}) self.assertEquals(len(rule.actions), 1) def test_action_manager_get_action(self): - portal = self.layer['portal'] + portal = self.layer["portal"] am = ActionManager() - pw = getToolByName(portal, 'portal_workflow') - workflow = pw['simple_publication_workflow'] - transition = workflow.transitions['publish'] + pw = getToolByName(portal, "portal_workflow") + workflow = pw["simple_publication_workflow"] + transition = workflow.transitions["publish"] am.delete_rule_for(transition) rule = am.create(transition) - element = getUtility(IRuleAction, name='plone.actions.Copy') - adding = getMultiAdapter((rule.rule, self.layer['request']), - name='+action') - addview = getMultiAdapter((adding, self.layer['request']), - name=element.addview) + element = getUtility(IRuleAction, name="plone.actions.Copy") + adding = getMultiAdapter((rule.rule, self.layer["request"]), name="+action") + addview = getMultiAdapter((adding, self.layer["request"]), name=element.addview) try: createAndAdd = addview.form_instance.createAndAdd except AttributeError: createAndAdd = addview.createAndAdd - createAndAdd(data={'target_folder': '/target'}) + createAndAdd(data={"target_folder": "/target"}) ra = RuleAdapter(rule, transition) action = ra.get_action(0) - self.assertEquals(action.element, 'plone.actions.Copy') + self.assertEquals(action.element, "plone.actions.Copy") def test_action_manager_action_index(self): - portal = self.layer['portal'] + portal = self.layer["portal"] am = ActionManager() - pw = getToolByName(portal, 'portal_workflow') - workflow = pw['simple_publication_workflow'] - transition = workflow.transitions['publish'] + pw = getToolByName(portal, "portal_workflow") + workflow = pw["simple_publication_workflow"] + transition = workflow.transitions["publish"] rule = am.create(transition) - element = getUtility(IRuleAction, name='plone.actions.Copy') - adding = getMultiAdapter((rule.rule, self.layer['request']), - name='+action') - addview = getMultiAdapter((adding, self.layer['request']), - name=element.addview) + element = getUtility(IRuleAction, name="plone.actions.Copy") + adding = getMultiAdapter((rule.rule, self.layer["request"]), name="+action") + addview = getMultiAdapter((adding, self.layer["request"]), name=element.addview) try: createAndAdd = addview.form_instance.createAndAdd except AttributeError: createAndAdd = addview.createAndAdd - createAndAdd(data={'target_folder': '/target'}) + createAndAdd(data={"target_folder": "/target"}) ra = RuleAdapter(rule, transition) action = ra.get_action(0) self.assertEquals(ra.action_index(action), 0) def test_action_manager_action_url(self): - portal = self.layer['portal'] + portal = self.layer["portal"] am = ActionManager() - pw = getToolByName(portal, 'portal_workflow') - workflow = pw['simple_publication_workflow'] - transition = workflow.transitions['publish'] + pw = getToolByName(portal, "portal_workflow") + workflow = pw["simple_publication_workflow"] + transition = workflow.transitions["publish"] rule = am.create(transition) - element = getUtility(IRuleAction, name='plone.actions.Copy') - adding = getMultiAdapter((rule.rule, self.layer['request']), - name='+action') - addview = getMultiAdapter((adding, self.layer['request']), - name=element.addview) + element = getUtility(IRuleAction, name="plone.actions.Copy") + adding = getMultiAdapter((rule.rule, self.layer["request"]), name="+action") + addview = getMultiAdapter((adding, self.layer["request"]), name=element.addview) try: createAndAdd = addview.form_instance.createAndAdd except AttributeError: createAndAdd = addview.createAndAdd - createAndAdd(data={'target_folder': '/target'}) + createAndAdd(data={"target_folder": "/target"}) ra = RuleAdapter(rule, transition) action = ra.get_action(0) - self.assertTrue(rule.rule.id in ra.action_url(action) and \ - '++0' in ra.action_url(action)) + self.assertTrue( + rule.rule.id in ra.action_url(action) and "++0" in ra.action_url(action) + ) def test_action_manager_available_actions(self): am = ActionManager() action_names = [a.title for a in am.available_actions] - self.assertTrue(action_names == [u'Logger', u'Notify user', - u'Copy to folder', u'Move to folder', u'Delete object', - u'Transition workflow state', u'Send email']) + self.assertTrue( + action_names + == [ + u"Logger", + u"Notify user", + u"Copy to folder", + u"Move to folder", + u"Delete object", + u"Transition workflow state", + u"Send email", + ] + ) def test_action_manager_delete_rule(self): - portal = self.layer['portal'] + portal = self.layer["portal"] am = ActionManager() - pw = getToolByName(portal, 'portal_workflow') - workflow = pw['simple_publication_workflow'] - transition = workflow.transitions['publish'] + pw = getToolByName(portal, "portal_workflow") + workflow = pw["simple_publication_workflow"] + transition = workflow.transitions["publish"] am.create(transition) am.delete_rule_for(transition) diff --git a/src/plone/app/workflowmanager/tests/test_controlpanel.py b/src/plone/app/workflowmanager/tests/test_controlpanel.py index 97f48b2..5f0beef 100644 --- a/src/plone/app/workflowmanager/tests/test_controlpanel.py +++ b/src/plone/app/workflowmanager/tests/test_controlpanel.py @@ -1,10 +1,9 @@ -import unittest2 as unittest - from AccessControl import Unauthorized - -from plone.app.workflowmanager.testing import INTEGRATION_MANAGER_TESTING -from plone.app.workflowmanager.testing import BaseTest from plone.app.workflowmanager.browser.controlpanel import Base +from plone.app.workflowmanager.testing import BaseTest +from plone.app.workflowmanager.testing import INTEGRATION_MANAGER_TESTING + +import unittest class TestControlPanel(BaseTest): @@ -12,45 +11,64 @@ class TestControlPanel(BaseTest): layer = INTEGRATION_MANAGER_TESTING def test_base_defaults_to_first_workflow_if_list(self): - view = Base(self.layer['portal'], - self.getRequest( - {'selected-workflow': ['simple_publication_workflow']})) + view = Base( + self.layer["portal"], + self.getRequest({"selected-workflow": ["simple_publication_workflow"]}), + ) self.assertTrue(view.selected_workflow is not None) def test_base_defaults_to_first_state_if_list(self): - view = Base(self.layer['portal'], self.getRequest({ - 'selected-workflow': ['simple_publication_workflow'], - 'selected-state': ['published']})) + view = Base( + self.layer["portal"], + self.getRequest( + { + "selected-workflow": ["simple_publication_workflow"], + "selected-state": ["published"], + } + ), + ) self.assertTrue(view.selected_state is not None) def test_base_defaults_to_first_transition_if_list(self): - view = Base(self.layer['portal'], self.getRequest({ - 'selected-workflow': ['simple_publication_workflow'], - 'selected-transition': ['publish']})) + view = Base( + self.layer["portal"], + self.getRequest( + { + "selected-workflow": ["simple_publication_workflow"], + "selected-transition": ["publish"], + } + ), + ) self.assertTrue(view.selected_transition is not None) def test_base_available_transitions_always_returns_a_list(self): - view = Base(self.layer['portal'], self.getRequest({ - 'selected-workflow': ['one_state_workflow']})) + view = Base( + self.layer["portal"], + self.getRequest({"selected-workflow": ["one_state_workflow"]}), + ) self.assertEquals(type(view.available_transitions), list) def test_base_available_states_always_returns_a_list(self): - view = Base(self.layer['portal'], self.getRequest({})) + view = Base(self.layer["portal"], self.getRequest({})) self.assertEquals(type(view.available_states), list) def test_authorize_raises_unauthorized(self): - view = Base(self.layer['portal'], self.getRequest({})) + view = Base(self.layer["portal"], self.getRequest({})) self.assertRaises(Unauthorized, view.authorize) def test_get_transition(self): - view = Base(self.layer['portal'], self.getRequest({ - 'selected-workflow': ['simple_publication_workflow']})) - self.assertTrue(view.get_transition('publish') is not None) + view = Base( + self.layer["portal"], + self.getRequest({"selected-workflow": ["simple_publication_workflow"]}), + ) + self.assertTrue(view.get_transition("publish") is not None) def test_get_transition_is_none_if_not_found(self): - view = Base(self.layer['portal'], self.getRequest({ - 'selected-workflow' : ['simple_publication_workflow']})) - self.assertTrue(view.get_transition('foobar') is None) + view = Base( + self.layer["portal"], + self.getRequest({"selected-workflow": ["simple_publication_workflow"]}), + ) + self.assertTrue(view.get_transition("foobar") is None) def test_suite(): diff --git a/src/plone/app/workflowmanager/tests/test_docs.py b/src/plone/app/workflowmanager/tests/test_docs.py index 3737969..2dcd41c 100644 --- a/src/plone/app/workflowmanager/tests/test_docs.py +++ b/src/plone/app/workflowmanager/tests/test_docs.py @@ -1,27 +1,34 @@ -import doctest -from plone.testing import layered -import unittest2 as unittest from plone.app.workflowmanager.testing import FUNCTIONAL_MANAGER_TESTING -import pprint +from plone.testing import layered + +import doctest import interlude +import pprint +import unittest + -optionflags = (doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE) +optionflags = doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE normal_testfiles = [ - '../standardtiles.txt', - '../head.txt', + "../standardtiles.txt", + "../head.txt", ] testtype_testfiles = [ - '../field.txt', + "../field.txt", ] def test_suite(): suite = unittest.TestSuite() - suite.addTests([ - layered(doctest.DocFileSuite('../browser.txt', - optionflags=optionflags, - globs={'interact': interlude.interact, - 'pprint': pprint.pprint}, - ), - layer=FUNCTIONAL_MANAGER_TESTING)]) + suite.addTests( + [ + layered( + doctest.DocFileSuite( + "../browser.txt", + optionflags=optionflags, + globs={"interact": interlude.interact, "pprint": pprint.pprint}, + ), + layer=FUNCTIONAL_MANAGER_TESTING, + ) + ] + ) return suite diff --git a/src/plone/app/workflowmanager/tests/test_layouts.py b/src/plone/app/workflowmanager/tests/test_layouts.py index 26ed530..4e92031 100644 --- a/src/plone/app/workflowmanager/tests/test_layouts.py +++ b/src/plone/app/workflowmanager/tests/test_layouts.py @@ -1,22 +1,18 @@ -import unittest2 as unittest - -from zope.component import getUtility, getMultiAdapter - -from Products.CMFCore.utils import getToolByName - -from plone.app.testing import TEST_USER_NAME from plone.app.testing import login - -from plone.contentrules.rule.interfaces import IRuleAction - -from plone.app.workflowmanager.testing import INTEGRATION_MANAGER_TESTING -from plone.app.workflowmanager.testing import BaseTest -from plone.app.workflowmanager.browser.actions import AddActionView -from plone.app.workflowmanager.browser.actions import DeleteActionView +from plone.app.testing import TEST_USER_NAME from plone.app.workflowmanager.actionmanager import ActionManager from plone.app.workflowmanager.actionmanager import RuleAdapter - +from plone.app.workflowmanager.browser.actions import AddActionView +from plone.app.workflowmanager.browser.actions import DeleteActionView from plone.app.workflowmanager.browser.layout import GraphLayout +from plone.app.workflowmanager.testing import BaseTest +from plone.app.workflowmanager.testing import INTEGRATION_MANAGER_TESTING +from plone.contentrules.rule.interfaces import IRuleAction +from Products.CMFCore.utils import getToolByName +from zope.component import getMultiAdapter +from zope.component import getUtility + +import unittest class TestActions(BaseTest): @@ -24,14 +20,17 @@ class TestActions(BaseTest): layer = INTEGRATION_MANAGER_TESTING def test_prop_sheet_exists(self): - portal = self.layer['portal'] + portal = self.layer["portal"] login(portal, TEST_USER_NAME) - req = self.getRequest({ - 'selected-workflow': ['simple_publication_workflow'], - 'selected-state': ['published']}) + req = self.getRequest( + { + "selected-workflow": ["simple_publication_workflow"], + "selected-state": ["published"], + } + ) gl = GraphLayout(portal, req) - props = getToolByName(portal, 'portal_properties') + props = getToolByName(portal, "portal_properties") sheetName = gl.getPropSheetName() props.addPropertySheet(sheetName) @@ -40,16 +39,19 @@ def test_prop_sheet_exists(self): self.assertTrue(exists) def test_create_prop_sheet(self): - portal = self.layer['portal'] + portal = self.layer["portal"] login(portal, TEST_USER_NAME) - req = self.getRequest({ - 'selected-workflow': ['simple_publication_workflow'], - 'selected-state': ['published']}) + req = self.getRequest( + { + "selected-workflow": ["simple_publication_workflow"], + "selected-state": ["published"], + } + ) gl = GraphLayout(portal, req) sheetName = gl.getPropSheetName() - props = getToolByName(portal, 'portal_properties') + props = getToolByName(portal, "portal_properties") exists = gl.propSheetExists(sheetName) self.assertFalse(exists) @@ -60,91 +62,108 @@ def test_create_prop_sheet(self): self.assertTrue(exists) def test_layout_exists(self): - portal = self.layer['portal'] + portal = self.layer["portal"] login(portal, TEST_USER_NAME) - req = self.getRequest({ - 'selected-workflow': ['simple_publication_workflow'], - 'selected-state': ['published']}) + req = self.getRequest( + { + "selected-workflow": ["simple_publication_workflow"], + "selected-state": ["published"], + } + ) gl = GraphLayout(portal, req) sheetName = gl.getPropSheetName() - props = getToolByName(portal, 'portal_properties') + props = getToolByName(portal, "portal_properties") props.addPropertySheet(sheetName) - gl.setWorkflow('simple_publication_workflow') + gl.setWorkflow("simple_publication_workflow") - props[sheetName].manage_addProperty('simple_publication_workflow', '','text') + props[sheetName].manage_addProperty("simple_publication_workflow", "", "text") exists = gl.layoutExists() - self.assertEqual( exists, 1 ) + self.assertEqual(exists, 1) def test_create_layout(self): - portal = self.layer['portal'] + portal = self.layer["portal"] login(portal, TEST_USER_NAME) - req = self.getRequest({ - 'selected-workflow': ['simple_publication_workflow'], - 'selected-state': ['published']}) + req = self.getRequest( + { + "selected-workflow": ["simple_publication_workflow"], + "selected-state": ["published"], + } + ) gl = GraphLayout(portal, req) sheetName = gl.getPropSheetName() - gl.setWorkflow('simple_publication_workflow') + gl.setWorkflow("simple_publication_workflow") - props = getToolByName(portal, 'portal_properties') + props = getToolByName(portal, "portal_properties") props.addPropertySheet(sheetName) - + gl.createLayout() - exists = props[sheetName].hasProperty('simple_publication_workflow') - self.assertEqual( exists, 1 ) + exists = props[sheetName].hasProperty("simple_publication_workflow") + self.assertEqual(exists, 1) def test_get_layout(self): - portal = self.layer['portal'] + portal = self.layer["portal"] login(portal, TEST_USER_NAME) - req = self.getRequest({ - 'selected-workflow': ['simple_publication_workflow'], - 'selected-state': ['published']}) + req = self.getRequest( + { + "selected-workflow": ["simple_publication_workflow"], + "selected-state": ["published"], + } + ) gl = GraphLayout(portal, req) sheetName = gl.getPropSheetName() - props = getToolByName(portal, 'portal_properties') + props = getToolByName(portal, "portal_properties") props.addPropertySheet(sheetName) sheetName = gl.getPropSheetName() - props[sheetName].manage_addProperty('simple_publication_workflow', 'test', 'text') + props[sheetName].manage_addProperty( + "simple_publication_workflow", "test", "text" + ) output = gl.getLayout() - self.assertEqual( output, 'test' ) + self.assertEqual(output, "test") def test_get_layout(self): - portal = self.layer['portal'] + portal = self.layer["portal"] login(portal, TEST_USER_NAME) - req = self.getRequest({ - 'selected-workflow': ['simple_publication_workflow'], - 'selected-state': ['published']}) + req = self.getRequest( + { + "selected-workflow": ["simple_publication_workflow"], + "selected-state": ["published"], + } + ) gl = GraphLayout(portal, req) sheetName = gl.getPropSheetName() - gl.setWorkflow('simple_publication_workflow') + gl.setWorkflow("simple_publication_workflow") - props = getToolByName(portal, 'portal_properties') + props = getToolByName(portal, "portal_properties") props.addPropertySheet(sheetName) sheetName = gl.getPropSheetName() - props[sheetName].manage_addProperty('simple_publication_workflow', 'test', 'text') + props[sheetName].manage_addProperty( + "simple_publication_workflow", "test", "text" + ) output = gl.getLayout() gl.editLayout("words words words") output2 = gl.getLayout() - - self.assertNotEqual( output, output2 ) + + self.assertNotEqual(output, output2) + def test_suite(): return unittest.defaultTestLoader.loadTestsFromName(__name__) diff --git a/src/plone/app/workflowmanager/tests/test_utils.py b/src/plone/app/workflowmanager/tests/test_utils.py index 826a51f..fa8bb7c 100644 --- a/src/plone/app/workflowmanager/tests/test_utils.py +++ b/src/plone/app/workflowmanager/tests/test_utils.py @@ -1,10 +1,9 @@ -import unittest2 as unittest - -from plone.app.workflowmanager.testing import INTEGRATION_MANAGER_TESTING from plone.app.workflowmanager.testing import BaseTest - +from plone.app.workflowmanager.testing import INTEGRATION_MANAGER_TESTING from plone.app.workflowmanager.utils import generate_id +import unittest + class TestUtils(BaseTest): @@ -17,14 +16,14 @@ def test_generate_id(self): self.assertEquals(title, new_id) def test_generate_id_with_ids(self): - title = '1' - ids = ['1', '2', '3'] + title = "1" + ids = ["1", "2", "3"] new_id = generate_id(title, ids) - self.assertEquals(title + '-1', new_id) + self.assertEquals(title + "-1", new_id) ids.append(new_id) new_id = generate_id(title, ids) - self.assertEquals(title + '-2', new_id) + self.assertEquals(title + "-2", new_id) def test_suite(): diff --git a/src/plone/app/workflowmanager/utils.py b/src/plone/app/workflowmanager/utils.py index a34738d..d147c2d 100644 --- a/src/plone/app/workflowmanager/utils.py +++ b/src/plone/app/workflowmanager/utils.py @@ -5,7 +5,7 @@ def generate_id(org_id, ids): count = 1 new_id = org_id while new_id in ids: - new_id = org_id + '-' + str(count) + new_id = org_id + "-" + str(count) count += 1 return new_id @@ -33,18 +33,17 @@ def clone_transition(transition, clone): def clone_state(state, clone): state.transitions = clone.transitions[:] - state.permission_roles = clone.permission_roles and \ - clone.permission_roles.copy() or None + state.permission_roles = ( + clone.permission_roles and clone.permission_roles.copy() or None + ) state.group_roles = clone.group_roles and clone.group_roles.copy() or None state.var_values = clone.var_values and clone.var_values.copy() or None state.description = clone.description def generateRuleName(transition): - return '--workflowmanager--%s--%s' % ( - transition.getWorkflow().id, - transition.id) + return "--workflowmanager--%s--%s" % (transition.getWorkflow().id, transition.id) + def generateRuleNameOld(transition): - return '--workflowmanager--%s' % ( - transition.id) + return "--workflowmanager--%s" % (transition.id)