Commit e57ed447 authored by Jérome Perrin's avatar Jérome Perrin

ERP5Type: don't publish workflow methods

Wrapping a method in a workflow method should not change the
publishable state the method.
If the original method is not publishable, wrapping it in a workflow
method should not make it publishable.  If the original method is
publishable, then the wrapped method should still be publishable.

This was always intended to work like this, as we can see in the code
comment in `WorkflowMethod.__init__` but was not properly tested and got
broken at some point.

It's important to restore the behavior, because workflow methods such as
`validate` should not be published, users must only be able to use the
user interface transitions freely, workflow methods transitions are
only available if developer expose them in a script - and perform the
necessary consistency and security checks in that script.
parent f932c89f
Pipeline #37578 failed with stage
in 0 seconds
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
import six import six
from zodbpickle.pickle import PicklingError from zodbpickle.pickle import PicklingError
import six.moves.http_client
import unittest import unittest
import sys import sys
import mock import mock
...@@ -2975,6 +2976,14 @@ return True''') ...@@ -2975,6 +2976,14 @@ return True''')
person.validate() person.validate()
self.assertRaises(WorkflowException, person.validate) self.assertRaises(WorkflowException, person.validate)
def test_workflow_transitions_are_not_published(self):
person = self.getPersonModule().newContent(portal_type='Person')
# workflow methods are not published by zope because they don't have a __doc__ attribute
self.assertIsNone(person.validate.__doc__)
ret = self.publish('%s/validate' % person.getPath(), basic='ERP5TypeTestCase:')
self.assertEqual(ret.getStatus(), six.moves.http_client.NOT_FOUND)
self.assertEqual(person.getValidationState(), 'draft')
def test_PropertyConstantGetter(self): def test_PropertyConstantGetter(self):
""" """
Check the boolean constant getter. Make sure Check the boolean constant getter. Make sure
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
############################################################################## ##############################################################################
import unittest import unittest
import six.moves.http_client
import transaction import transaction
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
...@@ -622,6 +623,18 @@ context.setTitle('Bar') ...@@ -622,6 +623,18 @@ context.setTitle('Bar')
# two calls: one to _setProperty, and one to _setDescription # two calls: one to _setProperty, and one to _setDescription
self.assertEqual(len(call_list), 6) self.assertEqual(len(call_list), 6)
def test_interaction_workflow_methods_are_published(self):
"""Wrapping a publishable method in an interaction workflow does not prevent its publication.
"""
self.assertIsNotNone(self.organisation.getTitle.__doc__)
self.createInteractionWorkflow()
self.interaction.setProperties('default', method_id='getTitle')
self.assertIsNotNone(self.organisation.getTitle.__doc__)
self.organisation.setTitle(self.id())
ret = self.publish('%s/getTitle' % self.organisation.getPath(), basic='ERP5TypeTestCase:')
self.assertEqual(ret.getStatus(), six.moves.http_client.OK)
self.assertEqual(ret.getBody(), self.id())
def test_security(self): def test_security(self):
# wrapping a method in an interaction workflow adds a default security to # wrapping a method in an interaction workflow adds a default security to
......
...@@ -166,7 +166,8 @@ class WorkflowMethod(Method): ...@@ -166,7 +166,8 @@ class WorkflowMethod(Method):
# This is intentional to prevent methods such as submit, share to # This is intentional to prevent methods such as submit, share to
# be called from a URL. If someone can show that this way # be called from a URL. If someone can show that this way
# is wrong (ex. for remote operation of a site), let us know. # is wrong (ex. for remote operation of a site), let us know.
if not method.__name__.startswith('_'): self.__doc__ = method.__doc__
if method.__name__.startswith('_') or method.__doc__ is None:
self.__name__ = method.__name__ self.__name__ = method.__name__
for func_id in ['func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']: for func_id in ['func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']:
setattr(self, func_id, getattr(method, func_id, None)) setattr(self, func_id, getattr(method, func_id, None))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment