Commit 7d9faf44 authored by Arnaud Fontaine's avatar Arnaud Fontaine

Perform revalidate automatically rather than requiring a manual action.

Also, save error message and non-validated text content in a workflow variable
rather than in a property.
parent ce0fac05
......@@ -106,7 +106,7 @@
<value>
<list>
<string>my_description</string>
<string>my_translated_validation_state_title</string>
<string>my_translated_validation_state_title_with_error_message</string>
</list>
</value>
</item>
......
......@@ -14,7 +14,7 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_translated_validation_state_title</string> </value>
<value> <string>my_translated_validation_state_title_with_error_message</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
......
......@@ -58,7 +58,6 @@
<list>
<string>validate</string>
<string>invalidate</string>
<string>revalidate</string>
</list>
</value>
</item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="InteractionDefinition" module="Products.ERP5.Interaction"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>activate_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>before_commit_script_name</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Component_revalidate</string> </value>
</item>
<item>
<key> <string>method_id</string> </key>
<value>
<list>
<string>revalidate</string>
</list>
</value>
</item>
<item>
<key> <string>once_per_transaction</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>portal_type_filter</string> </key>
<value>
<list>
<string>Document Component</string>
<string>Extension Component</string>
</list>
</value>
</item>
<item>
<key> <string>script_name</string> </key>
<value>
<list>
<string>revalidate</string>
</list>
</value>
</item>
<item>
<key> <string>temporary_document_disallowed</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>state_change[\'object\'].setTextContentAfterRevalidation()\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>state_change</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>revalidate</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="StateDefinition" module="Products.DCWorkflow.States"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>modified</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Modified</string> </value>
</item>
<item>
<key> <string>transitions</string> </key>
<value>
<tuple>
<string>invalidate</string>
<string>invalidate_action</string>
<string>modified</string>
<string>validate</string>
</tuple>
</value>
</item>
<item>
<key> <string>type_list</string> </key>
<value>
<tuple/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -30,8 +30,8 @@
<tuple>
<string>invalidate</string>
<string>invalidate_action</string>
<string>revalidate</string>
<string>revalidate_action</string>
<string>modified</string>
<string>validate</string>
</tuple>
</value>
</item>
......
......@@ -38,11 +38,11 @@
</item>
<item>
<key> <string>id</string> </key>
<value> <string>revalidate</string> </value>
<value> <string>modified</string> </value>
</item>
<item>
<key> <string>new_state_id</string> </key>
<value> <string></string> </value>
<value> <string>modified</string> </value>
</item>
<item>
<key> <string>script_name</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="TransitionDefinition" module="Products.DCWorkflow.Transitions"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string>Revalidate</string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string>%(content_url)s/Base_viewWorkflowActionDialog?workflow_action=revalidate_action</string> </value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>revalidate</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Revalidate a Component, until then the code previously validated/revalidated is used.</string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>revalidate_action</string> </value>
</item>
<item>
<key> <string>new_state_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>script_name</string> </key>
<value> <string>checkConsistency</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Revalidate Action</string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Guard" module="Products.DCWorkflow.Guard"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>roles</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="VariableDefinition" module="Products.DCWorkflow.Variables"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_expr</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_value</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>for_catalog</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>for_status</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>text_content</string> </value>
</item>
<item>
<key> <string>info_guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>update_always</string> </key>
<value> <int>1</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
2012-02-02 arnaud.fontaine
* Perform revalidate automatically rather than requiring a manual action.
2012-02-01 arnaud.fontaine
* Replace comments by description field in Component_view.
......
40998
\ No newline at end of file
40999
\ No newline at end of file
......@@ -58,11 +58,14 @@ class Component(Base):
'Reference',
'TextDocument')
def checkConsistency(self, *args, **kw):
def checkConsistency(self, text_content=None, *args, **kw):
"""
XXX-arnau: should probably in a separate Constraint class
"""
if not self.getTextContent():
if text_content is None:
text_content = self.getTextContent()
if not text_content:
return [ConsistencyMessage(self,
object_relative_url=self.getRelativeUrl(),
message="No source code",
......@@ -70,7 +73,7 @@ class Component(Base):
message = None
try:
self.load()
self.load(text_content=text_content)
except SyntaxError, e:
message = "%s (line: %d, column: %d)" % (e.msg, e.lineno, e.offset)
except Exception, e:
......@@ -99,21 +102,36 @@ class Component(Base):
Then, when the user revalidates the Component through a workflow action,
'text_content_non_validated' property is copied back to 'text_content'.
XXX-arnau: having a separate property would require hackish code when
exporting the bt5, perhaps a workflow variable would be better?
XXX-arnau: the workflow history bit is really ugly and should be moved to
an interaction workflow instead
"""
if self.getValidationState() == 'validated':
return self.setProperty('text_content_non_validated', text_content)
validation_state = self.getValidationState()
if validation_state in ('validated', 'modified'):
error_message_list = self.checkConsistency(text_content=text_content)
if error_message_list:
self.modified()
return super(Component, self)._setTextContent(text_content)
validation_workflow = self.workflow_history['component_validation_workflow']
def setTextContentAfterRevalidation(self):
"""
Call upon revalidate on an already validated Component to set the source
code from text_content_non_validated property
"""
super(Component, self)._setTextContent(self.getTextContent())
self.setProperty('text_content_non_validated', None)
last_validation_workflow = validation_workflow[-1]
last_validation_workflow['error_message'] = error_message_list[0]
last_validation_workflow['text_content'] = text_content
previous_validation_workflow = validation_workflow[-2]
previous_validation_workflow['error_message'] = ''
previous_validation_workflow['text_content'] = ''
else:
super(Component, self)._setTextContent(text_content)
self.validate()
if validation_state == 'modified':
# XXX-arnau: copy/paste
validation_workflow = self.workflow_history['component_validation_workflow']
previous_validation_workflow = validation_workflow[-2]
previous_validation_workflow['error_message'] = ''
previous_validation_workflow['text_content'] = ''
else:
return super(Component, self)._setTextContent(text_content)
def getTextContent(self, validated_only=False):
"""
......@@ -123,13 +141,29 @@ class Component(Base):
validated), meaningful when editing a Component or checking consistency
"""
if not validated_only:
text_content_non_validated = self.getProperty('text_content_non_validated')
text_content_non_validated = \
self.workflow_history['component_validation_workflow'][-1].get('text_content',
None)
if text_content_non_validated:
return text_content_non_validated
return super(Component, self).getTextContent()
def load(self, namespace_dict={}, validated_only=False):
def _getErrorMessage(self):
current_workflow = self.workflow_history['component_validation_workflow'][-1]
return current_workflow['error_message']
def getTranslatedValidationStateTitleWithErrorMessage(self):
validation_state_title = self.getTranslatedValidationStateTitle()
error_message = self._getErrorMessage()
if error_message:
return "%s (%s)" % (validation_state_title,
str(error_message.getTranslatedMessage()))
return validation_state_title
def load(self, namespace_dict={}, validated_only=False, text_content=None):
"""
Load the source code into the given dict. Using exec() rather than
imp.load_source() as the latter would required creating an intermediary
......@@ -138,7 +172,10 @@ class Component(Base):
it. By default namespace_dict is an empty dict to allow checking the
source code before validate.
"""
exec self.getTextContent(validated_only=validated_only) in namespace_dict
if text_content is None:
text_content = self.getTextContent(validated_only=validated_only)
exec text_content in namespace_dict
@staticmethod
def _getFilesystemPath():
......
......@@ -1204,6 +1204,18 @@ class TestZodbPropertySheet(ERP5TypeTestCase):
self.fail("Creating a Category Expression with syntax error raises "\
"an error")
from Products.ERP5Type.Tool.ComponentTool import ComponentTool
ComponentTool._original_reset = ComponentTool.reset
ComponentTool._reset_performed = False
def assertResetNotCalled(*args, **kwargs):
raise AssertionError("reset should only be called once revalidating")
def assertResetCalled(self, *args, **kwargs):
from Products.ERP5Type.Tool.ComponentTool import ComponentTool
ComponentTool._reset_performed = True
return ComponentTool._original_reset(self, *args, **kwargs)
import abc
class _TestZodbComponent(ERP5TypeTestCase):
......@@ -1255,74 +1267,54 @@ class _TestZodbComponent(ERP5TypeTestCase):
self.assertHasAttribute(self._module,
'TestValidateInvalidateComponent')
def testRevalidate(self):
"""
Check whether revalidate is performed properly
"""
validated_code = 'def foobar(*args, **kwargs):\n return "Validated"'
component = self._newComponent('TestRevalidateComponent', validated_code)
def testSourceCodeWithSyntaxError(self):
valid_code = 'def foobar(*args, **kwargs):\n return 42'
ComponentTool.reset = assertResetCalled
try:
component = self._newComponent('TestComponentWithSyntaxError', valid_code)
component.validate()
transaction.commit()
self.tic()
finally:
ComponentTool.reset = ComponentTool._original_reset
self.assertHasAttribute(self._module, 'TestRevalidateComponent')
self.assertEquals(component.getTextContent(), validated_code)
self.assertEquals(component.getTextContent(validated_only=True),
validated_code)
from Products.ERP5Type.Tool.ComponentTool import ComponentTool
old_reset_function = ComponentTool.reset
def assertResetNotCalled(*args, **kwargs):
raise AssertionError("reset should only be called once revalidating")
def assertResetCalled(self, *args, **kwargs):
from Products.ERP5Type.Tool.ComponentTool import ComponentTool
ComponentTool._reset_performed = True
return old_reset_function(self, *args, **kwargs)
revalidated_code = 'def foobar(*args, **kwargs):\n return "Revalidated"'
self.assertEquals(component.getValidationState(), 'validated')
self.assertEquals(component.getTextContent(), valid_code)
self.assertEquals(component.getTextContent(validated_only=True), valid_code)
self.assertHasAttribute(self._module, 'TestComponentWithSyntaxError')
try:
invalid_code = 'def foobar(*args, **kwargs)\n return 42'
ComponentTool.reset = assertResetNotCalled
component.setTextContent(revalidated_code)
try:
component.setTextContent(invalid_code)
transaction.commit()
self.tic()
finally:
ComponentTool.reset = ComponentTool._original_reset
self.assertEquals(component.getTextContent(), revalidated_code)
self.assertEquals(component.getTextContent(validated_only=True),
validated_code)
self.assertEquals(component.getValidationState(), 'modified')
self.assertNotEqual(component._getErrorMessage(), '')
self.assertEquals(component.getTextContent(), invalid_code)
self.assertEquals(component.getTextContent(validated_only=True), valid_code)
self._component_tool.reset()
self.assertHasAttribute(self._module, 'TestComponentWithSyntaxError')
ComponentTool.reset = assertResetCalled
component.revalidate()
try:
component.setTextContent(valid_code)
transaction.commit()
self.tic()
self.assertTrue(ComponentTool._reset_performed)
self.assertEquals(component.getTextContent(), revalidated_code)
self.assertEquals(component.getTextContent(validated_only=True),
revalidated_code)
self.assertEquals(ComponentTool._reset_performed, True)
finally:
self._component_tool.reset = old_reset_function
def testSourceCodeWithSyntaxError(self):
test_component = self._newComponent(
'TestComponentWithSyntaxError',
'def foobar(*args, **kwargs):\n return 42')
self.assertEqual(test_component.checkConsistency(), [])
test_component.validate()
transaction.commit()
self.tic()
self.assertHasAttribute(self._module,
'TestComponentWithSyntaxError')
test_component.setTextContent('def foobar(*args, **kwargs)\n return 42')
transaction.commit()
self.tic()
self.assertNotEqual(test_component.checkConsistency(), [])
ComponentTool.reset = ComponentTool._original_reset
ComponentTool._reset_performed = False
self.assertEquals(component.getValidationState(), 'validated')
self.assertEquals(component._getErrorMessage(), '')
self.assertEquals(component.getTextContent(), valid_code)
self.assertEquals(component.getTextContent(validated_only=True), valid_code)
self.assertHasAttribute(self._module, 'TestComponentWithSyntaxError')
from Products.ERP5Type.Core.ExtensionComponent import ExtensionComponent
......
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