From 739b1e934fead8555d3e288521a02767a195e67d Mon Sep 17 00:00:00 2001 From: Arnaud Fontaine <arnaud.fontaine@nexedi.com> Date: Wed, 22 Feb 2012 19:15:05 +0900 Subject: [PATCH] Set the Component state to modified upon modification, then check the consistency. This allows to check consistency of reference and version as well (through PropertyRecordableMixin rather than fiddling with the workflow history). Also, split up state and error message into two separate fields. --- .../portal_skins/erp5_core/Component_view.xml | 3 +- .../Component_view/my_error_message_list.xml | 313 ++++++++++++++++++ ... my_translated_validation_state_title.xml} | 2 +- .../interactions/Component_modify.xml | 129 ++++++++ .../scripts/Component_setModifiedState.xml | 67 ++++ .../Component_validateAfterModified.xml | 67 ++++ .../states/validated.xml | 1 - .../transitions/modified.xml | 2 +- .../variables/text_content.xml | 48 --- .../ERP5/bootstrap/erp5_core/bt/change_log | 4 + product/ERP5/bootstrap/erp5_core/bt/revision | 2 +- product/ERP5Type/dynamic/component_class.py | 6 +- product/ERP5Type/mixin/component.py | 252 ++++++++------ 13 files changed, 737 insertions(+), 159 deletions(-) create mode 100644 product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_error_message_list.xml rename product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/{my_translated_validation_state_title_with_error_message.xml => my_translated_validation_state_title.xml} (98%) create mode 100644 product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/interactions/Component_modify.xml create mode 100644 product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/scripts/Component_setModifiedState.xml create mode 100644 product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/scripts/Component_validateAfterModified.xml delete mode 100644 product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/variables/text_content.xml diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view.xml index aeb33550fe..5a063ba309 100644 --- a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view.xml +++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view.xml @@ -106,7 +106,8 @@ <value> <list> <string>my_description</string> - <string>my_translated_validation_state_title_with_error_message</string> + <string>my_translated_validation_state_title</string> + <string>my_error_message_list</string> </list> </value> </item> diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_error_message_list.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_error_message_list.xml new file mode 100644 index 0000000000..337c4f3b30 --- /dev/null +++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_error_message_list.xml @@ -0,0 +1,313 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="LinesField" module="Products.Formulator.StandardFields"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>id</string> </key> + <value> <string>my_error_message_list</string> </value> + </item> + <item> + <key> <string>message_values</string> </key> + <value> + <dictionary> + <item> + <key> <string>external_validator_failed</string> </key> + <value> <string>The input failed the external validator.</string> </value> + </item> + <item> + <key> <string>line_too_long</string> </key> + <value> <string>A line was too long.</string> </value> + </item> + <item> + <key> <string>required_not_found</string> </key> + <value> <string>Input is required but no input given.</string> </value> + </item> + <item> + <key> <string>too_long</string> </key> + <value> <string>You entered too many characters.</string> </value> + </item> + <item> + <key> <string>too_many_lines</string> </key> + <value> <string>You entered too many lines.</string> </value> + </item> + </dictionary> + </value> + </item> + <item> + <key> <string>overrides</string> </key> + <value> + <dictionary> + <item> + <key> <string>alternate_name</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>css_class</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>default</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>description</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>editable</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>enabled</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>external_validator</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>extra</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>hidden</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_length</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_linelength</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_lines</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>required</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>unicode</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>view_separator</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>whitespace_preserve</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </value> + </item> + <item> + <key> <string>tales</string> </key> + <value> + <dictionary> + <item> + <key> <string>alternate_name</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>css_class</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>default</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>description</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>editable</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>enabled</string> </key> + <value> + <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> + </value> + </item> + <item> + <key> <string>external_validator</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>extra</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>hidden</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_length</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_linelength</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_lines</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>required</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>unicode</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>view_separator</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>whitespace_preserve</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </value> + </item> + <item> + <key> <string>values</string> </key> + <value> + <dictionary> + <item> + <key> <string>alternate_name</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>css_class</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>default</string> </key> + <value> + <list/> + </value> + </item> + <item> + <key> <string>description</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>editable</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>enabled</string> </key> + <value> <int>1</int> </value> + </item> + <item> + <key> <string>external_validator</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>extra</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <int>3</int> </value> + </item> + <item> + <key> <string>hidden</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>max_length</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_linelength</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_lines</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>required</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string>Errors</string> </value> + </item> + <item> + <key> <string>unicode</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>view_separator</string> </key> + <value> <string encoding="cdata"><![CDATA[ + +<br /> + +]]></string> </value> + </item> + <item> + <key> <string>whitespace_preserve</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <int>40</int> </value> + </item> + </dictionary> + </value> + </item> + </dictionary> + </pickle> + </record> + <record id="2" aka="AAAAAAAAAAI="> + <pickle> + <global name="TALESMethod" module="Products.Formulator.TALESField"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_text</string> </key> + <value> <string>python: here.getValidationState() == \'modified\'</string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_translated_validation_state_title_with_error_message.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_translated_validation_state_title.xml similarity index 98% rename from product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_translated_validation_state_title_with_error_message.xml rename to product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_translated_validation_state_title.xml index 864a295d7f..f8bf5216b5 100644 --- a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_translated_validation_state_title_with_error_message.xml +++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Component_view/my_translated_validation_state_title.xml @@ -14,7 +14,7 @@ </item> <item> <key> <string>id</string> </key> - <value> <string>my_translated_validation_state_title_with_error_message</string> </value> + <value> <string>my_translated_validation_state_title</string> </value> </item> <item> <key> <string>message_values</string> </key> diff --git a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/interactions/Component_modify.xml b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/interactions/Component_modify.xml new file mode 100644 index 0000000000..c466dede06 --- /dev/null +++ b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/interactions/Component_modify.xml @@ -0,0 +1,129 @@ +<?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> + <list> + <string>Component_validateAfterModified</string> + </list> + </value> + </item> + <item> + <key> <string>description</string> </key> + <value> <string></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>Component_modify</string> </value> + </item> + <item> + <key> <string>method_id</string> </key> + <value> + <list> + <string>_setTextContent*</string> + <string>_setReference*</string> + <string>_setVersion*</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>Component_setModifiedState</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> + <record id="2" aka="AAAAAAAAAAI="> + <pickle> + <global name="Guard" module="Products.DCWorkflow.Guard"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>expr</string> </key> + <value> + <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> + </value> + </item> + </dictionary> + </pickle> + </record> + <record id="3" aka="AAAAAAAAAAM="> + <pickle> + <global name="Expression" module="Products.CMFCore.Expression"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>text</string> </key> + <value> <string>python: here.getValidationState() in (\'validated\', \'modified\')</string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/scripts/Component_setModifiedState.xml b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/scripts/Component_setModifiedState.xml new file mode 100644 index 0000000000..3b9c284f3e --- /dev/null +++ b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/scripts/Component_setModifiedState.xml @@ -0,0 +1,67 @@ +<?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\'].modified()\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>Component_setModifiedState</string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/scripts/Component_validateAfterModified.xml b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/scripts/Component_validateAfterModified.xml new file mode 100644 index 0000000000..1661ae989b --- /dev/null +++ b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_interaction_workflow/scripts/Component_validateAfterModified.xml @@ -0,0 +1,67 @@ +<?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\'].checkConsistencyAndValidate()\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>Component_validateAfterModified</string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/states/validated.xml b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/states/validated.xml index 219f67c417..ce42820726 100644 --- a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/states/validated.xml +++ b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/states/validated.xml @@ -31,7 +31,6 @@ <string>invalidate</string> <string>invalidate_action</string> <string>modified</string> - <string>validate</string> </tuple> </value> </item> diff --git a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/transitions/modified.xml b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/transitions/modified.xml index 94ab3bb097..c3abfb4bd6 100644 --- a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/transitions/modified.xml +++ b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/transitions/modified.xml @@ -50,7 +50,7 @@ </item> <item> <key> <string>title</string> </key> - <value> <string></string> </value> + <value> <string>Modified</string> </value> </item> <item> <key> <string>trigger_type</string> </key> diff --git a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/variables/text_content.xml b/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/variables/text_content.xml deleted file mode 100644 index 8ff402c78c..0000000000 --- a/product/ERP5/bootstrap/erp5_core/WorkflowTemplateItem/portal_workflow/component_validation_workflow/variables/text_content.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?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> diff --git a/product/ERP5/bootstrap/erp5_core/bt/change_log b/product/ERP5/bootstrap/erp5_core/bt/change_log index 7f88fcb867..afd9e10bb6 100644 --- a/product/ERP5/bootstrap/erp5_core/bt/change_log +++ b/product/ERP5/bootstrap/erp5_core/bt/change_log @@ -1,3 +1,7 @@ +2012-02-22 arnaud.fontaine +* Split up state and error message into two separate fields. +* Always set the Component state to modified upon modification, then check the consistency. + 2012-02-21 arnaud.fontaine * Do not update automatically the component module registry for reliability's sake. diff --git a/product/ERP5/bootstrap/erp5_core/bt/revision b/product/ERP5/bootstrap/erp5_core/bt/revision index 65466d1501..6123aa80b3 100644 --- a/product/ERP5/bootstrap/erp5_core/bt/revision +++ b/product/ERP5/bootstrap/erp5_core/bt/revision @@ -1 +1 @@ -41004 \ No newline at end of file +41005 \ No newline at end of file diff --git a/product/ERP5Type/dynamic/component_class.py b/product/ERP5Type/dynamic/component_class.py index 262e68f755..595c0456a6 100644 --- a/product/ERP5Type/dynamic/component_class.py +++ b/product/ERP5Type/dynamic/component_class.py @@ -111,9 +111,9 @@ class ComponentDynamicPackage(ModuleType): # be handled by component_validation_workflow which will take care of # updating the registry if component.getValidationState() in ('modified', 'validated'): - reference = component.getReference() - self.__registry_dict.setdefault( - reference, {})[component.getVersion()] = component + reference = component.getReference(validated_only=True) + version = component.getVersion(validated_only=True) + self.__registry_dict.setdefault(reference, {})[version] = component return self.__registry_dict diff --git a/product/ERP5Type/mixin/component.py b/product/ERP5Type/mixin/component.py index a3d9ecb1dc..996bba5358 100644 --- a/product/ERP5Type/mixin/component.py +++ b/product/ERP5Type/mixin/component.py @@ -32,6 +32,7 @@ from __future__ import absolute_import from AccessControl import ClassSecurityInfo +from Products.ERP5.mixin.property_recordable import PropertyRecordableMixin from Products.ERP5Type import Permissions from Products.ERP5Type.Base import Base from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter @@ -39,7 +40,7 @@ from Products.ERP5Type.ConsistencyMessage import ConsistencyMessage from zLOG import LOG, INFO -class ComponentMixin(Base): +class ComponentMixin(PropertyRecordableMixin, Base): isPortalContent = 1 isRADContent = 1 isDelivery = ConstantGetter('isDelivery', value=True) @@ -58,121 +59,166 @@ class ComponentMixin(Base): 'TextDocument') security.declareProtected(Permissions.ModifyPortalContent, 'checkConsistency') - def checkConsistency(self, text_content=None, *args, **kw): + def checkConsistency(self, *args, **kw): """ XXX-arnau: should probably be in a separate Constraint class? """ - if text_content is None: - text_content = self.getTextContent() - + error_list = [] + object_relative_url = self.getRelativeUrl() + + reference = self.getReference() + if not reference: + error_list.append( + ConsistencyMessage(self, + object_relative_url, + message="Reference must be set", + mapping={})) + + elif (reference.endswith('_version') or + reference[0] == '_' or + reference in ('find_module', 'load_module')): + error_list.append( + ConsistencyMessage(self, + object_relative_url, + message="Reference cannot end with '_version' or "\ + "start with '_' or be equal to find_module or "\ + "load_module", + mapping={})) + + version = self.getVersion() + if not version: + error_list.append(ConsistencyMessage(self, + object_relative_url, + message="Version must be set", + mapping={})) + elif version[0] == '_': + error_list.append(ConsistencyMessage(self, + object_relative_url, + message="Version cannot start with '_'", + mapping={})) + + text_content = self.getTextContent() if not text_content: - return [ConsistencyMessage(self, - object_relative_url=self.getRelativeUrl(), - message="No source code", - mapping={})] - - message = None - try: - self.load(text_content=text_content) - except SyntaxError, e: - mapping = dict(error_message=str(e), - line_number=e.lineno, - column_number=e.offset) - - message = "Syntax error in source code: ${error_message} " \ - "(line: ${line_number}, column: ${column_number})" - - except Exception, e: - mapping = dict(message=str(e)) - message = "Source code: ${error_message}" - - if message: - return [ConsistencyMessage(self, - object_relative_url=self.getRelativeUrl(), - message=message, - mapping=mapping)] - - return [] - - def _setTextContent(self, text_content): + error_list.append( + ConsistencyMessage(self, + object_relative_url=object_relative_url, + message="No source code", + mapping={})) + else: + message = None + try: + self.load(text_content=text_content) + except SyntaxError, e: + mapping = dict(error_message=str(e), + line_number=e.lineno, + column_number=e.offset) + + message = "Syntax error in source code: ${error_message} " \ + "(line: ${line_number}, column: ${column_number})" + + except Exception, e: + mapping = dict(error_message=str(e)) + message = "Source code: ${error_message}" + + if message: + error_list.append( + ConsistencyMessage(self, + object_relative_url=self.getRelativeUrl(), + message=message, + mapping=mapping)) + + return error_list + + def _recordPropertyDecorator(accessor_name, property_name): + def inner(self, property_value): + """ + Everytime either 'reference', 'version' or 'text_content' are + modified when a Component is in modified or validated state, the + Component is set to modified state by component interaction + workflow, then in this method, the current property value is + recorded in order to handle any error returned when checking + consistency before the new value is set. At the end, through + component interaction workflow, the Component is validated only + if checkConsistency returns no error + + The recorded property will be used upon loading the Component + whereas the new value set is displayed in Component view. + """ + if self.getValidationState() in ('modified', 'validated'): + self.recordProperty(property_name) + + return getattr(super(ComponentMixin, self), accessor_name)(property_value) + + return inner + + security.declareProtected(Permissions.ModifyPortalContent, '_setReference') + _setReference = _recordPropertyDecorator('_setReference', 'reference') + + security.declareProtected(Permissions.ModifyPortalContent, '_setVersion') + _setVersion = _recordPropertyDecorator('_setVersion', 'version') + + security.declareProtected(Permissions.ModifyPortalContent, '_setTextContent') + _setTextContent = _recordPropertyDecorator('_setTextContent', 'text_content') + + def checkConsistencyAndValidate(self): """ - When the validation state is already 'validated', set the new value to - 'text_content_non_validated' property instead of 'text_content' for the - following reasons: - - 1/ It allows to validate the source code through Component validation - workflow rather than after each edition; - - 2/ It avoids dirty hacks to call checkConsistency upon edit and deal with - error messages, instead use workflow as it makes more sense. - - Then, when the user revalidates the Component through a workflow action, - 'text_content_non_validated' property is copied back to 'text_content'. - - XXX-arnau: the workflow history bit is really ugly and should be moved to - an interaction workflow instead + When a Component is in validated or modified validation state and + it is modified, modified state is set then this checks whether the + Component can be validated again if checkConsistency returns no + error """ - 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() - - validation_workflow = self.workflow_history['component_validation_workflow'] - - 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(ComponentMixin, 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'] = '' + error_list = self.checkConsistency() + if error_list: + workflow = self.workflow_history['component_validation_workflow'][-1] + workflow['error_list'] = error_list else: - return super(ComponentMixin, self)._setTextContent(text_content) + self.clearRecordedProperty('reference') + self.clearRecordedProperty('version') + self.clearRecordedProperty('text_content') + self.validate() + + def _getRecordedPropertyDecorator(accessor_name, property_name): + def inner(self, validated_only=False): + """ + When validated_only is True, then returns the property recorded if the + Component has been modified but there was an error upon consistency + checking + """ + if validated_only: + try: + return self.getRecordedProperty(property_name) + # AttributeError when this property has never been recorded before + # (_recorded_property_dict) and KeyError if the property has been + # recorded before but is not anymore + except (AttributeError, KeyError): + pass + + return getattr(super(ComponentMixin, self), accessor_name)() + + return inner security.declareProtected(Permissions.AccessContentsInformation, - 'getTextContent') - def getTextContent(self, validated_only=False): - """ - Return the source code of the validated source code (if validated_only is - True), meaningful when generating the Component, or the non-validated - source code (when a Component is modified when it has already been - validated), meaningful when editing a Component or checking consistency - """ - if not validated_only: - 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 + 'getReference') + getReference = _getRecordedPropertyDecorator('getReference', 'reference') - return super(ComponentMixin, self).getTextContent() + security.declareProtected(Permissions.AccessContentsInformation, 'getVersion') + getVersion = _getRecordedPropertyDecorator('getVersion', 'version') - def _getErrorMessage(self): - current_workflow = self.workflow_history['component_validation_workflow'][-1] - return current_workflow['error_message'] + security.declareProtected(Permissions.AccessContentsInformation, + 'getTextContent') + getTextContent = _getRecordedPropertyDecorator('getTextContent', + 'text_content') security.declareProtected(Permissions.AccessContentsInformation, - 'getTranslatedValidationStateTitleWithErrorMessage') - 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 + 'getErrorMessageList') + def getErrorMessageList(self): + """ + Return the checkConsistency errors which may have occurred when + the Component has been modified after being validated once + """ + current_workflow = self.workflow_history['component_validation_workflow'][-1] + return [str(error.getTranslatedMessage()) + for error in current_workflow['error_list']] security.declareProtected(Permissions.ModifyPortalContent, 'load') def load(self, namespace_dict={}, validated_only=False, text_content=None): -- 2.30.9