Commit 60c42769 authored by Tomáš Peterka's avatar Tomáš Peterka Committed by Tomáš Peterka

[hal_json] Improve extra_param (aka keep_items) persistency between requests

parent 09c37a35
......@@ -5,10 +5,11 @@ Responsible for validating form data and redirecting to the form action.
Please note that the new UI has deprecated use of Selections. Your scripts
will no longer receive `selection_name` nor `selection` in their arguments.
There are runtime values hidden in every form (injected by getHateoas Script):
There are runtime values hidden in every dialog form (injected by getHateoas Script):
form_id - previous form ID (backward compatibility reasons)
dialog_id - current form dialog ID
dialog_method - method to be called - can be either update_method or dialog_method of the Dialog Form
extra_param_json - JSON serialized extra parameters for the dialog script
"""
from Products.ERP5Type.Log import log, DEBUG, INFO, WARNING, ERROR
......@@ -110,6 +111,21 @@ try:
editable_mode = request.get('editable_mode', 1)
request.set('editable_mode', 1)
form_data = form.validate_all_to_request(request)
# Notify the underlying script whether user did modifications
form_hash = form.hash_validated_data(form_data)
# Inject `has_changed` parameter to arguments
if "form_hash" in extra_param:
kw['has_changed'] = (form_hash != extra_param.get('form_hash'))
# update form_hash here so we do not rely on developer/Dialog Script
# to pass it correctly
extra_param["form_hash"] = form_hash
# Put extra_param into request so we can pass it behind developers back
# it is picked up at Base_renderForm so the developer does not need to
# know that they should pass it.
# We cannot use **kwargs because all form fields get injected there so
# from our point of view it contains random garbage
request.set('extra_param', extra_param)
request.set('editable_mode', editable_mode)
default_skin = portal.portal_skins.getDefaultSkin()
......@@ -187,7 +203,7 @@ if len(listbox_id_list):
# First check for an query in form parameters - if they are there
# that means previous view was a listbox with selected stuff so recover here
query = extra_param.get("query", None)
select_all = int(extra_param.pop("_select_all", "0"))
select_all = extra_param.get("_select_all", 0)
# inject `uids` into Scripts **kwargs when we got any `query` (empty or filled)
if query is not None:
......@@ -200,11 +216,12 @@ if query is not None:
# early-stop if user selected all documents
if query == "" and select_all == 0 and dialog_method != update_method: # do not interrupt on UPDATE
extra_param["_select_all"] = 1
return context.Base_renderForm(
dialog_id,
message=translate("All documents are selected! Submit again to proceed or Cancel and narrow down your search."),
level=WARNING,
keep_items={'_select_all': 1},
keep_items=extra_param,
query=query,
form_data=form_data)
......@@ -215,13 +232,9 @@ if query == "" and select_all == 0 and dialog_method != update_method: # do not
if dialog_category == "object_search" :
portal.portal_selections.setSelectionParamsFor(kw['selection_name'], kw)
# Notify the underlying script whether user did modifications
form_hash = form.hash_validated_data(form_data)
if "form_hash" in extra_param:
kw['has_changed'] = (form_hash != extra_param.pop('form_hash'))
# Add rest of extra param into arguments of the target method
kw.update(extra_param)
kw.update(**extra_param)
kw.update(keep_items=extra_param) # better backward compatibility
# Finally we will call the Dialog Method
# Handle deferred style, unless we are executing the update action
......@@ -239,7 +252,8 @@ if dialog_method != update_method and kw.get('deferred_style', 0):
return context.Base_renderForm(dialog_id,
message=translate('Deferred reports are possible only with preference '\
'"Report Style" set to "ODT" or "ODS"'),
level=WARNING)
level=WARNING,
keep_items=extra_param)
# If the action form has report_view as it's method, it
if page_template != 'report_view':
......@@ -304,7 +318,7 @@ if True:
meta_type = ""
if meta_type in ("ERP5 Form", "ERP5 Report"):
return context.ERP5Document_getHateoas(REQUEST=request, form=dialog_form, mode="form", form_data=form_data)
return context.ERP5Document_getHateoas(REQUEST=request, form=dialog_form, mode="form", form_data=form_data, extra_param_json=extra_param)
return dialog_form(**kw)
......
......@@ -9,16 +9,21 @@ This script differs from Base_redirect that it keeps the form values in place.
:param REQUEST: request
:param **kwargs: should contain parameters to ERP5Document_getHateoas such as 'query' to replace Selections
"""
keep_items = keep_items or {}
REQUEST = REQUEST or context.REQUEST
form = getattr(context, form_id)
if not message and "portal_status_message" in keep_items:
message = keep_items.pop("portal_status_message")
# recover "hidden field" from HAL_JSON interface behind developers back (sorry)
extra_param_json = REQUEST.get('extra_param', {})
if keep_items is not None:
if not message and "portal_status_message" in keep_items:
message = keep_items.pop("portal_status_message")
if not level and "portal_status_level" in keep_items:
level = keep_items.pop("portal_status_level")
if not level and "portal_status_level" in keep_items:
level = keep_items.pop("portal_status_level")
extra_param_json.update(keep_items)
return context.ERP5Document_getHateoas(form=form, mode='form', REQUEST=REQUEST, extra_param_json=keep_items,
return context.ERP5Document_getHateoas(form=form, mode='form', REQUEST=REQUEST, extra_param_json=extra_param_json,
portal_status_message=message, portal_status_level=level, **kwargs)
......@@ -1243,11 +1243,6 @@ def renderForm(traversed_document, form, response_dict, key_prefix=None, selecti
# end-if report_section
if form.pt == "form_dialog":
# Insert hash of current values into the form so scripts can see whether data has
# changed if they provide multi-step process
if form_data is not None:
extra_param_json["form_hash"] = form.hash_validated_data(form_data)
# extra_param_json is a special field in forms (just like form_id). extra_param_json field holds JSON
# metadata about the form (its hash and dynamic fields)
renderHiddenField(response_dict, 'extra_param_json', json.dumps(extra_param_json))
......
......@@ -2,12 +2,25 @@ from Products.ERP5Type.Log import log
log("Folder method received dialog_id, form_id, uids and {!s}".format(kwargs.keys()))
if 'has_changed' not in kwargs or kwargs['has_changed'] is None:
message = "Did nothing."
if kwargs.get('has_changed', None) is None:
message = "First submission."
else:
if kwargs['has_changed']:
message = "Data has changed."
else:
message = "Data the same."
if kwargs.get("update_method", ""):
return context.Base_renderForm(dialog_id, message="Updated. " + message)
if _my_confirmation == 0:
# Here is an example of unfriendly confirmation Script which takes
# whole keep_item for itself!
# It should take keep_items from parameters, update it and pass it
# along. But no programmer will ever comply with that so we are ready!
return context.Base_renderForm(dialog_id,
message="Submit again to confirm. " + message,
level='warning',
keep_items={'_my_confirmation': 1})
return context.Base_redirect(form_id, keep_items={"portal_status_message": message})
......@@ -50,7 +50,7 @@
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>dialog_id, form_id, uids, **kwargs</string> </value>
<value> <string>dialog_id, form_id, uids, _my_confirmation=0, **kwargs</string> </value>
</item>
<item>
<key> <string>id</string> </key>
......
......@@ -121,7 +121,7 @@
</item>
<item>
<key> <string>update_action</string> </key>
<value> <string>Folder_doNothingDialog</string> </value>
<value> <string>Folder_doNothing</string> </value>
</item>
<item>
<key> <string>update_action_title</string> </key>
......
......@@ -95,7 +95,7 @@
<tr><th rowspan="1" colspan="3">Updating the dialog must not trigger warning about all selected</th></tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/update_dialog" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block tal:define="notification_configuration python: {'class': 'success', 'text': 'Data received.'}">
<tal:block tal:define="notification_configuration python: {'class': 'success', 'text': 'Updated. First submission.'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
......@@ -106,10 +106,25 @@
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
<tr><td>assertValue</td>
<td>//input[@name="field_custom_variable"]</td>
<td>couscous</td></tr>
<tr><td>type</td>
<td>//input[@name="field_custom_variable"]</td>
<td>couscous</td></tr>
<tr><th rowspan="1" colspan="3">Submitting, however, must warn the user</th></tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_dialog" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block tal:define="notification_configuration python: {'class': 'error', 'text': 'Submit again to confirm. Data the same.'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
<tr><td>assertValue</td>
<td>//input[@name="field_custom_variable"]</td>
<td>couscous</td></tr>
<tr><th rowspan="1" colspan="3">Second submission must work as advertised</th></tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_dialog" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
......@@ -141,6 +156,19 @@
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
<tr><td>waitForElementPresent</td>
<td>//input[@name="field_custom_variable"]</td><td></td></tr>
<tr><td>type</td>
<td>//input[@name="field_custom_variable"]</td>
<td>musaka</td></tr>
<tr><th rowspan="1" colspan="3">Now the user-script confirmation should kick in</th></tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_dialog" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block tal:define="notification_configuration python: {'class': 'error', 'text': 'Submit again to confirm. Data has changed.'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
<tr><td>waitForElementPresent</td>
<td>//input[@name="field_custom_variable"]</td><td></td></tr>
<tr><td>type</td>
......@@ -189,7 +217,13 @@
<tr><th rowspan="1" colspan="3">Second submission must work as advertised</th></tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_dialog" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block tal:define="notification_configuration python: {'class': 'success', 'text': 'Did nothing.'}">
<tal:block tal:define="notification_configuration python: {'class': 'error', 'text': 'Submit again to confirm. First submission.'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_dialog" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block tal:define="notification_configuration python: {'class': 'success', 'text': 'Data the same.'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
......
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