You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by nm...@apache.org on 2022/07/15 13:59:58 UTC

[ofbiz-framework] branch trunk updated: Implemented: Define return user message from controller (OFBIZ-12652)

This is an automated email from the ASF dual-hosted git repository.

nmalin pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git


The following commit(s) were added to refs/heads/trunk by this push:
     new e12c98ac5b Implemented: Define return user message from controller (OFBIZ-12652)
e12c98ac5b is described below

commit e12c98ac5b1fcd58a8143707b5a80a333964b7ab
Author: Nicolas Malin <ni...@nereide.fr>
AuthorDate: Fri Jul 15 15:59:09 2022 +0200

    Implemented: Define return user message from controller (OFBIZ-12652)
    
    Currently, when you wish return a message to a user after an event request, you need to set it ine the called event.
    
    for a service in java :
      ServiceUtil.returnSuccess("Your service is a success")
    
    for a service in groovy :
      return success("Your service is a success")
    
    for a Java class :
      request.setAttribute("_EVENT_MESSAGE_", "Your service is a success");
    
    If during an integration, you want to use standard service like createProduct, createPartyRelationship, and need a specific message for users, you need to define your own service.
    
    For escape this case and increase the service usability, I propose to implement a new system to override the event return by a definition depending on the buisness context.
    
    For that two improvement :
    1. Add new child element to request-map->response on the controller
        With given the exact value:
    
             <response name="success" type="request" value="json">
                 <return-user-message value="Your service is a success"/>
             </response>
    
        With a flexible expander:
    
            <response name="success" type="request" value="json">
               <return-user-message value="Your service to change is a success"/>
            </response>
    
        With a property:
    
            <response name="success" type="request" value="json">
               <return-user-message ressource="CommonUiLabels" value="CommonSuccessfullyCreated"/>
            </response>
    
        From a context field:
    
            <response name="success" type="request" value="json">
               <return-user-message from-field="mySpecificReturnMessage"/>
            </response>
    
    2. From the context directly sent from the form
    
      <form name="CallEvent" target="MyEvent" .. >
         <field name="_CUSTOM_EVENT_MESSAGE_"> <hidden value="Your service to change is a success"/>
         <field name="_CUSTOM_ERROR_MESSAGE_"> <hidden value="Your service failed"/>
    
    Thanks to Florian Motteau for the implementation help
---
 framework/webapp/dtd/site-conf.xsd                 | 35 +++++++++++++
 .../ofbiz/webapp/control/ConfigXMLReader.java      | 60 ++++++++++++++++++++++
 .../ofbiz/webapp/control/RequestHandler.java       | 52 +++++++++++++++++++
 3 files changed, 147 insertions(+)

diff --git a/framework/webapp/dtd/site-conf.xsd b/framework/webapp/dtd/site-conf.xsd
index b02d6e46ce..f6912fa9ce 100644
--- a/framework/webapp/dtd/site-conf.xsd
+++ b/framework/webapp/dtd/site-conf.xsd
@@ -382,6 +382,40 @@ under the License.
             </xs:attribute>
         </xs:complexType>
     </xs:element>
+    <xs:element name="return-user-message">
+        <xs:annotation>
+            <xs:documentation>
+                Before return a response to the end user, we can override the event message from different origin.
+                Hard coded, from the labelling system or from a given field
+            </xs:documentation>
+        </xs:annotation>
+        <xs:complexType>
+            <xs:attribute name="ressource" type="xs:string">
+                <xs:annotation>
+                    <xs:documentation>
+                        Properties ressource to use for resolve the message, if you set a value here, indicate the key on value attribute
+                        otherwise this attribute will be ignored.
+                        'like: CommonUiLabels'
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="value" type="xs:string">
+                <xs:annotation>
+                    <xs:documentation>
+                        Value to use to display the response user message.
+                        You can set a plain text, a flexible string or use a key from the property file give in ressource attribute.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="from-field" type="xs:string">
+                <xs:annotation>
+                    <xs:documentation>
+                        Set from what field in context we can found the response user message. This field can contain a flexible string
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+        </xs:complexType>
+    </xs:element>
     <xs:element name="event">
         <xs:annotation>
             <xs:documentation>
@@ -469,6 +503,7 @@ under the License.
                         </xs:documentation>
                     </xs:annotation>
                 </xs:element>
+                <xs:element minOccurs="0" ref="return-user-message"/>
             </xs:sequence>
             <xs:attributeGroup ref="attlist.response"/>
         </xs:complexType>
diff --git a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ConfigXMLReader.java b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ConfigXMLReader.java
index 4d76e2283c..ab3b267e23 100644
--- a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ConfigXMLReader.java
+++ b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ConfigXMLReader.java
@@ -876,6 +876,7 @@ public final class ConfigXMLReader {
         private boolean saveHomeView = false;
         private Map<String, String> redirectParameterMap = new HashMap<>();
         private Map<String, String> redirectParameterValueMap = new HashMap<>();
+        private RequestResponseUserMessage responseMessage = null;
 
         /**
          * Gets status code.
@@ -901,6 +902,14 @@ public final class ConfigXMLReader {
             return redirectParameterValueMap;
         }
 
+        /**
+         * return the response user message element linked to this
+         * @return
+         */
+        public RequestResponseUserMessage getResponseMessage() {
+            return responseMessage;
+        }
+
         /**
          * Gets type.
          * @return the type
@@ -938,6 +947,57 @@ public final class ConfigXMLReader {
                     this.redirectParameterMap.put(redirectParameterElement.getAttribute("name"), from);
                 }
             }
+            Element messageElement = UtilXml.firstChildElement(responseElement, "return-user-message");
+            if (messageElement != null) {
+                this.responseMessage = new RequestResponseUserMessage(this, messageElement);
+            }
+        }
+    }
+
+    public static class RequestResponseUserMessage {
+        private RequestResponse requestResponse;
+        private String ressource;
+        private String value;
+        private String fromField;
+
+        public RequestResponseUserMessage() {
+        }
+
+        public RequestResponseUserMessage(RequestResponse requestResponse, Element responseElement) {
+            this.requestResponse = requestResponse;
+            ressource = UtilValidate.isNotEmpty(responseElement.getAttribute("ressource"))
+                    ? responseElement.getAttribute("ressource")
+                    : null;
+            value = UtilValidate.isNotEmpty(responseElement.getAttribute("value"))
+                    ? responseElement.getAttribute("value")
+                    : null;
+            fromField = UtilValidate.isNotEmpty(responseElement.getAttribute("from-field"))
+                    ? responseElement.getAttribute("from-field")
+                    : null;
+        }
+
+        /**
+         * Return the ressource to use
+         * @return
+         */
+        public String getRessource() {
+            return ressource;
+        }
+
+        /**
+         * Return the value
+         * @return
+         */
+        public String getValue(Map<String, Object> context) {
+            return value;
+        }
+
+        /**
+         * Return the fromField
+         * @return
+         */
+        public String getFromField() {
+            return fromField;
         }
     }
 
diff --git a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java
index 877a5de387..18ec08d8d5 100644
--- a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java
+++ b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java
@@ -56,6 +56,7 @@ import org.apache.ofbiz.base.util.UtilMisc;
 import org.apache.ofbiz.base.util.UtilObject;
 import org.apache.ofbiz.base.util.UtilProperties;
 import org.apache.ofbiz.base.util.UtilValidate;
+import org.apache.ofbiz.base.util.string.FlexibleStringExpander;
 import org.apache.ofbiz.entity.Delegator;
 import org.apache.ofbiz.entity.GenericEntityException;
 import org.apache.ofbiz.entity.GenericValue;
@@ -825,6 +826,9 @@ public final class RequestHandler {
                     + eventReturn + "].");
         }
 
+        // before follow, analyze if a have a specific event message to return on the request.
+        setUserMessageResponseToRequest(request, nextRequestResponse);
+
         if (Debug.verboseOn()) {
             Debug.logVerbose("[Event Response Selected]  type=" + nextRequestResponse.getType() + ", value=" + nextRequestResponse.getValue()
                     + ". " + showSessionId(request), MODULE);
@@ -1017,6 +1021,54 @@ public final class RequestHandler {
         }
     }
 
+    /**
+     * Before return to end user the response, analyse if in this place we need override the event message
+     * 1. Check if the request response have a dedicated response user message
+     * 2. Check if a custom message is present on the context like _CUSTOM_ERROR_MESSAGE_ and _CUSTOM_EVENT_MESSAGE_
+     * @param request
+     * @param requestResponse
+     */
+    private void setUserMessageResponseToRequest(HttpServletRequest request, ConfigXMLReader.RequestResponse requestResponse) {
+        final String fieldMessageName = requestResponse.getName() == "error"
+                ? "_ERROR_MESSAGE_"
+                : "_EVENT_MESSAGE_";
+        final String customMessageField = "_CUSTOM" + fieldMessageName;
+        Map<String, Object> context = UtilHttp.getCombinedMap(request);
+        String userMessage = null;
+
+        if (requestResponse.getResponseMessage() != null) {
+            ConfigXMLReader.RequestResponseUserMessage responseMessage = requestResponse.getResponseMessage();
+
+            // Check if the response user message come from labelling ressource
+            String value = responseMessage.getValue(context);
+            if (UtilValidate.isNotEmpty(value)) {
+                userMessage = responseMessage.getRessource() != null
+                        ? UtilProperties.getMessage(
+                        responseMessage.getRessource(), value,
+                        context, UtilHttp.getLocale(request))
+                        : value;
+            } else if (responseMessage.getFromField() != null
+                    && context.containsKey(responseMessage.getFromField())) {
+
+                // now analyze each field to found a flexible string to expand
+                userMessage = FlexibleStringExpander.getInstance(
+                                (String) context.get(responseMessage.getFromField()))
+                        .expandString(context);
+            }
+
+            if (UtilValidate.isNotEmpty(userMessage)) {
+                request.setAttribute(fieldMessageName, userMessage);
+                return;
+            }
+
+            if (context.containsKey(customMessageField)) {
+
+                //This field from the request so for security reason do not expand it to exclude any code injection
+                request.setAttribute(fieldMessageName, context.get(customMessageField));
+            }
+        }
+    }
+
     /**
      * Find the event handler and invoke an event.
      */