You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by jl...@apache.org on 2020/04/04 15:59:20 UTC

[ofbiz-framework] branch trunk updated (8ee522e -> ba548f6)

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

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


    from 8ee522e  Improved: Decodes AjaxAutocompleteOptions return value
     add c344918  Improved: Implemented: Documented: Completed: Reverted: Fixed: Improved: no functional change (OFBIZ-) Explanation Thanks:
     add 6395aff  Improved: Remove createTopic service (unused) (OFBIZ-11376)
     add c45ed25  Improved: Defects reported by code analysis tool. (OFBIZ-10571)
     add 19c31f1  Documented: revert remove docbook help files for accounting (OFBIZ-11420)
     add 0a0ad09  Documented: revert remove docbook help files for commonext-SETUP (OFBIZ-11420)
     add beac466  Documented: revert remove docbook help files for content (OFBIZ-11420)
     add e9a0d11  Documented: revert remove docbook help files for humanres (OFBIZ-11420)
     add 39cc830  Fixed: Picklist is in Input status even after order is completed. (OFBIZ-10883)
     add 2f7e675  Fixed: hr-glossary.adoc: line 22: id assigned to block already in use: ANNUAL_REVENUE
     add 11b8d98  Improved: Put the TOCs on left in generated AsciiDoc documentation (OFBIZ-11423) Following discussions
     add b770f91  Improved: Use FlexibleStringExpander in form widget lookup field field target parameters
     add 59f65f3  Documented: Documented use of field attribute parameter-name and lookup field attribute target-parameter in widget-form.xsd
     add 09b4225  Fixed: Fixed line lengths in ModelFormFieldTest to adhere to coding standards
     add c7f7774  Improved: Remove unused labels from ProductUiLabels.xml
     add 6c9bdb9  Improved: UI labels
     add f5f2d45  Improved: Cleanup HumanRes labels
     add 5cf41f2  Improved: Set checkstyle to use LF line endings
     add 8d1b3f4  Improved: Convert PartyInvitationService.xml from minilang to groovy (OFBIZ-11360)
     add 9f9454e  Fixed: Code refactoring to support groovy syntax (OFBIZ-10231)
     add 2dc7328  Improved: Removes getSubContentWithPermCheck and getSubSubContentWithPermCheck unused services (OFBIZ-11393)(OFBIZ-11394)
     add ca17e2f  Improved: Add 2020 version of Incoterms
     add 21d568e  Fixed: Convert ProductServices.xml mini lang to groovy Improved: no functional change (OFBIZ-10231)
     add 793cf20  Fixed: Refactoring permission model call, alone permission service failed (OFBIZ-11440)
     add cab72ef  Improved: Convert party/LookupServices.xml mini-lang to groovyDSL (OFBIZ-11362)
     add 145f53e  Improved: Convert ProductServices.xml mini lang to groovy (OFBIZ-10231)
     add 5d3f85d  Fixed: Convert ProductServices.xml mini lang to groovy: productPriceGenericPermission failed (OFBIZ-10231)
     add f98ed9e  Fixed: createMissingCategoryAndProductAltUrls service misses a transaction (OFBIZ-11441)
     add 312d153  Improved: Convert ProductFeatureServices.xml mini lang to groovy (OFBIZ-11439)
     add 054e66c  Improved: Convert createTextAndUploadedContent service from mini-lang to groovy DSL (OFBIZ-11368)
     add 36f9e77  Improved: Convert OrderServices.xml mini-lang to groovyDSL : getNextOrderId
     add b999e59  Improved: Convert OrderServices.xml mini-lang to groovyDSL : getOrderedSummaryInformation
     add f951f8d  Fixed: Convert OrderServices.xml mini-lang to groovyDSL : getNextOrderId
     add e586da6  Improved: Upgrade Freemarker from 2.3.29 to 2.3.30.
     add 0c2a7ee  Improved: Convert ProductContentServices.xml mini lang to groovy (OFBIZ-11436)
     add 7f10602  Improved: Convert CommonServices.xml from mini lang to groovy (OFBIZ-11402)
     add fe4f9cf  Improved: Convert PartyServices.xml from mini lang to groovy (OFBIZ-11361)
     add d0f5a83  Fixed: Potential Nullpointer in ErrorPage.ftl
     add 0da3899  Improved: Remove unused ‘UtilHttp#checkURLforSpiders’ (OFBIZ-11138)
     add d390752  Implemented: Remove the user login security question.
     add 92d5ad0  Improved: no functional change
     add 54a429e  Implemented: _WARNING_MESSAGE_
     add 89333df  Fixed: Fixed a bug introduced with the removal of the  login security question.
     add 7fe20b4  Improved: Styles some clickable fields of backend tables as buttons.
     add a769aaf  Improved: Ensure MacroFormRenderer uses ModelFormField#getCurrentContainerId rather than ModelFormField#getIdName to ensure any FlexibleStringExpander expression defined in the field's id-name property is processed before rendering into the container FTL macro.
     add 062fc40  Fixed: CommonTheme has a dependency on Flatgrey application.js
     add d65b011  Fixed: Unable to view entity row record in webtools if PK contains timestamp field (OFBIZ-11426)
     add b824d45  Fixed: Propagate the theme in DataResourceWorker.renderDataResourceAsText() Improved: no functional change
     add f3bd6a1  Improved: no functional change
     add 7240b26  Fixed: Ensure that the SameSite attribute is set to 'strict' for all cookies.
     add 3a5a657  Fixed: Ensure that the SameSite attribute is set to 'strict' for all cookies.
     add ef8546b  Improved: POC for CSRF Token
     add 019b588  Improved: POC for CSRF Token
     new 6c49411  Improved: "auth" should be true for all the request url used for Application components
     new 866c742  Fixed: Ensure that the SameSite attribute is set to 'strict' for all cookies.
     new 11c75b6  Fixed: Ensure that the SameSite attribute is set to 'strict' for all cookies.
     new 87277ab  Improved: Added unit testing, using JMockit, to ensure that form macros are rendered using ids from ModelFormField#getCurrentContainerId.
     new 1fbf6c3  Improved: Added license header to MacroFormRendererTest
     new d1ca68c  Improved: Added unit testing, using JMockit, to ensure that form macros are rendered using ids from ModelFormField#getCurrentContainerId.
     new c68d43e  Improved: Added unit testing, using JMockit, to ensure that form macros are rendered using ids from ModelFormField#getCurrentContainerId.
     new 43f4639  Improved: Added unit testing, using JMockit, to ensure that form macros are rendered using ids from ModelFormField#getCurrentContainerId.
     new 4d2e5d3  Fixed: Specified key was too long; max key length is 767 bytes for ProductPromoCodeEmail entity.(OFBIZ-5426) (#44)
     new 48e81c4  Improved: style alignment properties
     new 20cf076  Improved: unify style application
     new 321e516  Improved: unify style application
     new c89e934  Improved: unify style application
     new 6c66ce0  Fixed: DataModel - correct foreign key (#51)
     new 060e9ab  Improved: no functional change
     new f2e6989  Improved: Implement the pretty print for keyword search
     new ae3ae26  Improved: type="text/css" was missing on a call to <<link rel="stylesheet/less>>
     new e666c65  Improved: Improve Web Content Caching
     new c9d516d  Fixed: The createTaskContent request does not work
     new 4594fc4  Improved: Convert PartyPermissionServices.xml from mini lang to groovy (OFBIZ-11433)
     new 8fc5028  Fixed: correct path to ftpAddress services (OFBIZ-11359)
     new 37f33f4  Fixed: correct path to ftpAddress services (OFBIZ-11359)
     new 5bc579a  Merges OFBiz trunk
     new 768353a  Improved: Implemented: Documented: Completed: Reverted: Fixed:
     new 645d419  Merge branch 'trunk' into POC-for-CSRF-Token-OFBIZ-11306
     new ba548f6  Merge branch 'JacquesLeRoux-POC-for-CSRF-Token-OFBIZ-11306' into trunk Because of GitHub message on PR56: This branch cannot be rebased due to conflicts

The 26 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../humanres/template/category/CategoryTree.ftl    |  16 +-
 .../category/ftl/CatalogAltUrlSeoTransform.java    |   8 +-
 .../product/category/ftl/UrlRegexpTransform.java   |  13 +-
 .../product/template/category/CategoryTree.ftl     |   2 +-
 .../java/org/apache/ofbiz/common/CommonEvents.java |   3 +-
 .../common/webcommon/WEB-INF/common-controller.xml |   4 +-
 framework/security/config/security.properties      |  22 +-
 .../apache/ofbiz/security/CsrfDefenseStrategy.java |  93 ++++++
 .../java/org/apache/ofbiz/security/CsrfUtil.java   | 358 +++++++++++++++++++++
 .../ofbiz/security/ICsrfDefenseStrategy.java       |  55 ++++
 .../ofbiz/security/NoCsrfDefenseStrategy.java}     |  34 +-
 .../org/apache/ofbiz/security/CsrfUtilTests.java   | 264 +++++++++++++++
 framework/webapp/dtd/site-conf.xsd                 |  14 +
 .../ofbiz/webapp/control/ConfigXMLReader.java      |   3 +
 .../ofbiz/webapp/control/ControlEventListener.java |   3 +
 .../ofbiz/webapp/control/RequestHandler.java       |  33 +-
 .../ofbiz/webapp/ftl/CsrfTokenAjaxTransform.java   |  57 ++--
 .../webapp/ftl/CsrfTokenPairNonAjaxTransform.java  |  56 ++--
 .../ofbiz/webapp/freemarkerTransforms.properties   |   2 +
 .../webtools/groovyScripts/entity/CheckDb.groovy   |   7 +-
 .../webtools/groovyScripts/entity/EntityRef.groovy |   6 +
 framework/webtools/template/entity/CheckDb.ftl     |  28 +-
 .../webtools/template/entity/EntityRefList.ftl     |   9 +-
 framework/webtools/template/entity/ViewGeneric.ftl |   5 +-
 .../webapp/webtools/WEB-INF/controller.xml         |   2 +-
 .../java/org/apache/ofbiz/widget/WidgetWorker.java |  14 +
 .../widget/renderer/macro/MacroFormRenderer.java   |  14 +-
 themes/bluelight/template/Header.ftl               |   6 +-
 .../common-theme/template/includes/ListLocales.ftl |   2 +-
 .../template/macro/CsvFormMacroLibrary.ftl         |   2 +-
 .../template/macro/FoFormMacroLibrary.ftl          |   2 +-
 .../template/macro/HtmlFormMacroLibrary.ftl        |   8 +-
 .../template/macro/TextFormMacroLibrary.ftl        |   2 +-
 .../template/macro/XlsFormMacroLibrary.ftl         |   2 +-
 .../template/macro/XmlFormMacroLibrary.ftl         |   2 +-
 .../webapp/common/js/util/OfbizUtil.js             |  12 +-
 themes/flatgrey/template/Header.ftl                |   6 +-
 themes/rainbowstone/template/includes/Header.ftl   |   4 +
 .../rainbowstone/template/includes/TopAppBar.ftl   |   2 +-
 themes/tomahawk/template/AppBarClose.ftl           |   2 +-
 themes/tomahawk/template/Header.ftl                |   4 +
 41 files changed, 1037 insertions(+), 144 deletions(-)
 create mode 100644 framework/security/src/main/java/org/apache/ofbiz/security/CsrfDefenseStrategy.java
 create mode 100644 framework/security/src/main/java/org/apache/ofbiz/security/CsrfUtil.java
 create mode 100644 framework/security/src/main/java/org/apache/ofbiz/security/ICsrfDefenseStrategy.java
 copy framework/{base/src/main/java/org/apache/ofbiz/base/concurrent/ConstantFuture.java => security/src/main/java/org/apache/ofbiz/security/NoCsrfDefenseStrategy.java} (62%)
 create mode 100644 framework/security/src/test/java/org/apache/ofbiz/security/CsrfUtilTests.java
 copy applications/product/src/main/java/org/apache/ofbiz/product/category/ftl/OfbizCatalogUrlTransform.java => framework/webapp/src/main/java/org/apache/ofbiz/webapp/ftl/CsrfTokenAjaxTransform.java (61%)
 copy applications/product/src/main/java/org/apache/ofbiz/product/category/ftl/OfbizCatalogUrlTransform.java => framework/webapp/src/main/java/org/apache/ofbiz/webapp/ftl/CsrfTokenPairNonAjaxTransform.java (62%)


[ofbiz-framework] 19/26: Fixed: The createTaskContent request does not work

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit c9d516d367d4c06d99adae002273540b13511d32
Author: Jacques Le Roux <ja...@les7arts.com>
AuthorDate: Fri Mar 27 10:55:59 2020 +0100

    Fixed: The createTaskContent request does not work
    
    (OFBIZ-11246)
    
    It seems that same request can not be parsed multiple times if it has multi part
    object in it as the parse method remove it after that.
    
    Found one stackoverflow link around the same:
    
    https://stackoverflow.com/questions/13881272/
    servletfileuploadparserequestrequest-returns-an-empty-list
    
    I believe that all places/uploads using this workflow should resulting the same
    issue.
    
    One possible solution I could think of without going with new approach is to set
    list of file Items into the request attribute and use it if parse method remove
    it and unable to retrieve on 2nd call.
    
    Thanks: Ankush Upadhyay for the analysis and initial patch. I only slightly
    modified it.
---
 .../src/main/java/org/apache/ofbiz/content/layout/LayoutWorker.java   | 4 ++++
 framework/base/src/main/java/org/apache/ofbiz/base/util/UtilHttp.java | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/applications/content/src/main/java/org/apache/ofbiz/content/layout/LayoutWorker.java b/applications/content/src/main/java/org/apache/ofbiz/content/layout/LayoutWorker.java
index 07e3e79..dad4217 100644
--- a/applications/content/src/main/java/org/apache/ofbiz/content/layout/LayoutWorker.java
+++ b/applications/content/src/main/java/org/apache/ofbiz/content/layout/LayoutWorker.java
@@ -35,6 +35,7 @@ import org.apache.ofbiz.base.util.UtilGenerics;
 import org.apache.ofbiz.base.util.UtilHttp;
 import org.apache.ofbiz.base.util.UtilMisc;
 import org.apache.ofbiz.base.util.UtilProperties;
+import org.apache.ofbiz.base.util.UtilValidate;
 import org.apache.ofbiz.service.ServiceUtil;
 
 /**
@@ -66,6 +67,9 @@ public final class LayoutWorker {
             return ServiceUtil.returnError(e4.getMessage());
         }
 
+        if(lst.size() == 0 && UtilValidate.isNotEmpty(request.getAttribute("fileItems"))) {
+            lst = UtilGenerics.cast(request.getAttribute("fileItems"));
+        }
         if (lst.size() == 0) {
             String errMsg = UtilProperties.getMessage(err_resource,
                     "layoutEvents.no_files_uploaded", locale);
diff --git a/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilHttp.java b/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilHttp.java
index 169ed10..5452a19 100644
--- a/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilHttp.java
+++ b/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilHttp.java
@@ -66,6 +66,7 @@ import org.apache.commons.fileupload.FileItem;
 import org.apache.commons.fileupload.FileUploadException;
 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
 import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.apache.commons.fileupload.servlet.ServletRequestContext;
 import org.apache.commons.lang.RandomStringUtils;
 import org.apache.http.conn.ssl.NoopHostnameVerifier;
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
@@ -225,6 +226,7 @@ public final class UtilHttp {
                 Debug.logError("File upload error" + e, module);
             }
             if (uploadedItems != null) {
+                request.setAttribute("fileItems", uploadedItems);
                 for (FileItem item: uploadedItems) {
                     String fieldName = item.getFieldName();
                     //byte[] itemBytes = item.get();


[ofbiz-framework] 24/26: Improved: Implemented: Documented: Completed: Reverted: Fixed:

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 768353a09339eb431c89d50ee96568a998352d4b
Author: Jacques Le Roux <ja...@les7arts.com>
AuthorDate: Sat Apr 4 15:25:16 2020 +0200

    Improved:
    Implemented:
    Documented:
    Completed:
    Reverted:
    Fixed:
    
    (OFBIZ-)
    Explanation
    Thanks:
---
 .../security/src/main/java/org/apache/ofbiz/security/CsrfUtil.java      | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/framework/security/src/main/java/org/apache/ofbiz/security/CsrfUtil.java b/framework/security/src/main/java/org/apache/ofbiz/security/CsrfUtil.java
index eaf5635..9d400b8 100644
--- a/framework/security/src/main/java/org/apache/ofbiz/security/CsrfUtil.java
+++ b/framework/security/src/main/java/org/apache/ofbiz/security/CsrfUtil.java
@@ -139,7 +139,7 @@ public class CsrfUtil {
             // e.g. "/viewprofile?partyId=Company" to "/viewprofile"
             requestUri = requestUri.substring(0, requestUri.indexOf("?"));
         }
-        String controlServletPart = "/control/";
+        String controlServletPart = "/control/"; // TODO remove with OFBIZ-11229
         if (requestUri.contains(controlServletPart)) {
             // e.g. "/partymgr/control/viewprofile" to "viewprofile"
             requestUri = requestUri.substring(requestUri.indexOf(controlServletPart) + controlServletPart.length());


[ofbiz-framework] 23/26: Merges OFBiz trunk

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 5bc579ab4a6679e5840e7b9aeb377859441dd02e
Author: Jacques Le Roux <ja...@les7arts.com>
AuthorDate: Thu Feb 27 14:36:26 2020 +0100

    Merges OFBiz trunk


[ofbiz-framework] 11/26: Improved: unify style application

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 20cf076c4487649b4678cb526080ef6af7e1056f
Author: Pierre Smits <pi...@apache.org>
AuthorDate: Sun Mar 15 10:01:23 2020 +0100

    Improved: unify style application
    
    (OFBIZ-11458)
    
    replace 'align-float' with 'align-text'
---
 applications/accounting/template/ar/payment/BatchPayments.ftl | 4 ++--
 applications/party/template/visit/ShowVisits.ftl              | 4 ++--
 applications/party/template/visit/VisitDetail.ftl             | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/applications/accounting/template/ar/payment/BatchPayments.ftl b/applications/accounting/template/ar/payment/BatchPayments.ftl
index 17cb591..fe40363 100644
--- a/applications/accounting/template/ar/payment/BatchPayments.ftl
+++ b/applications/accounting/template/ar/payment/BatchPayments.ftl
@@ -128,7 +128,7 @@ function setServiceName(selection) {
                     <span class="label">${uiLabelMap.AccountingRunningTotal} :</span>
                     <span class="label" id="showPaymentRunningTotal"></span>
                 </div>
-                <div class="align-float">
+                <div class="align-text">
                     <select name="serviceName" id="serviceName" onchange="javascript:setServiceName(this);">
                         <option value="">${uiLabelMap.AccountingSelectAction}</option>
                         <option value="<@o...@ofbizUrl>" id="processBatchPayment">${uiLabelMap.AccountingCreateBatch}</option>
@@ -154,7 +154,7 @@ function setServiceName(selection) {
                     <input type="hidden" name='thruDate' value="${thruDate!}" />
                 </div>
                 </div>
-                <div id="createPaymentBatch" style="display: none;" class="align-float">
+                <div id="createPaymentBatch" style="display: none;" class="text">
                     <label for="paymentGroupName">${uiLabelMap.AccountingPaymentGroupName}</label>
                     <input type="text" size='25' id="paymentGroupName" name='paymentGroupName' />
                     <#if finAccounts?has_content>
diff --git a/applications/party/template/visit/ShowVisits.ftl b/applications/party/template/visit/ShowVisits.ftl
index 4e27e01..946b152 100644
--- a/applications/party/template/visit/ShowVisits.ftl
+++ b/applications/party/template/visit/ShowVisits.ftl
@@ -35,7 +35,7 @@ under the License.
   </div>
   <div class="screenlet-body">
       <br />
-        <div class="align-float">
+        <div class="align-text">
             <span class="label">
             <#if (visitSize > 0)>
                 <#if (viewIndex > 1)>
@@ -79,7 +79,7 @@ under the License.
         </#list>
       </table>
       <br />
-      <div class="align-float">
+      <div class="align-text">
           <span class="label">
           <#if (visitSize > 0)>
               <#if (viewIndex > 1)>
diff --git a/applications/party/template/visit/VisitDetail.ftl b/applications/party/template/visit/VisitDetail.ftl
index 9a516a1..6a5cbc7 100644
--- a/applications/party/template/visit/VisitDetail.ftl
+++ b/applications/party/template/visit/VisitDetail.ftl
@@ -95,7 +95,7 @@ under the License.
   </div>
   <div class="screenlet-body">
       <#if serverHits?has_content>
-        <div class="align-float">
+        <div class="align-text">
           <span class="label">
             <#if 0 < viewIndex>
               <a href="<@o...@ofbizUrl>" class="smallSubmit">${uiLabelMap.CommonPrevious}</a> |
@@ -151,7 +151,7 @@ under the License.
         </#if>
       </table>
       <#if serverHits?has_content>
-        <div class="align-float">
+        <div class="align-text">
           <span class="label">
             <#if 0 < viewIndex>
               <a href="<@o...@ofbizUrl>" class="smallSubmit">${uiLabelMap.CommonPrevious}</a> |


[ofbiz-framework] 07/26: Improved: Added unit testing, using JMockit, to ensure that form macros are rendered using ids from ModelFormField#getCurrentContainerId.

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit c68d43efa21b91f91a33fc002af1d387b0b11483
Author: Jacques Le Roux <ja...@les7arts.com>
AuthorDate: Sat Mar 21 23:01:36 2020 +0100

    Improved: Added unit testing, using JMockit, to ensure that form macros are
    rendered using ids from ModelFormField#getCurrentContainerId.
    
    (OFBIZ-4035)
    
    Fixes an issue due to Eclipse automated import organisation.
    
    There are still check style errors
---
 .../renderer/macro/MacroFormRendererTest.java      | 37 ++++++++++------------
 1 file changed, 17 insertions(+), 20 deletions(-)

diff --git a/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java b/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java
index 6c5f60b..7e63336 100644
--- a/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java
+++ b/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java
@@ -18,14 +18,14 @@
  *******************************************************************************/
 package org.apache.ofbiz.widget.renderer.macro;
 
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.Map;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
+import com.google.common.collect.ImmutableMap;
+import freemarker.core.Environment;
+import freemarker.template.Template;
+import freemarker.template.TemplateException;
+import mockit.Expectations;
+import mockit.Mock;
+import mockit.MockUp;
+import mockit.Mocked;
 import org.apache.ofbiz.base.util.UtilCodec;
 import org.apache.ofbiz.base.util.UtilCodec.SimpleEncoder;
 import org.apache.ofbiz.base.util.UtilHttp;
@@ -34,18 +34,15 @@ import org.apache.ofbiz.webapp.control.RequestHandler;
 import org.apache.ofbiz.widget.model.ModelFormField;
 import org.apache.ofbiz.widget.model.ThemeFactory;
 import org.apache.ofbiz.widget.renderer.VisualTheme;
-import org.hibernate.jdbc.Expectations;
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.Mock;
 
-import com.google.common.collect.ImmutableMap;
-
-import freemarker.core.Environment;
-import freemarker.template.Template;
-import freemarker.template.TemplateException;
-import mockit.MockUp;
-import mockit.Mocked;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Map;
 
 public class MacroFormRendererTest {
 
@@ -95,11 +92,11 @@ public class MacroFormRendererTest {
     }
 
     @Test
-    public void textRendererUsesContainerId(@Mocked ModelFormField.TextField textField) 
+    public void textRendererUsesContainerId(@Mocked ModelFormField.TextField textField)
             throws IOException, TemplateException {
         new Expectations() {{
-            httpSession.getAttribute("delegatorName");
-            result = "delegator";
+                httpSession.getAttribute("delegatorName");
+                result = "delegator";
 
             textField.getModelFormField();
             result = modelFormField;


[ofbiz-framework] 18/26: Improved: Improve Web Content Caching

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit e666c65b7cb210bfeffb35884001775dc08fd3aa
Author: Jacques Le Roux <ja...@les7arts.com>
AuthorDate: Fri Mar 27 10:05:37 2020 +0100

    Improved: Improve Web Content Caching
    
    (OFBIZ-11477)
    
    According to OWASP OFBiz Web Content Caching is weak:
    
    Independently of the cache policy defined by the web application, if caching web
    application contents is allowed, the session IDs must never be cached, so it is
    highly recommended to use the Cache-Control: no-cache="Set-Cookie, Set-Cookie2"
    directive, to allow web clients to cache everything except the session ID
    
    I though noticed that Set-Cookie2 is deprecated for a long time now. And we new
    browsers policies it to often updated. So no need to use Set-Cookie2.
---
 .../src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java   | 2 ++
 1 file changed, 2 insertions(+)

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 d24f2b2..b18fa8d 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
@@ -991,6 +991,8 @@ public class RequestHandler {
         if (viewNoCache) {
            UtilHttp.setResponseBrowserProxyNoCache(resp);
            if (Debug.verboseOn()) Debug.logVerbose("Sending no-cache headers for view [" + nextPage + "]", module);
+        } else {
+            resp.setHeader("Cache-Control", "Set-Cookie");
         }
         
         //Security Headers


[ofbiz-framework] 04/26: Improved: Added unit testing, using JMockit, to ensure that form macros are rendered using ids from ModelFormField#getCurrentContainerId.

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 87277ab9925f9dfa7787b86605b43857d2fc4978
Author: Daniel Watford <da...@watfordconsulting.com>
AuthorDate: Sun Feb 23 18:33:33 2020 +0000

    Improved: Added unit testing, using JMockit, to ensure that form macros are
    rendered using ids from ModelFormField#getCurrentContainerId.
    
    (OFBIZ-4035)
---
 build.gradle                                       |   5 +
 .../renderer/macro/MacroFormRendererTest.java      | 151 +++++++++++++++++++++
 2 files changed, 156 insertions(+)

diff --git a/build.gradle b/build.gradle
index 1488f35..8bae19d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -197,6 +197,7 @@ dependencies {
     implementation 'com.auth0:java-jwt:3.8.3'
     testImplementation 'org.hamcrest:hamcrest-library:2.2' // Enable junit4 to not depend on hamcrest-1.3
     testImplementation 'org.mockito:mockito-core:3.2.0'
+    testImplementation 'org.jmockit:jmockit:1.49'
     testImplementation 'com.pholser:junit-quickcheck-generators:0.9'
     runtimeOnly 'javax.xml.soap:javax.xml.soap-api:1.4.0'
     runtimeOnly 'de.odysseus.juel:juel-spi:2.2.7'
@@ -318,6 +319,10 @@ eclipse.classpath.file.whenMerged { classpath ->
 }
 tasks.eclipse.dependsOn(cleanEclipse)
 
+test {
+    jvmArgs "-javaagent:${classpath.find { it.name.contains("jmockit") }.absolutePath}"
+}
+
 /* ========================================================
  * Tasks
  * ======================================================== */
diff --git a/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java b/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java
new file mode 100644
index 0000000..a2d4fb1
--- /dev/null
+++ b/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java
@@ -0,0 +1,151 @@
+package org.apache.ofbiz.widget.renderer.macro;
+
+import com.google.common.collect.ImmutableMap;
+import freemarker.core.Environment;
+import freemarker.template.Template;
+import freemarker.template.TemplateException;
+import mockit.Expectations;
+import mockit.Mock;
+import mockit.MockUp;
+import mockit.Mocked;
+import org.apache.ofbiz.base.util.UtilCodec;
+import org.apache.ofbiz.base.util.UtilCodec.SimpleEncoder;
+import org.apache.ofbiz.base.util.UtilHttp;
+import org.apache.ofbiz.base.util.template.FreeMarkerWorker;
+import org.apache.ofbiz.webapp.control.RequestHandler;
+import org.apache.ofbiz.widget.model.ModelFormField;
+import org.apache.ofbiz.widget.model.ThemeFactory;
+import org.apache.ofbiz.widget.renderer.VisualTheme;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Map;
+
+public class MacroFormRendererTest {
+
+    @Mocked
+    private HttpServletRequest request;
+
+    @Mocked
+    private HttpServletResponse response;
+
+    @Mocked
+    private HttpSession httpSession;
+
+    @Mocked
+    private Template template;
+
+    @Mocked
+    private Environment environment;
+
+    @Mocked
+    private VisualTheme visualTheme;
+
+    @Mocked
+    private RequestHandler requestHandler;
+
+    @Mocked
+    private SimpleEncoder simpleEncoder;
+
+    @Mocked
+    private ModelFormField.ContainerField containerField;
+
+    @Mocked
+    private ModelFormField modelFormField;
+
+    @Mocked
+    private Appendable appendable;
+
+    @Mocked
+    private StringReader stringReader;
+
+    @Before
+    public void setupMockups() {
+        new FreeMarkerWorkerMockUp();
+        new ThemeFactoryMockUp();
+        new RequestHandlerMockUp();
+        new UtilHttpMockUp();
+        new UtilCodecMockUp();
+    }
+
+    @Test
+    public void textRendererUsesContainerId(@Mocked ModelFormField.TextField textField) throws IOException, TemplateException {
+        new Expectations() {{
+            httpSession.getAttribute("delegatorName");
+            result = "delegator";
+
+            textField.getModelFormField();
+            result = modelFormField;
+
+            modelFormField.getTooltip(withNotNull());
+            result = "";
+
+            modelFormField.getCurrentContainerId(withNotNull());
+            result = "CurrentTextId";
+
+            new StringReader(withSubstring("id=\"CurrentTextId\""));
+        }};
+
+        final MacroFormRenderer macroFormRenderer = new MacroFormRenderer(null, request, response);
+        macroFormRenderer.renderTextField(appendable, ImmutableMap.of("session", httpSession), textField);
+    }
+
+    @Test
+    public void containerRendererUsesContainerId() throws IOException, TemplateException {
+        new Expectations() {{
+            modelFormField.getCurrentContainerId(withNotNull());
+            result = "CurrentContainerId";
+
+            new StringReader(withSubstring("id=\"CurrentContainerId\""));
+        }};
+
+        final MacroFormRenderer macroFormRenderer = new MacroFormRenderer(null, request, response);
+        macroFormRenderer.renderContainerFindField(appendable, ImmutableMap.of(), containerField);
+    }
+
+    class FreeMarkerWorkerMockUp extends MockUp<FreeMarkerWorker> {
+        @Mock
+        public Template getTemplate(String templateLocation) {
+            return template;
+        }
+
+        @Mock
+        public Environment renderTemplate(Template template, Map<String, Object> context, Appendable outWriter) {
+            return environment;
+        }
+    }
+
+    class ThemeFactoryMockUp extends MockUp<ThemeFactory> {
+        @Mock
+        public VisualTheme resolveVisualTheme(HttpServletRequest request) {
+            return visualTheme;
+        }
+    }
+
+    class RequestHandlerMockUp extends MockUp<RequestHandler> {
+        @Mock
+        public RequestHandler from(HttpServletRequest request) {
+            return requestHandler;
+        }
+    }
+
+    class UtilHttpMockUp extends MockUp<UtilHttp> {
+        @Mock
+        public boolean isJavaScriptEnabled(HttpServletRequest request) {
+            return true;
+        }
+    }
+
+    class UtilCodecMockUp extends MockUp<UtilCodec> {
+        @Mock
+        public SimpleEncoder getEncoder(String type) {
+            return simpleEncoder;
+        }
+    }
+}
+


[ofbiz-framework] 05/26: Improved: Added license header to MacroFormRendererTest

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 1fbf6c3d6b614cadd340fc3550cef37c95188cd9
Author: Daniel Watford <da...@watfordconsulting.com>
AuthorDate: Mon Feb 24 07:05:11 2020 +0000

    Improved: Added license header to MacroFormRendererTest
    
    (OFBIZ-4035)
---
 .../widget/renderer/macro/MacroFormRendererTest.java   | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java b/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java
index a2d4fb1..3eb10c0 100644
--- a/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java
+++ b/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java
@@ -1,3 +1,21 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *******************************************************************************/
 package org.apache.ofbiz.widget.renderer.macro;
 
 import com.google.common.collect.ImmutableMap;


[ofbiz-framework] 21/26: Fixed: correct path to ftpAddress services (OFBIZ-11359)

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 8fc5028be99aa0df662dabbb93d0c9cd36271e6a
Author: Nicolas Malin <ni...@nereide.fr>
AuthorDate: Fri Mar 27 11:41:03 2020 +0100

    Fixed: correct path to ftpAddress services
    (OFBIZ-11359)
    
    After the minilang ContactMarchServices.xml to groovy, I forgot to change
    the path of existant ftpAddress services already present before.
    
    Thanks to Olivier Heintz for this alert
---
 applications/party/servicedef/services_contact.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/applications/party/servicedef/services_contact.xml b/applications/party/servicedef/services_contact.xml
index 1fa4461..90fd990 100644
--- a/applications/party/servicedef/services_contact.xml
+++ b/applications/party/servicedef/services_contact.xml
@@ -91,14 +91,14 @@ under the License.
         <attribute name="emailAddress" type="String" mode="IN" optional="false"/>
     </service>
     <service name="createFtpAddress" default-entity-name="FtpAddress" engine="groovy" invoke="createFtpAddress"
-             location="component://party/groovyScripts/party/ContactMechServices.groovy">
+             location="component://party/groovyScripts/contact/ContactMechServices.groovy">
         <description>create FtpAddress</description>
         <permission-service service-name="partyBasePermissionCheck" main-action="CREATE"/>
         <auto-attributes mode="OUT" include="pk"/>
         <auto-attributes mode="IN" include="nonpk" optional="true"/>
     </service>
     <service name="updateFtpAddressWithHistory" default-entity-name="FtpAddress" engine="groovy" invoke="updateFtpAddressWithHistory"
-             location="component://party/groovyScripts/party/ContactMechServices.groovy">
+             location="component://party/groovyScripts/contact/ContactMechServices.groovy">
         <description>update FtpAddress</description>
         <permission-service service-name="partyBasePermissionCheck" main-action="UPDATE"/>
         <auto-attributes mode="IN" include="pk"/>


[ofbiz-framework] 17/26: Improved: type="text/css" was missing on a call to < Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 6c49411ee7914e3aff8e31c802bff0721361abef
Author: Jacques Le Roux <ja...@les7arts.com>
AuthorDate: Sat Mar 14 08:51:06 2020 +0100

    Improved: "auth" should be true for all the request url used for Application
    components
    
    (OFBIZ-4956)
    
    Currently there are some URLs present in application components with
    auth="false". So anyone can hit these URLs and access these resources without
    authorization.
    I think all the URLs should be secure with auth="true"
    
    jleroux: I have also fixed the dataResourceId="GZ-DIG"
    
    Thanks: Amardeep Singh Jhajj for report and initial fix
---
 applications/accounting/webapp/accounting/WEB-INF/controller.xml  | 6 +++---
 applications/content/webapp/content/WEB-INF/controller.xml        | 4 ++--
 applications/datamodel/data/demo/OrderDemoData.xml                | 2 +-
 applications/humanres/webapp/humanres/WEB-INF/controller.xml      | 2 +-
 .../manufacturing/webapp/manufacturing/WEB-INF/controller.xml     | 2 +-
 applications/marketing/webapp/marketing/WEB-INF/controller.xml    | 2 +-
 applications/order/webapp/ordermgr/WEB-INF/controller.xml         | 8 ++++----
 applications/party/webapp/partymgr/WEB-INF/controller.xml         | 8 ++++----
 applications/product/webapp/catalog/WEB-INF/controller.xml        | 6 +++---
 applications/product/webapp/facility/WEB-INF/controller.xml       | 2 +-
 framework/common/webcommon/WEB-INF/common-controller.xml          | 2 +-
 11 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/applications/accounting/webapp/accounting/WEB-INF/controller.xml b/applications/accounting/webapp/accounting/WEB-INF/controller.xml
index a692b46..7116519 100644
--- a/applications/accounting/webapp/accounting/WEB-INF/controller.xml
+++ b/applications/accounting/webapp/accounting/WEB-INF/controller.xml
@@ -874,7 +874,7 @@ under the License.
 
     <!-- =============== Fixed Asset mapping =================-->
     <request-map uri="ListFixedAssets"><security https="true" auth="true"/><response name="success" type="view" value="ListFixedAssets"/></request-map>
-    <request-map uri="FixedAssetSearchResults"><security https="true" auth="false"/><response name="success" type="view" value="FixedAssetSearchResults"/></request-map>
+    <request-map uri="FixedAssetSearchResults"><security https="true" auth="true"/><response name="success" type="view" value="FixedAssetSearchResults"/></request-map>
     <request-map uri="EditFixedAsset"><security https="true" auth="true"/><response name="success" type="view" value="EditFixedAsset"/></request-map>
     <request-map uri="createFixedAsset">
         <security https="true" auth="true"/>
@@ -2030,7 +2030,7 @@ under the License.
         <response name="error" type="request" value="json"/>
     </request-map>
     <request-map uri="reconcileFinAccountTrans">
-        <security https="true" auth="false"/>
+        <security https="true" auth="true"/>
         <event type="service-multi" invoke="reconcileFinAccountTrans"/>
         <response name="success" type="view" value="BankReconciliation"/>
         <response name="error" type="view" value="BankReconciliation"/>
@@ -2066,7 +2066,7 @@ under the License.
         <response name="error" type="view" value="ViewGlReconciliationWithTransaction"/>
     </request-map>
     <request-map uri="assignGlRecToFinAccTrans">
-        <security https="true" auth="false"/>
+        <security https="true" auth="true"/>
         <event type="service-multi" invoke="assignGlRecToFinAccTrans"/>
         <response name="success" type="view" value="FindFinAccountTrans"/>
         <response name="error" type="view" value="FindFinAccountTrans"/>
diff --git a/applications/content/webapp/content/WEB-INF/controller.xml b/applications/content/webapp/content/WEB-INF/controller.xml
index 0732b6c..468cfbd 100644
--- a/applications/content/webapp/content/WEB-INF/controller.xml
+++ b/applications/content/webapp/content/WEB-INF/controller.xml
@@ -1029,7 +1029,7 @@ under the License.
     </request-map>
     <request-map uri="UploadImage"><security auth="true" https="true"/><response name="success" type="view" value="UploadImage"/></request-map>
     <request-map uri="img">
-        <security auth="false" https="false"/>
+        <security auth="true" https="true"/>
         <event type="java" path="org.apache.ofbiz.content.data.DataEvents" invoke="serveImage"/>
         <response name="success" type="none"/>
         <response name="error" type="request" value="main"/>
@@ -1756,7 +1756,7 @@ under the License.
     <!-- ================ SimpleContent Requests ================= -->
 
     <request-map uri="ViewSimpleContent">
-        <security auth="false" https="false"/>
+        <security auth="true" https="true"/>
         <response name="success" type="view" value="ViewSimpleContent"/>
     </request-map>
 
diff --git a/applications/datamodel/data/demo/OrderDemoData.xml b/applications/datamodel/data/demo/OrderDemoData.xml
index 6b4929b..04bcc3e 100644
--- a/applications/datamodel/data/demo/OrderDemoData.xml
+++ b/applications/datamodel/data/demo/OrderDemoData.xml
@@ -792,7 +792,7 @@ under the License.
 
     <!-- test Digital Download product -->
     <Product productId="GZ-DIG" productTypeId="DIGITAL_GOOD" primaryProductCategoryId="101" productName="Digital Gizmo" internalName="Digital Gizmo" description="A digital gizmo: can be downloaded immediately after purchase." longDescription="This gizmo is part of an exciting new breed that needs no corporeal form: it is all digital! Buy and download it now!" taxable="Y" chargeShipping="N" autoCreateKeywords="Y" isVirtual="N" isVariant="N" createdDate="2001-05-13 12:00:00.0" createdByUse [...]
-    <DataResource dataResourceId="GZ-DIG" dataResourceTypeId="OFBIZ_FILE_BIN" mimeTypeId="image/gif" dataResourceName="Digital Gizmo Image" objectInfo="themes/common/webapp/images/ofbiz_logo.png"/>
+    <DataResource dataResourceId="GZ-DIG" dataResourceTypeId="OFBIZ_FILE_BIN" mimeTypeId="image/gif" dataResourceName="Digital Gizmo Image" objectInfo="themes/common-theme/webapp/images/ofbiz_logo.png"/>
     <DataResource dataResourceTypeId="ELECTRONIC_TEXT" dataResourceId="GZ-DIG-ALT" localeString="en"/>
     <DataResource dataResourceTypeId="ELECTRONIC_TEXT" dataResourceId="DRGZ-DIG-ALTEN" localeString="en_US"/>
     <ElectronicText dataResourceId="GZ-DIG-ALT" textData="digital-gizmo"/>
diff --git a/applications/humanres/webapp/humanres/WEB-INF/controller.xml b/applications/humanres/webapp/humanres/WEB-INF/controller.xml
index fb8810c..fc137a9 100644
--- a/applications/humanres/webapp/humanres/WEB-INF/controller.xml
+++ b/applications/humanres/webapp/humanres/WEB-INF/controller.xml
@@ -40,7 +40,7 @@ under the License.
 
     <!-- Request Mappings -->
     <request-map uri="view">
-        <security https="true" auth="false"/>
+        <security https="true" auth="true"/>
         <response name="success" type="request" value="main"/>
     </request-map>
     
diff --git a/applications/manufacturing/webapp/manufacturing/WEB-INF/controller.xml b/applications/manufacturing/webapp/manufacturing/WEB-INF/controller.xml
index 9550502..4948591 100644
--- a/applications/manufacturing/webapp/manufacturing/WEB-INF/controller.xml
+++ b/applications/manufacturing/webapp/manufacturing/WEB-INF/controller.xml
@@ -39,7 +39,7 @@ under the License.
 
     <!-- Request Mappings -->
     <request-map uri="view">
-        <security https="false" auth="false"/>
+        <security https="true" auth="true"/>
         <response name="success" type="request" value="main"/>
     </request-map>
 
diff --git a/applications/marketing/webapp/marketing/WEB-INF/controller.xml b/applications/marketing/webapp/marketing/WEB-INF/controller.xml
index de47863..7221e3a 100644
--- a/applications/marketing/webapp/marketing/WEB-INF/controller.xml
+++ b/applications/marketing/webapp/marketing/WEB-INF/controller.xml
@@ -305,7 +305,7 @@ under the License.
         <response name="error" type="request-redirect" value="FindImportContactListParties"/>
     </request-map>
     <request-map uri="contactListOptOut" track-serverhit="false" track-visit="false">
-        <security https="true" auth="false"/>        
+        <security https="true" auth="true"/>
         <event type="service" invoke="updateContactListPartyNoUserLogin"/>
         <response name="success" type="view" value="ContactListOptOut"/>
     </request-map>
diff --git a/applications/order/webapp/ordermgr/WEB-INF/controller.xml b/applications/order/webapp/ordermgr/WEB-INF/controller.xml
index 2d4cce3..10c5d3c 100644
--- a/applications/order/webapp/ordermgr/WEB-INF/controller.xml
+++ b/applications/order/webapp/ordermgr/WEB-INF/controller.xml
@@ -39,7 +39,7 @@ under the License.
 
     <!-- Request Mappings -->
     <request-map uri="view">
-        <security https="false" auth="false"/>
+        <security https="true" auth="true"/>
         <response name="success" type="request" value="main"/>
     </request-map>
 
@@ -229,7 +229,7 @@ under the License.
     </request-map>
 
     <request-map uri="getConfigDetailsEvent">
-        <security https="true" auth="false"/>
+        <security https="true" auth="true"/>
         <event type="java" path="org.apache.ofbiz.order.shoppingcart.ShoppingCartEvents" invoke="getConfigDetailsEvent"/>
         <response name="success" type="request" value="json"/>
         <response name="error" type="request" value="json"/>
@@ -596,7 +596,7 @@ under the License.
         <response name="success" type="view" value="AddGiftCertificate"/>
     </request-map>
     <request-map uri="addGiftCertificateSurvey">
-        <security https="true" auth="false"/>
+        <security https="true" auth="true"/>
         <event type="java" invoke="createSurveyResponseAndRestoreParameters" path="org.apache.ofbiz.content.survey.SurveyEvents"/>
         <response name="success" type="request" value="additem"/>
         <response name="error" type="view" value="AddGiftCertificate"/>
@@ -1794,7 +1794,7 @@ under the License.
     </request-map>
 
     <request-map uri="crosssell">
-        <security https="false" auth="false"/>
+        <security https="true" auth="true"/>
         <response name="success" type="view" value="product"/>
     </request-map>
 
diff --git a/applications/party/webapp/partymgr/WEB-INF/controller.xml b/applications/party/webapp/partymgr/WEB-INF/controller.xml
index a9bee45..1936fca 100644
--- a/applications/party/webapp/partymgr/WEB-INF/controller.xml
+++ b/applications/party/webapp/partymgr/WEB-INF/controller.xml
@@ -41,7 +41,7 @@ under the License.
     -->
 
     <!-- Request Mappings -->
-    <request-map uri="view"><security https="true" auth="false"/><response name="success" type="request" value="main"/></request-map>
+    <request-map uri="view"><security https="true" auth="true"/><response name="success" type="request" value="main"/></request-map>
     
     <request-map uri="main"><security https="true" auth="true"/><response name="success" type="view" value="main"/></request-map>
 
@@ -995,7 +995,7 @@ under the License.
    <!-- ================ SimpleContent Requests ================= -->
 
     <request-map uri="ViewSimpleContent">
-        <security auth="false" https="false"/>
+        <security auth="true" https="true"/>
         <response name="success" type="view" value="ViewSimpleContent"/>
     </request-map>
 
@@ -1050,7 +1050,7 @@ under the License.
     </request-map>
 
     <request-map uri="img">
-        <security auth="false" https="false"/>
+        <security auth="true" https="true"/>
         <event type="java" path="org.apache.ofbiz.content.data.DataEvents" invoke="serveImage"/>
         <response name="success" type="none"/>
         <response name="error" type="request" value="main"/>
@@ -1342,7 +1342,7 @@ under the License.
 
     <!--  external communication event; mark as read using 1px image request -->
     <request-map uri="ceimages" track-serverhit="false" track-visit="false">
-        <security https="false" auth="false"/>
+        <security https="false" auth="true"/>
         <event type="java" path="org.apache.ofbiz.party.communication.CommunicationEventServices" invoke="markCommunicationAsRead"/>
         <response name="success" type="none"/>
     </request-map>
diff --git a/applications/product/webapp/catalog/WEB-INF/controller.xml b/applications/product/webapp/catalog/WEB-INF/controller.xml
index 65257f2..496f99b 100644
--- a/applications/product/webapp/catalog/WEB-INF/controller.xml
+++ b/applications/product/webapp/catalog/WEB-INF/controller.xml
@@ -1922,7 +1922,7 @@ under the License.
     
     <!-- Get Values options associated with a Price Rule Condition Input -->
     <request-map uri="getAssociatedPriceRulesConds">
-        <security https="true" auth="false"/>
+        <security https="true" auth="true"/>
         <event type="service" invoke="getAssociatedPriceRulesConds"/>
         <response name="success" type="request" value="json"/>
         <response name="error" type="request" value="json"/>
@@ -2836,7 +2836,7 @@ under the License.
         </response>
     </request-map>
     <request-map uri="viewImage">
-        <security https="false" auth="false"/>
+        <security https="true" auth="true"/>
         <response name="success" type="view" value="viewImage"/>
         <response name="error" type="view" value="viewImage"/>
     </request-map>
@@ -3031,7 +3031,7 @@ under the License.
         <response name="error" type="request" value="json"/>
     </request-map>
     <request-map uri="listMiniproduct">
-        <security auth="false" https="true"/>
+        <security auth="true" https="true"/>
         <response name="success" type="view" value="listMiniproduct"/>
     </request-map>
 
diff --git a/applications/product/webapp/facility/WEB-INF/controller.xml b/applications/product/webapp/facility/WEB-INF/controller.xml
index 0ddf8e0..35cb285 100644
--- a/applications/product/webapp/facility/WEB-INF/controller.xml
+++ b/applications/product/webapp/facility/WEB-INF/controller.xml
@@ -53,7 +53,7 @@ under the License.
         <response name="success" type="view" value="FindFacility"/>
     </request-map>
     <request-map uri="FacilitySearchResults">
-        <security https="true" auth="false"/>
+        <security https="true" auth="true"/>
         <response name="success" type="view" value="FacilitySearchResults"/>
     </request-map>
     <request-map uri="EditFacility">
diff --git a/framework/common/webcommon/WEB-INF/common-controller.xml b/framework/common/webcommon/WEB-INF/common-controller.xml
index b2cd339..46fa551 100644
--- a/framework/common/webcommon/WEB-INF/common-controller.xml
+++ b/framework/common/webcommon/WEB-INF/common-controller.xml
@@ -237,7 +237,7 @@ under the License.
     <!--========================== AJAX events =====================-->
     <!-- Get states related to a country -->
     <request-map uri="getAssociatedStateList">
-        <security https="true" auth="false"/>
+        <security https="true" auth="true"/>
         <event type="service" invoke="getAssociatedStateList"/>
         <response name="success" type="request" value="json"/>
         <response name="error" type="request" value="json"/>


[ofbiz-framework] 22/26: Fixed: correct path to ftpAddress services (OFBIZ-11359)

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 37f33f48ff56a1201181e51bc3a2c2fb373e2e43
Author: Nicolas Malin <ni...@nereide.fr>
AuthorDate: Fri Mar 27 11:46:11 2020 +0100

    Fixed: correct path to ftpAddress services
    (OFBIZ-11359)
    
    After the minilang ContactMarchServices.xml to groovy, I forgot to change
    the path of existant ftpAddress services already present before.
    
    Thanks to Olivier Heintz for this alert
---
 applications/party/servicedef/services.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/applications/party/servicedef/services.xml b/applications/party/servicedef/services.xml
index b26dcfc..fc71f8e 100644
--- a/applications/party/servicedef/services.xml
+++ b/applications/party/servicedef/services.xml
@@ -505,7 +505,7 @@ under the License.
         <attribute name="partyIdTo" type="String" mode="IN" optional="false"/>
     </service>
     <service name="createPartyFtpAddress" engine="groovy"
-             location="component://party/groovyScripts/party/ContactMechServices.groovy" invoke="createPartyFtpAddress" auth="true">
+             location="component://party/groovyScripts/contact/ContactMechServices.groovy" invoke="createPartyFtpAddress" auth="true">
         <description>Create an Ftp Address associated to a party</description>
         <permission-service service-name="partyContactMechPermissionCheck" main-action="CREATE"/>
         <auto-attributes entity-name="ContactMech" include="nonpk" mode="IN" optional="true"/>
@@ -515,7 +515,7 @@ under the License.
         <attribute name="contactMechId" type="String" mode="INOUT" optional="true"/>
     </service>
     <service name="updatePartyFtpAddress" engine="groovy"
-             location="component://party/groovyScripts/party/ContactMechServices.groovy" invoke="updatePartyFtpAddress" auth="true">
+             location="component://party/groovyScripts/contact/ContactMechServices.groovy" invoke="updatePartyFtpAddress" auth="true">
         <description>Update an Ftp Address associated to a party</description>
         <permission-service service-name="partyContactMechPermissionCheck" main-action="UPDATE"/>
         <auto-attributes entity-name="PartyContactMech" mode="IN" optional="true"/>


[ofbiz-framework] 15/26: Improved: no functional change

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 060e9ab950da20d6c03825b5676b86f532a3c718
Author: Jacques Le Roux <ja...@les7arts.com>
AuthorDate: Tue Mar 24 18:31:54 2020 +0100

    Improved: no functional change
    
    Adds /uploads/ in .runtime/.gitignore
---
 runtime/.gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/runtime/.gitignore b/runtime/.gitignore
index f4a9877..290c994 100644
--- a/runtime/.gitignore
+++ b/runtime/.gitignore
@@ -6,3 +6,4 @@
 /tmp
 /tempfiles
 /output
+/uploads/


[ofbiz-framework] 08/26: Improved: Added unit testing, using JMockit, to ensure that form macros are rendered using ids from ModelFormField#getCurrentContainerId.

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 43f46399ffdf144adf164da08edf5af97c8ebca7
Author: Jacques Le Roux <ja...@les7arts.com>
AuthorDate: Sat Mar 21 23:09:05 2020 +0100

    Improved: Added unit testing, using JMockit, to ensure that form macros are
    rendered using ids from ModelFormField#getCurrentContainerId.
    
    (OFBIZ-4035)
    
    Fixes check style errors
---
 .../renderer/macro/MacroFormRendererTest.java      | 24 +++++++++++-----------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java b/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java
index 7e63336..b89086d 100644
--- a/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java
+++ b/framework/widget/src/test/java/org/apache/ofbiz/widget/renderer/macro/MacroFormRendererTest.java
@@ -98,17 +98,17 @@ public class MacroFormRendererTest {
                 httpSession.getAttribute("delegatorName");
                 result = "delegator";
 
-            textField.getModelFormField();
-            result = modelFormField;
+                textField.getModelFormField();
+                result = modelFormField;
 
-            modelFormField.getTooltip(withNotNull());
-            result = "";
+                modelFormField.getTooltip(withNotNull());
+                result = "";
 
-            modelFormField.getCurrentContainerId(withNotNull());
-            result = "CurrentTextId";
+                modelFormField.getCurrentContainerId(withNotNull());
+                result = "CurrentTextId";
 
-            new StringReader(withSubstring("id=\"CurrentTextId\""));
-        }};
+                new StringReader(withSubstring("id=\"CurrentTextId\""));
+            }};
 
         final MacroFormRenderer macroFormRenderer = new MacroFormRenderer(null, request, response);
         macroFormRenderer.renderTextField(appendable, ImmutableMap.of("session", httpSession), textField);
@@ -117,11 +117,11 @@ public class MacroFormRendererTest {
     @Test
     public void containerRendererUsesContainerId() throws IOException, TemplateException {
         new Expectations() {{
-            modelFormField.getCurrentContainerId(withNotNull());
-            result = "CurrentContainerId";
+                modelFormField.getCurrentContainerId(withNotNull());
+                result = "CurrentContainerId";
 
-            new StringReader(withSubstring("id=\"CurrentContainerId\""));
-        }};
+                new StringReader(withSubstring("id=\"CurrentContainerId\""));
+            }};
 
         final MacroFormRenderer macroFormRenderer = new MacroFormRenderer(null, request, response);
         macroFormRenderer.renderContainerFindField(appendable, ImmutableMap.of(), containerField);


[ofbiz-framework] 16/26: Improved: Implement the pretty print for keyword search

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit f2e69894fb1a4070696a1e4d6d05eef3dd7a11b9
Author: Jacques Le Roux <ja...@les7arts.com>
AuthorDate: Thu Mar 26 11:07:29 2020 +0100

    Improved: Implement the pretty print for keyword search
    
    (OFBIZ-11476)
    
    With OFBIZ-9164 and r1835891 I introduced
    keywordConstraint::prettyPrintConstraint without implementation.
    So the information is missing at top of page.
    
    This implements it. It also amends 2 French labels
---
 applications/product/config/ProductUiLabels.xml                      | 4 ++--
 .../main/java/org/apache/ofbiz/product/product/ProductSearch.java    | 5 +----
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/applications/product/config/ProductUiLabels.xml b/applications/product/config/ProductUiLabels.xml
index 83b4a5e..421353b 100644
--- a/applications/product/config/ProductUiLabels.xml
+++ b/applications/product/config/ProductUiLabels.xml
@@ -29031,7 +29031,7 @@
         <value xml:lang="de">Sie haben gesucht nach</value>
         <value xml:lang="en">you searched for</value>
         <value xml:lang="es">ha buscado por</value>
-        <value xml:lang="fr">Vous avez recherché</value>
+        <value xml:lang="fr">vous avez recherché</value>
         <value xml:lang="it">tu hai cercato</value>
         <value xml:lang="ja">検索対象は</value>
         <value xml:lang="ro">tu ai cautat</value>
@@ -29075,7 +29075,7 @@
         <value xml:lang="de">Produkte suchen</value>
         <value xml:lang="en">Search Products</value>
         <value xml:lang="es">Buscar Productos</value>
-        <value xml:lang="fr">Rechercher l'article</value>
+        <value xml:lang="fr">Recherche d'articles</value>
         <value xml:lang="it">Ricerca prodotti</value>
         <value xml:lang="ja">製品を検索</value>
         <value xml:lang="nl">Zoeken producten</value>
diff --git a/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductSearch.java b/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductSearch.java
index 744f9b1..48e6532 100644
--- a/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductSearch.java
+++ b/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductSearch.java
@@ -1662,12 +1662,9 @@ public class ProductSearch {
             return true;
         }
 
-        /* (non-Javadoc)
-         * @see org.apache.ofbiz.product.product.ProductSearch.ProductSearchConstraint#prettyPrintConstraint(org.apache.ofbiz.service.LocalDispatcher, boolean, java.util.Locale)
-         */
         @Override
         public String prettyPrintConstraint(LocalDispatcher dispatcher, boolean detailed, Locale locale) {
-            return null;
+            return this.keywordsString;
         }
 
     }


[ofbiz-framework] 12/26: Improved: unify style application

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 321e51602a744799779b4edf7cd6ee5040ee2003
Author: Pierre Smits <pi...@apache.org>
AuthorDate: Sun Mar 15 10:03:14 2020 +0100

    Improved: unify style application
    
    (OFBIZ-11458)
    
    replace 'align-float' with 'align-text'
---
 applications/humanres/template/FindEmployee.ftl        | 2 +-
 applications/party/template/party/EditShoppingList.ftl | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/applications/humanres/template/FindEmployee.ftl b/applications/humanres/template/FindEmployee.ftl
index 3d47ef3..62581fd 100644
--- a/applications/humanres/template/FindEmployee.ftl
+++ b/applications/humanres/template/FindEmployee.ftl
@@ -213,7 +213,7 @@ under the License.
                     <td>${partyRow.postalCode!}</td>
                 </#if>
                 <td><#if partyType.description??>${partyType.get("description", locale)}<#else>???</#if></td>
-                <td class="button-col align-float">
+                <td class="button-col align-text">
                     <a href="<@o...@ofbizUrl>">${uiLabelMap.CommonDetails}</a>
                 </td>
             </tr>
diff --git a/applications/party/template/party/EditShoppingList.ftl b/applications/party/template/party/EditShoppingList.ftl
index 04efafe..fb98a23 100644
--- a/applications/party/template/party/EditShoppingList.ftl
+++ b/applications/party/template/party/EditShoppingList.ftl
@@ -155,7 +155,7 @@ under the License.
         <#assign childShoppingList = childShoppingListData.childShoppingList>
         <tr>
           <td class="button-col"><a href="<@o...@ofbizUrl>">${childShoppingList.listName?default(childShoppingList.shoppingListId)}</a></li>
-          <td class="button-col align-float">
+          <td class="button-col align-text">
             <a href="<@o...@ofbizUrl>">${uiLabelMap.PartyGotoList}</a>
             <a href="<@o...@ofbizUrl>">${uiLabelMap.PartyAddListToCart}</a>
           </td>


[ofbiz-framework] 14/26: Fixed: DataModel - correct foreign key (#51)

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 6c66ce0dc2d70207c971ea45d946f45bb35bbd91
Author: Pierre Smits <pi...@apache.org>
AuthorDate: Tue Mar 24 10:15:58 2020 +0100

    Fixed: DataModel - correct foreign key (#51)
    
    (OFBIZ-11474)
    
    Renaming foreign key to PROD_PRCDE_OPCD
---
 applications/datamodel/entitydef/product-entitymodel.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/applications/datamodel/entitydef/product-entitymodel.xml b/applications/datamodel/entitydef/product-entitymodel.xml
index e34749d..f1a1ef3 100644
--- a/applications/datamodel/entitydef/product-entitymodel.xml
+++ b/applications/datamodel/entitydef/product-entitymodel.xml
@@ -3647,7 +3647,7 @@ under the License.
       <field name="emailAddress" type="email"></field>
       <prim-key field="productPromoCodeId"/>
       <prim-key field="emailAddress"/>
-      <relation type="one" fk-name="PROD_PRCDE_PCD" rel-entity-name="ProductPromoCode">
+      <relation type="one" fk-name="PROD_PRCDE_OPCD" rel-entity-name="ProductPromoCode">
         <key-map field-name="productPromoCodeId"/>
       </relation>
     </entity>


[ofbiz-framework] 20/26: Improved: Convert PartyPermissionServices.xml from mini lang to groovy (OFBIZ-11433)

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 4594fc4964e92a48295608ec445394bfa1d5c3f3
Author: Harutyun Farajyan <ha...@ecomify.de>
AuthorDate: Tue Mar 17 16:44:35 2020 +0100

    Improved: Convert PartyPermissionServices.xml from mini lang to groovy
    (OFBIZ-11433)
    
    Thanks to Harutyun Farajyan for providing the patch
---
 .../party/PartyPermissionServices.groovy           | 280 ++++++++++++++++++++
 .../minilang/party/PartyPermissionServices.xml     | 284 ---------------------
 applications/party/servicedef/services.xml         |  51 ++--
 3 files changed, 309 insertions(+), 306 deletions(-)

diff --git a/applications/party/groovyScripts/party/PartyPermissionServices.groovy b/applications/party/groovyScripts/party/PartyPermissionServices.groovy
new file mode 100644
index 0000000..c004ddd
--- /dev/null
+++ b/applications/party/groovyScripts/party/PartyPermissionServices.groovy
@@ -0,0 +1,280 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.ofbiz.base.util.UtilProperties
+import org.apache.ofbiz.entity.GenericValue
+
+// ============== Basic Permission Checking =============
+
+//Returns hasPermission=true if user has one of the base PARTYMGR CRUD+ADMIN permissions
+/**
+ * Party Manager base permission logic
+ */
+def basePermissionCheck() {
+    parameters.primaryPermission = "PARTYMGR"
+    Map serviceResult = run service: "genericBasePermissionCheck", with: parameters
+    return serviceResult
+}
+
+//Returns hasPermission=true if userLogin partyId equals partyId parameter
+/**
+ * Party ID Permission Check
+ */
+def partyIdPermissionCheck(Map parameters) {
+    Map result = success()
+    Boolean hasPermission
+    String partyId = parameters.partyId
+
+    if (partyId && userLogin.partyId && partyId == userLogin.partyId) {
+        hasPermission = true
+    } else {
+        String resourceDescription = parameters.resourceDescription
+        if (!resourceDescription) {
+            resourceDescription = UtilProperties.getPropertyValue("CommonUiLabels", "CommonPermissionThisOperation")
+        }
+        String failMessage = UtilProperties.getMessage("PartyUiLabels",
+                "PartyPermissionErrorPartyId", [resourceDescription: resourceDescription], parameters.locale)
+        hasPermission = false
+        result.failMessage = failMessage
+    }
+    result.hasPermission = hasPermission
+    return result
+}
+
+//Returns hasPermission=true if userLogin party equals partyId parameter OR
+//      user has one of the base PARTYMGR CRUD+ADMIN permissions
+/**
+ * Base Permission Plus Party ID Permission Check
+ */
+def basePlusPartyIdPermissionCheck() {
+    Map result = run service: "basePermissionCheck", with: parameters
+    if (!result.hasPermission) {
+        result = partyIdPermissionCheck(parameters)
+    }
+    return result
+}
+
+// ============== Additional Permission Checking =============
+
+//Returns hasPermission=true if userLogin partyId equals partyId parameter OR
+//       user has one of the base PARTYMGR or PARTYMGR_STS CRUD+ADMIN permissions
+/**
+ * Party status permission logic
+ */
+def partyStatusPermissionCheck() {
+    Map result = success()
+    Boolean hasPermission = false
+    if (parameters.partyId && parameters.partyId == userLogin.partyId) {
+        hasPermission = true
+        result.hasPermission = hasPermission
+    }
+    if (!hasPermission) {
+        parameters.altPermission = "PARTYMGR_STS"
+        result = run service: "basePermissionCheck", with: parameters
+    }
+    return result
+}
+
+//Returns hasPermission=true if userLogin partyId equals partyId parameter OR
+//       user has one of the base PARTYMGR or PARTYMGR_GRP CRUD+ADMIN permissions
+/**
+ * Party group permission logic
+ */
+def partyGroupPermissionCheck() {
+    parameters.altPermission = "PARTYMGR_GRP"
+    Map result = run service: "partyStatusPermissionCheck", with: parameters
+    return result
+}
+
+//Returns hasPermission=true if user has one of the base PARTYMGR or PARTYMGR_SRC CRUD+ADMIN permissions
+/**
+ * Party datasource permission logic
+ */
+def partyDatasourcePermissionCheck() {
+    parameters.altPermission = "PARTYMGR_SRC"
+    Map result = run service: "basePermissionCheck", with: parameters
+    return result
+}
+
+//Returns hasPermission=true if user has one of the base PARTYMGR or PARTYMGR_ROLE CRUD+ADMIN permissions
+/**
+ * Party role permission logic
+ */
+def partyRolePermissionCheck() {
+    parameters.altPermission = "PARTYMGR_ROLE"
+    Map result = run service: "partyStatusPermissionCheck", with: parameters
+    return result
+}
+
+//Returns hasPermission=true if user has one of the base PARTYMGR or PARTYMGR_REL CRUD+ADMIN permissions
+/**
+ * Party relationship permission logic
+ */
+def partyRelationshipPermissionCheck() {
+    Map result = success()
+    if (!parameters.partyIdFrom) {
+        parameters.partyIdFrom = userLogin.partyId
+        result.hasPermission = true
+    } else {
+        parameters.altPermission = "PARTYMGR_REL"
+        result = run service: "basePermissionCheck", with: parameters
+    }
+    return result
+}
+
+//Returns hasPermission=true if userLogin partyId equals partyId parameter OR
+//       user has one of the base PARTYMGR or PARTYMGR_PCM CRUD+ADMIN permissions
+/**
+ * Party contact mech permission logic
+ */
+def partyContactMechPermissionCheck() {
+    Map result = success()
+    if (!parameters.partyId || userLogin.partyId == parameters.partyId) {
+        Boolean hasPermission = true
+        result.hasPermission = hasPermission
+    } else {
+        parameters.altPermission = "PARTYMGR_PCM"
+        result = run service: "basePermissionCheck", with: parameters
+    }
+    return result
+}
+
+//Accept/Decline PartyInvitation Permission Checks
+/**
+ * Accept and Decline PartyInvitation Permission Logic
+ */
+def accAndDecPartyInvitationPermissionCheck() {
+    Map result = success()
+    Boolean hasPermission = false
+    if (security.hasEntityPermission("PARTYMGR_UPDATE", "_UPDATE", parameters.userLogin)) {
+        hasPermission = true
+        result.hasPermission = hasPermission
+    }
+    if (!hasPermission) {
+        GenericValue partyInvitation = from("PartyInvitation").where(parameters).queryOne()
+        if (!partyInvitation?.partyId) {
+            if (!partyInvitation?.emailAddress) {
+                return error(UtilProperties.getMessage("PartyUiLabels",
+                        "PartyInvitationNotValidError", parameters.locale))
+            } else {
+                Map serviceResult = run service: "findPartyFromEmailAddress", with: [address: partyInvitation.emailAddress]
+                String partyId = serviceResult.partyId
+                if (partyId && partyId == userLogin.partyId) {
+                    hasPermission = true
+                    result.hasPermission = hasPermission
+                } else {
+                    return error(UtilProperties.getMessage("PartyUiLabels",
+                            "PartyInvitationNotValidError", parameters.locale))
+                }
+            }
+        } else {
+            if (partyInvitation.partyId == userLogin.partyId) {
+                hasPermission = true
+                result.hasPermission = hasPermission
+            }
+        }
+    }
+    if (!hasPermission) {
+        String failMessage = UtilProperties.getMessage("PartyUiLabels", "PartyInvitationAccAndDecPermissionError", parameters.locale)
+        logWarning(failMessage)
+        result.failMessage = failMessage
+        result.hasPermission = hasPermission
+    }
+    return result
+}
+
+//Cancel PartyInvitation Permission Checks
+/**
+ * Cancel PartyInvitation Permission Logic
+ */
+def cancelPartyInvitationPermissionCheck() {
+    Map result = success()
+    Boolean hasPermission = false
+    if (security.hasEntityPermission("PARTYMGR_UPDATE", "_UPDATE", parameters.userLogin)) {
+        hasPermission = true
+        result.hasPermission = hasPermission
+    }
+    if (!hasPermission) {
+        GenericValue partyInvitation = from("PartyInvitation").where(parameters).queryOne()
+        if (partyInvitation?.partyIdFrom
+                && partyInvitation.partyIdFrom == userLogin.partyId) {
+            hasPermission = true
+            result.hasPermission = hasPermission
+        }
+        if (!hasPermission) {
+            if (!partyInvitation?.partyId) {
+                if (!partyInvitation?.emailAddress) {
+                    String errorMessage = UtilProperties.getMessage("PartyUiLabels", "PartyInvitationNotValidError", parameters.locale)
+                    logError(errorMessage)
+                    return error(errorMessage)
+                } else {
+                    Map findPartyCtx = [address: partyInvitation.emailAddress]
+                    Map serviceResult = run service: "findPartyFromEmailAddress", with: findPartyCtx
+                    String partyId = serviceResult.partyId
+                    if (partyId) {
+                        if (partyId == userLogin.partyId) {
+                            hasPermission = true
+                            result.hasPermission = hasPermission
+                        }
+                    } else {
+                        String errorMessage = UtilProperties.getMessage("PartyUiLabels", "PartyInvitationNotValidError", parameters.locale)
+                        logError(errorMessage)
+                        return error(errorMessage)
+                    }
+                }
+            } else {
+                if (partyInvitation?.partyId == userLogin.partyId) {
+                    hasPermission = true
+                    result.hasPermission = hasPermission
+                }
+            }
+        }
+    }
+    if (!hasPermission) {
+        String failMessage = UtilProperties.getMessage("PartyUiLabels", "PartyInvitationCancelPermissionError", parameters.locale)
+        logWarning(failMessage)
+        result.failMessage = failMessage
+        result.hasPermission = hasPermission
+    }
+    return result
+}
+
+//Returns hasPermission=true if userLogin partyId equals partyIdFrom parameter OR
+//       partyIdTo parameter OR user has one of the base PARTYMGR or PARTYMGR_CME CRUD+ADMIN permissions
+/**
+ * Communication Event permission logic
+ */
+def partyCommunicationEventPermissionCheck() {
+    Map result = success()
+    if (parameters.communicationEventTypeId == "EMAIL_COMMUNICATION" && parameters.mainAction == "CREATE") {
+        parameters.altPermission = "PARTYMGR_CME-EMAIL"
+    } else if (parameters.communicationEventTypeId == "COMMENT_NOTE" && parameters.mainAction == "CREATE") {
+        parameters.altPermission = "PARTYMGR_CME-NOTE"
+    } else if (parameters.partyIdFrom != userLogin.partyId
+            && parameters.partyIdTo != userLogin.partyId
+            && parameters.partyId != userLogin.partyId) { // <- update role
+        parameters.altPermission = "PARTYMGR_CME"
+    } else {
+        result.hasPermission = true
+    }
+    if (!result.hasPermission) {
+        result = run service: "basePermissionCheck", with: parameters
+    }
+    return result
+}
\ No newline at end of file
diff --git a/applications/party/minilang/party/PartyPermissionServices.xml b/applications/party/minilang/party/PartyPermissionServices.xml
deleted file mode 100644
index a11321d..0000000
--- a/applications/party/minilang/party/PartyPermissionServices.xml
+++ /dev/null
@@ -1,284 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-
-<simple-methods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-        xmlns="http://ofbiz.apache.org/Simple-Method" xsi:schemaLocation="http://ofbiz.apache.org/Simple-Method http://ofbiz.apache.org/dtds/simple-methods.xsd">
-
-    <!-- ============== Basic Permission Checking ============= -->
-
-    <!-- Returns hasPermission=true if user has one of the base PARTYMGR CRUD+ADMIN permissions -->
-    <simple-method method-name="basePermissionCheck" short-description="Party Manager base permission logic">
-        <set field="primaryPermission" value="PARTYMGR"/>
-        <call-simple-method method-name="genericBasePermissionCheck" xml-resource="component://common/minilang/permission/CommonPermissionServices.xml"/>
-    </simple-method>
-
-    <!-- Returns hasPermission=true if userLogin partyId equals partyId parameter -->
-    <simple-method method-name="partyIdPermissionCheck" short-description="Party ID Permission Check">
-        <if-empty field="partyId">
-            <set field="partyId" from-field="parameters.partyId"/>
-        </if-empty>
-        <if>
-            <condition>
-                <and>
-                    <not><if-empty field="partyId"/></not>
-                    <not><if-empty field="userLogin.partyId"/></not>
-                    <if-compare-field field="partyId" to-field="userLogin.partyId" operator="equals"/>
-                </and>
-            </condition>
-            <then>
-                <set field="hasPermission" type="Boolean" value="true"/>
-            </then>
-            <else>
-                <set field="resourceDescription" from-field="parameters.resourceDescription"/>
-                <if-empty field="resourceDescription">
-                    <property-to-field resource="CommonUiLabels" property="CommonPermissionThisOperation" field="resourceDescription"/>
-                </if-empty>
-                <property-to-field resource="PartyUiLabels" property="PartyPermissionErrorPartyId" field="failMessage"/>
-                <set field="hasPermission" type="Boolean" value="false"/>
-                <field-to-result field="failMessage"/>
-            </else>
-        </if>
-        <field-to-result field="hasPermission"/>
-    </simple-method>
-
-    <!-- Returns hasPermission=true if userLogin party equals partyId parameter OR
-        user has one of the base PARTYMGR CRUD+ADMIN permissions -->
-    <simple-method method-name="basePlusPartyIdPermissionCheck" short-description="Base Permission Plus Party ID Permission Check">
-        <call-simple-method method-name="basePermissionCheck"/>
-        <if-compare field="hasPermission" operator="not-equals" value="true">
-            <call-simple-method method-name="partyIdPermissionCheck"/>
-        </if-compare>
-    </simple-method>
-
-    <!-- ============== Additional Permission Checking ============= -->
-
-    <!-- Returns hasPermission=true if userLogin partyId equals partyId parameter OR
-         user has one of the base PARTYMGR or PARTYMGR_STS CRUD+ADMIN permissions -->
-    <simple-method method-name="partyStatusPermissionCheck" short-description="Party status permission logic">
-        <set field="hasPermission" type="Boolean" value="false"/>
-        <if-not-empty field="parameters.partyId">
-            <if-compare-field field="parameters.partyId" to-field="userLogin.partyId" operator="equals">
-                <set field="hasPermission" type="Boolean" value="true"/>
-                <field-to-result field="hasPermission"/>
-            </if-compare-field>
-        </if-not-empty>
-        <if-compare field="hasPermission" operator="not-equals" value="true">
-            <set field="altPermission" value="PARTYMGR_STS"/>
-            <call-simple-method method-name="basePermissionCheck"/>
-        </if-compare>
-    </simple-method>
-
-    <!-- Returns hasPermission=true if userLogin partyId equals partyId parameter OR
-         user has one of the base PARTYMGR or PARTYMGR_GRP CRUD+ADMIN permissions -->
-    <simple-method method-name="partyGroupPermissionCheck" short-description="Party group permission logic">
-        <set field="altPermission" value="PARTYMGR_GRP"/>
-        <call-simple-method method-name="basePlusPartyIdPermissionCheck"/>
-    </simple-method>
-
-    <!-- Returns hasPermission=true if user has one of the base PARTYMGR or PARTYMGR_SRC CRUD+ADMIN permissions -->
-    <simple-method method-name="partyDatasourcePermissionCheck" short-description="Party datasource permission logic">
-        <set field="altPermission" value="PARTYMGR_SRC"/>
-        <call-simple-method method-name="basePermissionCheck"/>
-    </simple-method>
-
-    <!-- Returns hasPermission=true if user has one of the base PARTYMGR or PARTYMGR_ROLE CRUD+ADMIN permissions -->
-    <simple-method method-name="partyRolePermissionCheck" short-description="Party role permission logic">
-        <set field="altPermission" value="PARTYMGR_ROLE"/>
-        <call-simple-method method-name="basePlusPartyIdPermissionCheck"/>
-    </simple-method>
-
-    <!-- Returns hasPermission=true if user has one of the base PARTYMGR or PARTYMGR_REL CRUD+ADMIN permissions -->
-    <simple-method method-name="partyRelationshipPermissionCheck" short-description="Party relationship permission logic">
-        <if-empty field="parameters.partyIdFrom">
-            <set field="parameters.partyIdFrom" from-field="userLogin.partyId"/>
-            <set field="hasPermission" type="Boolean" value="true"/>
-            <field-to-result field="hasPermission"/>
-            <else>
-                <set field="altPermission" value="PARTYMGR_REL"/>
-                <call-simple-method method-name="basePermissionCheck"/>
-            </else>
-        </if-empty>
-    </simple-method>
-
-    <!-- Returns hasPermission=true if userLogin partyId equals partyId parameter OR
-         user has one of the base PARTYMGR or PARTYMGR_PCM CRUD+ADMIN permissions -->
-    <simple-method method-name="partyContactMechPermissionCheck" short-description="Party contact mech permission logic">
-        <if-empty field="parameters.partyId">
-            <set field="parameters.partyId" from-field="userLogin.partyId"/>
-        </if-empty>
-        <if-compare-field to-field="userLogin.partyId" field="parameters.partyId" operator="equals">
-            <set field="hasPermission" type="Boolean" value="true"/>
-            <field-to-result field="hasPermission"/>
-
-            <else>
-                <set field="altPermission" value="PARTYMGR_PCM"/>
-                <call-simple-method method-name="basePermissionCheck"/>
-            </else>
-        </if-compare-field>
-    </simple-method>
-
-    <!-- Accept/Decline/Cancel PartyInvitation Permission Checks -->
-    <simple-method method-name="accAndDecPartyInvitationPermissionCheck" short-description="Accept and Decline PartyInvitation Permission Logic">
-        <set field="hasPermission" type="Boolean" value="false"/>
-        <if-has-permission permission="PARTYMGR_UPDATE" action="_UPDATE">
-            <set field="hasPermission" type="Boolean" value="true"/>
-            <field-to-result field="hasPermission"/>
-        </if-has-permission>
-        <if-compare field="hasPermission" operator="not-equals" value="true">
-            <entity-one entity-name="PartyInvitation" value-field="partyInvitation"/>
-            <if-empty field="partyInvitation.partyId">
-                <if-empty field="partyInvitation.emailAddress">
-                    <add-error>
-                        <fail-property resource="PartyUiLabels" property="PartyInvitationNotValidError"/>
-                    </add-error>
-                <else>
-                    <set field="findPartyCtx.address" from-field="partyInvitation.emailAddress"/>
-                    <call-service service-name="findPartyFromEmailAddress" in-map-name="findPartyCtx">
-                        <result-to-field result-name="partyId" field="partyId"/>
-                    </call-service>
-                    <if-not-empty field="partyId">
-                        <if-compare-field field="partyId" to-field="userLogin.partyId" operator="equals">
-                            <set field="hasPermission" type="Boolean" value="true"/>
-                            <field-to-result field="hasPermission"/>
-                        </if-compare-field>
-                    <else>
-                        <add-error>
-                            <fail-property resource="PartyUiLabels" property="PartyInvitationNotValidError"/>
-                        </add-error>
-                    </else>
-                    </if-not-empty>
-                </else>
-                </if-empty>
-            <else>
-                <if-compare-field field="partyInvitation.partyId" to-field="userLogin.partyId" operator="equals">
-                    <set field="hasPermission" type="Boolean" value="true"/>
-                    <field-to-result field="hasPermission"/>
-                </if-compare-field>
-            </else>
-            </if-empty>
-            <check-errors/>
-        </if-compare>
-        <if-compare field="hasPermission" operator="not-equals" value="true">
-            <property-to-field property="PartyInvitationAccAndDecPermissionError" field="failMessage" resource="PartyUiLabels"/>
-            <field-to-result field="hasPermission"/>
-            <field-to-result field="failMessage"/>
-        </if-compare>
-    </simple-method>
-    <simple-method method-name="cancelPartyInvitationPermissionCheck" short-description="Cancel PartyInvitation Permission Logic">
-        <set field="hasPermission" type="Boolean" value="false"/>
-        <if-has-permission permission="PARTYMGR_UPDATE" action="_UPDATE">
-            <set field="hasPermission" type="Boolean" value="true"/>
-            <field-to-result field="hasPermission"/>
-        </if-has-permission>
-        <if-compare field="hasPermission" operator="not-equals" value="true">
-            <entity-one entity-name="PartyInvitation" value-field="partyInvitation"/>
-            <if-not-empty field="partyInvitation.partyIdFrom">
-                <if-compare-field field="partyInvitation.partyIdFrom" to-field="userLogin.partyId" operator="equals">
-                    <set field="hasPermission" type="Boolean" value="true"/>
-                    <field-to-result field="hasPermission"/>
-                </if-compare-field>
-            </if-not-empty>
-            <if-compare field="hasPermission" operator="not-equals" value="true">
-                <if-empty field="partyInvitation.partyId">
-                    <if-empty field="partyInvitation.emailAddress">
-                        <add-error>
-                            <fail-property resource="PartyUiLabels" property="PartyInvitationNotValidError"/>
-                        </add-error>
-                    <else>
-                        <set field="findPartyCtx.address" from-field="partyInvitation.emailAddress"/>
-                        <call-service service-name="findPartyFromEmailAddress" in-map-name="findPartyCtx">
-                            <result-to-field result-name="partyId" field="partyId"/>
-                        </call-service>
-                        <if-not-empty field="partyId">
-                            <if-compare-field field="partyId" to-field="userLogin.partyId" operator="equals">
-                                <set field="hasPermission" type="Boolean" value="true"/>
-                                <field-to-result field="hasPermission"/>
-                            </if-compare-field>
-                        <else>
-                            <add-error>
-                                <fail-property resource="PartyUiLabels" property="PartyInvitationNotValidError"/>
-                            </add-error>
-                        </else>
-                        </if-not-empty>
-                    </else>
-                    </if-empty>
-                <else>
-                    <if-compare-field field="partyInvitation.partyId" to-field="userLogin.partyId" operator="equals">
-                        <set field="hasPermission" type="Boolean" value="true"/>
-                        <field-to-result field="hasPermission"/>
-                    </if-compare-field>
-                </else>
-                </if-empty>
-                <check-errors/>
-            </if-compare>
-        </if-compare>
-        <if-compare field="hasPermission" operator="not-equals" value="true">
-            <property-to-field property="PartyInvitationCancelPermissionError" field="failMessage" resource="PartyUiLabels"/>
-            <field-to-result field="hasPermission"/>
-            <field-to-result field="failMessage"/>
-        </if-compare>
-    </simple-method>
-
-    <!-- Returns hasPermission=true if userLogin partyId equals partyIdFrom parameter OR
-         partyIdTo parameter OR user has one of the base PARTYMGR or PARTYMGR_CME CRUD+ADMIN permissions -->
-    <simple-method method-name="partyCommunicationEventPermissionCheck" short-description="Communication Event permission logic">
-        <if>
-            <condition>
-                <and>
-                    <if-compare operator="equals" value="EMAIL_COMMUNICATION" field="parameters.communicationEventTypeId"/>
-                    <if-compare operator="equals" value="CREATE" field="action"/>
-                </and>
-            </condition>
-            <then>
-                <set field="altPermission" value="PARTYMGR_CME-EMAIL"/>
-                <call-simple-method method-name="basePermissionCheck"/>
-            </then>
-            <else-if>
-                <condition>
-                    <and>
-                        <if-compare operator="equals" value="COMMENT_NOTE" field="parameters.communicationEventTypeId"/>
-                        <if-compare operator="equals" value="CREATE" field="action"/>
-                    </and>
-                </condition>
-                <then>
-                    <set field="altPermission" value="PARTYMGR_CME-NOTE"/>
-                    <call-simple-method method-name="basePermissionCheck"/>
-                </then>
-            </else-if>
-            <else-if>
-                <condition>
-                    <and>
-                        <if-compare-field field="parameters.partyIdFrom" to-field="userLogin.partyId" operator="not-equals"/>
-                        <if-compare-field field="parameters.partyIdTo" to-field="userLogin.partyId" operator="not-equals"/>
-                        <if-compare-field field="parameters.partyId" to-field="userLogin.partyId" operator="not-equals"/><!-- update role -->
-                    </and>
-                </condition>
-                <then>
-                    <set field="altPermission" value="PARTYMGR_CME"/>
-                    <call-simple-method method-name="basePermissionCheck"/>
-                </then>
-            </else-if>
-            <else>
-                <set field="hasPermission" type="Boolean" value="true"/>
-                <field-to-result field="hasPermission"/>
-            </else>
-        </if>
-    </simple-method>
-</simple-methods>
diff --git a/applications/party/servicedef/services.xml b/applications/party/servicedef/services.xml
index 00b7109..b26dcfc 100644
--- a/applications/party/servicedef/services.xml
+++ b/applications/party/servicedef/services.xml
@@ -1102,16 +1102,23 @@ under the License.
     </service>
 
     <!-- Permission checking services-->
-    <service name="partyBasePermissionCheck" engine="simple"
-            location="component://party/minilang/party/PartyPermissionServices.xml" invoke="basePermissionCheck">
+    <service name="partyBasePermissionCheck" engine="groovy"
+            location="component://party/groovyScripts/party/PartyPermissionServices.groovy" invoke="basePermissionCheck">
         <description>
             Performs a basic Party Manager security check. The user must have one of the base PARTYMGR
             CRUD+ADMIN permissions.
         </description>
         <implements service="permissionInterface"/>
     </service>
-    <service name="partyIdPermissionCheck" engine="simple"
-            location="component://party/minilang/party/PartyPermissionServices.xml" invoke="basePlusPartyIdPermissionCheck">
+    <service name="basePermissionCheck" engine="groovy" 
+            location="component://party/groovyScripts/party/PartyPermissionServices.groovy" invoke="basePermissionCheck">
+        <description>
+            Performs a basic security check. The user must have the base PARTYMGR  permission.
+        </description>
+        <implements service="permissionInterface"/>
+    </service>
+    <service name="partyIdPermissionCheck" engine="groovy"
+            location="component://party/groovyScripts/party/PartyPermissionServices.groovy" invoke="basePlusPartyIdPermissionCheck">
         <description>
             Performs a party ID security check. The userLogin partyId must equal
             the partyId parameter, or the logged-in user must have the correct permission
@@ -1120,8 +1127,8 @@ under the License.
         <implements service="permissionInterface"/>
         <attribute name="partyId" type="String" mode="INOUT" optional="true"/>
     </service>
-    <service name="partyStatusPermissionCheck" engine="simple"
-            location="component://party/minilang/party/PartyPermissionServices.xml" invoke="partyStatusPermissionCheck">
+    <service name="partyStatusPermissionCheck" engine="groovy"
+            location="component://party/groovyScripts/party/PartyPermissionServices.groovy" invoke="partyStatusPermissionCheck">
         <description>
             Performs a party status security check. The userLogin partyId must equal the partyId parameter OR
             the user must have one of the base PARTYMGR or PARTYMGR_STS CRUD+ADMIN permissions.
@@ -1129,8 +1136,8 @@ under the License.
         <implements service="permissionInterface"/>
         <attribute name="partyId" type="String" mode="IN" optional="true"/>
     </service>
-    <service name="partyGroupPermissionCheck" engine="simple"
-            location="component://party/minilang/party/PartyPermissionServices.xml" invoke="partyGroupPermissionCheck">
+    <service name="partyGroupPermissionCheck" engine="groovy"
+            location="component://party/groovyScripts/party/PartyPermissionServices.groovy" invoke="partyGroupPermissionCheck">
         <description>
             Performs a party group security check. The userLogin partyId must equal the partyId parameter OR
             the user has one of the base PARTYMGR or PARTYMGR_GRP CRUD+ADMIN permissions.
@@ -1138,16 +1145,16 @@ under the License.
         <implements service="permissionInterface"/>
         <attribute name="partyId" type="String" mode="INOUT" optional="true"/>
     </service>
-    <service name="partyDatasourcePermissionCheck" engine="simple"
-            location="component://party/minilang/party/PartyPermissionServices.xml" invoke="partyDatasourcePermissionCheck">
+    <service name="partyDatasourcePermissionCheck" engine="groovy"
+            location="component://party/groovyScripts/party/PartyPermissionServices.groovy" invoke="partyDatasourcePermissionCheck">
         <description>
             Performs a party datasource security check. The user must have one of the base PARTYMGR or
             PARTYMGR_SRC CRUD+ADMIN permissions.
         </description>
         <implements service="permissionInterface"/>
     </service>
-    <service name="partyRolePermissionCheck" engine="simple"
-            location="component://party/minilang/party/PartyPermissionServices.xml" invoke="partyRolePermissionCheck">
+    <service name="partyRolePermissionCheck" engine="groovy"
+            location="component://party/groovyScripts/party/PartyPermissionServices.groovy" invoke="partyRolePermissionCheck">
         <description>
             Performs a party role security check. The user must have one of the base PARTYMGR or
             PARTYMGR_ROLE CRUD+ADMIN permissions.
@@ -1155,8 +1162,8 @@ under the License.
         <implements service="permissionInterface"/>
         <attribute name="partyId" type="String" mode="INOUT" optional="true"/>
     </service>
-    <service name="partyRelationshipPermissionCheck" engine="simple"
-            location="component://party/minilang/party/PartyPermissionServices.xml" invoke="partyRelationshipPermissionCheck">
+    <service name="partyRelationshipPermissionCheck" engine="groovy"
+            location="component://party/groovyScripts/party/PartyPermissionServices.groovy" invoke="partyRelationshipPermissionCheck">
         <description>
             Performs a party relationship security check. The user must have one of the base PARTYMGR or
             PARTYMGR_REL CRUD+ADMIN permissions.
@@ -1164,8 +1171,8 @@ under the License.
         <implements service="permissionInterface"/>
         <attribute name="partyIdFrom" type="String" mode="IN" optional="true"/>
     </service>
-    <service name="partyContactMechPermissionCheck" engine="simple"
-            location="component://party/minilang/party/PartyPermissionServices.xml" invoke="partyContactMechPermissionCheck">
+    <service name="partyContactMechPermissionCheck" engine="groovy"
+            location="component://party/groovyScripts/party/PartyPermissionServices.groovy" invoke="partyContactMechPermissionCheck">
         <description>
             Performs a party contact mech security check. The userLogin partyId must equal the partyId parameter OR
             the user must have one of the base PARTYMGR or PARTYMGR_PCM CRUD+ADMIN permissions.
@@ -1173,8 +1180,8 @@ under the License.
         <implements service="permissionInterface"/>
         <attribute name="partyId" type="String" mode="IN" optional="true"/>
     </service>
-    <service name="accAndDecPartyInvitationPermissionCheck" engine="simple"
-            location="component://party/minilang/party/PartyPermissionServices.xml" invoke="accAndDecPartyInvitationPermissionCheck">
+    <service name="accAndDecPartyInvitationPermissionCheck" engine="groovy"
+            location="component://party/groovyScripts/party/PartyPermissionServices.groovy" invoke="accAndDecPartyInvitationPermissionCheck">
         <description>
             Performs accept and decline PartyInvitation security check. The userLogin partyId must equal the
             partyIdTo in PartyInvitation OR partyId fetched using emailAdress in PartyInvitation.
@@ -1183,8 +1190,8 @@ under the License.
         <implements service="permissionInterface"/>
         <attribute name="partyInvitationId" type="String" mode="IN" optional="false"/>
     </service>
-    <service name="cancelPartyInvitationPermissionCheck" engine="simple"
-            location="component://party/minilang/party/PartyPermissionServices.xml" invoke="cancelPartyInvitationPermissionCheck">
+    <service name="cancelPartyInvitationPermissionCheck" engine="groovy"
+            location="component://party/groovyScripts/party/PartyPermissionServices.groovy" invoke="cancelPartyInvitationPermissionCheck">
         <description>
             Performs cancel PartyInvitation security check. The userLogin partyId must equal the
             partyId/partyIdFrom in PartyInvitation OR partyId fetched using emailAdress in PartyInvitation.
@@ -1193,8 +1200,8 @@ under the License.
         <implements service="permissionInterface"/>
         <attribute name="partyInvitationId" type="String" mode="IN" optional="false"/>
     </service>
-    <service name="partyCommunicationEventPermissionCheck" engine="simple"
-            location="component://party/minilang/party/PartyPermissionServices.xml" invoke="partyCommunicationEventPermissionCheck">
+    <service name="partyCommunicationEventPermissionCheck" engine="groovy"
+            location="component://party/groovyScripts/party/PartyPermissionServices.groovy" invoke="partyCommunicationEventPermissionCheck">
         <description>Party CommunicationEvents Permission Checking Logic</description>
         <implements service="permissionInterface"/>
         <attribute name="partyIdFrom" type="String" mode="IN" optional="true"/>


[ofbiz-framework] 10/26: Improved: style alignment properties

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 48e81c48dba67cd4c0814327ddc4242fe3cb4df1
Author: Pierre Smits <pi...@apache.org>
AuthorDate: Sun Mar 15 09:45:32 2020 +0100

    Improved: style alignment properties
    
    (OFBIZ-11458)
    
    Adding alignment properties (creating consistency across themes.
---
 themes/bluelight/webapp/bluelight/style.css        | 24 ++++++++++++++-----
 themes/flatgrey/webapp/flatgrey/style.css          | 28 ++++++++++++++++------
 themes/flatgrey/webapp/flatgrey/stylertl.css       | 24 ++++++++++++++++---
 themes/rainbowstone/webapp/rainbowstone/style.css  | 27 ++++++++++++++++-----
 .../rainbowstone/webapp/rainbowstone/stylertl.css  | 23 ++++++++++++++++--
 themes/tomahawk/webapp/tomahawk/css/style.css      | 24 ++++++++++++++-----
 themes/tomahawk/webapp/tomahawk/css/stylertl.css   | 23 ++++++++++++++++--
 7 files changed, 141 insertions(+), 32 deletions(-)

diff --git a/themes/bluelight/webapp/bluelight/style.css b/themes/bluelight/webapp/bluelight/style.css
index 4de925c..7fdccf6 100644
--- a/themes/bluelight/webapp/bluelight/style.css
+++ b/themes/bluelight/webapp/bluelight/style.css
@@ -904,22 +904,34 @@ in contained elements. */
 /* ================================== */
 /* ===== Used to align elements ===== */
 /* ================================== */
+.align-bottom {
+    vertical-align: bottom;;
+}
+.align-center {
+    text-align: center;
+}
 .align-float {
     float: right;
 }
-
+.align-justify {
+    text-align: justify;
+}
+.align-left {
+    text-align: left;
+}
+.align-middle {
+    vertical-align: bottom;;
+}
+.align-right {
+    text-align: right;
+}
 .align-text {
     text-align: right;
 }
-
 .align-top {
     vertical-align: top;
 }
 
-.centered {
-    text-align: center;
-}
-
 .page-container {
     background-color: #B8DFFC;
 }
diff --git a/themes/flatgrey/webapp/flatgrey/style.css b/themes/flatgrey/webapp/flatgrey/style.css
index a0dd301..0b502f8 100644
--- a/themes/flatgrey/webapp/flatgrey/style.css
+++ b/themes/flatgrey/webapp/flatgrey/style.css
@@ -223,22 +223,36 @@ th, th a {
     /*background: url("images/big-fade.png") repeat-x 0 90px transparent;*/
 }
 
+/* ================================== */
+/* ===== Used to align elements ===== */
+/* ================================== */
+.align-bottom {
+    vertical-align: bottom;;
+}
+.align-center {
+    text-align: center;
+}
 .align-float {
     float: right;
 }
-
+.align-justify {
+    text-align: justify;
+}
+.align-left {
+    text-align: left;
+}
+.align-middle {
+    vertical-align: bottom;;
+}
+.align-right {
+    text-align: right;
+}
 .align-text {
     text-align: right;
 }
-
 .align-top {
     vertical-align: top;
 }
-
-.centered {
-    text-align: center;
-}
-
 .page-title {
     color: #557996;
     margin-bottom: 0.5em;
diff --git a/themes/flatgrey/webapp/flatgrey/stylertl.css b/themes/flatgrey/webapp/flatgrey/stylertl.css
index 85796d3..2deded7 100644
--- a/themes/flatgrey/webapp/flatgrey/stylertl.css
+++ b/themes/flatgrey/webapp/flatgrey/stylertl.css
@@ -169,15 +169,33 @@ DIV.column-left-wide {
 /* ================================== */
 /* ===== Used to align elements ===== */
 /* ================================== */
-
+.align-bottom {
+    vertical-align: bottom;;
+}
+.align-center {
+    text-align: center;
+}
 .align-float {
     float: left;
 }
-
+.align-justify {
+    text-align: justify;
+}
+.align-left {
+    text-align: left;
+}
+.align-middle {
+    vertical-align: bottom;;
+}
+.align-right {
+    text-align: right;
+}
 .align-text {
     text-align: left;
 }
-
+.align-top {
+    vertical-align: top;
+}
 /* ==================================== */
 /* ===== Masthead (Header) Styles ===== */
 /* ==================================== */
diff --git a/themes/rainbowstone/webapp/rainbowstone/style.css b/themes/rainbowstone/webapp/rainbowstone/style.css
index a8ad664..09cc770 100644
--- a/themes/rainbowstone/webapp/rainbowstone/style.css
+++ b/themes/rainbowstone/webapp/rainbowstone/style.css
@@ -225,22 +225,37 @@ th, th a {
     /*background: url("images/big-fade.png") repeat-x 0 90px transparent;*/
 }
 
+/* ================================== */
+/* ===== Used to align elements ===== */
+/* ================================== */
+.align-bottom {
+    vertical-align: bottom;;
+}
+.align-center {
+    text-align: center;
+}
 .align-float {
     float: right;
 }
-
+.align-justify {
+    text-align: justify;
+}
+.align-left {
+    text-align: left;
+}
+.align-middle {
+    vertical-align: bottom;;
+}
+.align-right {
+    text-align: right;
+}
 .align-text {
     text-align: right;
 }
-
 .align-top {
     vertical-align: top;
 }
 
-.centered {
-    text-align: center;
-}
-
 .page-title {
     color: #557996;
     margin-bottom: 0.5em;
diff --git a/themes/rainbowstone/webapp/rainbowstone/stylertl.css b/themes/rainbowstone/webapp/rainbowstone/stylertl.css
index 85796d3..8d36745 100644
--- a/themes/rainbowstone/webapp/rainbowstone/stylertl.css
+++ b/themes/rainbowstone/webapp/rainbowstone/stylertl.css
@@ -169,14 +169,33 @@ DIV.column-left-wide {
 /* ================================== */
 /* ===== Used to align elements ===== */
 /* ================================== */
-
+.align-bottom {
+    vertical-align: bottom;;
+}
+.align-center {
+    text-align: center;
+}
 .align-float {
     float: left;
 }
-
+.align-justify {
+    text-align: justify;
+}
+.align-left {
+    text-align: left;
+}
+.align-middle {
+    vertical-align: bottom;;
+}
+.align-right {
+    text-align: right;
+}
 .align-text {
     text-align: left;
 }
+.align-top {
+    vertical-align: top;
+}
 
 /* ==================================== */
 /* ===== Masthead (Header) Styles ===== */
diff --git a/themes/tomahawk/webapp/tomahawk/css/style.css b/themes/tomahawk/webapp/tomahawk/css/style.css
index e5d6cd8..0b38c79 100644
--- a/themes/tomahawk/webapp/tomahawk/css/style.css
+++ b/themes/tomahawk/webapp/tomahawk/css/style.css
@@ -933,22 +933,34 @@ in contained elements. */
 /* ================================== */
 /* ===== Used to align elements ===== */
 /* ================================== */
+.align-bottom {
+    vertical-align: bottom;;
+}
+.align-center {
+    text-align: center;
+}
 .align-float {
     float: right;
 }
-
+.align-justify {
+    text-align: justify;
+}
+.align-left {
+    text-align: left;
+}
+.align-middle {
+    vertical-align: bottom;;
+}
+.align-right {
+    text-align: right;
+}
 .align-text {
     text-align: right;
 }
-
 .align-top {
     vertical-align: top;
 }
 
-.centered {
-    text-align: center;
-}
-
 /* ==================================== */
 /* ===== Masthead (Header) Styles ===== */
 /* ==================================== */
diff --git a/themes/tomahawk/webapp/tomahawk/css/stylertl.css b/themes/tomahawk/webapp/tomahawk/css/stylertl.css
index 5016d2d..82d773e 100644
--- a/themes/tomahawk/webapp/tomahawk/css/stylertl.css
+++ b/themes/tomahawk/webapp/tomahawk/css/stylertl.css
@@ -169,14 +169,33 @@ DIV.column-left-wide {
 /* ================================== */
 /* ===== Used to align elements ===== */
 /* ================================== */
-
+.align-bottom {
+    vertical-align: bottom;;
+}
+.align-center {
+    text-align: center;
+}
 .align-float {
     float: left;
 }
-
+.align-justify {
+    text-align: justify;
+}
+.align-left {
+    text-align: left;
+}
+.align-middle {
+    vertical-align: bottom;;
+}
+.align-right {
+    text-align: right;
+}
 .align-text {
     text-align: left;
 }
+.align-top {
+    vertical-align: top;
+}
 
 /* ==================================== */
 /* ===== Masthead (Header) Styles ===== */


[ofbiz-framework] 09/26: Fixed: Specified key was too long; max key length is 767 bytes for ProductPromoCodeEmail entity.(OFBIZ-5426) (#44)

Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 4d2e5d3e26dfc5011084f8f34c430a52c9497df1
Author: Pawan Verma <ve...@users.noreply.github.com>
AuthorDate: Mon Mar 23 17:08:58 2020 +0530

    Fixed: Specified key was too long; max key length is 767 bytes for ProductPromoCodeEmail entity.(OFBIZ-5426) (#44)
    
    * Fixed: Specified key was too long; max key length is 767 bytes for ProductPromoCodeEmail entity.
    (OFBIZ-5426)
    
    The problem is in the entity model. An email address should not be used in the primary key - mainly because an email address is case-insensitive. A better design would be to use the email address contact mechanism ID in the primary key.
    
    Done Following:
    1. Changed Entity Name from ProductPromoCodeEmail to ProductPromoCodeContMech
    2. Related Changes for the entity name change
    3. Migration service to migrate old data
    
    Thanks, Leon for the report and Adrian Crum, Jacques Le Roux, Ingo Wolfmayr, Deepak Dixit, Pierre Smits and Gil Portenseigne for the discussion and review.
    
    * Improved: Added new line in service definition file and lincence in MigrationServices file.
    (OFBIZ-5426)
    
    Thanks, Jacopo for the review.
---
 .../datamodel/entitydef/product-entitymodel.xml    | 24 ++++--
 .../catalog/promo/EditProductPromoCode.groovy      |  2 +-
 applications/product/ofbiz-component.xml           |  1 +
 .../product/servicedef/services_migration.xml      | 32 ++++++++
 .../product/servicedef/services_pricepromo.xml     |  8 +-
 .../ofbiz/product/migrate/MigrationServices.java   | 92 ++++++++++++++++++++++
 .../apache/ofbiz/product/promo/PromoServices.java  | 34 +++++++-
 .../template/promo/EditProductPromoCode.ftl        |  5 +-
 .../product/webapp/catalog/WEB-INF/controller.xml  |  2 +-
 .../webtools/groovyScripts/entity/XmlDsDump.groovy |  4 +-
 10 files changed, 186 insertions(+), 18 deletions(-)

diff --git a/applications/datamodel/entitydef/product-entitymodel.xml b/applications/datamodel/entitydef/product-entitymodel.xml
index 2ee09ec..e34749d 100644
--- a/applications/datamodel/entitydef/product-entitymodel.xml
+++ b/applications/datamodel/entitydef/product-entitymodel.xml
@@ -3640,7 +3640,7 @@ under the License.
         <key-map field-name="lastModifiedByUserLogin" rel-field-name="userLoginId"/>
       </relation>
     </entity>
-    <entity entity-name="ProductPromoCodeEmail"
+    <entity entity-name="OldProductPromoCodeEmail" table-name="PRODUCT_PROMO_CODE_EMAIL"
             package-name="org.apache.ofbiz.product.promo"
             title="Product Promotion Email">
       <field name="productPromoCodeId" type="id"></field>
@@ -3651,19 +3651,33 @@ under the License.
         <key-map field-name="productPromoCodeId"/>
       </relation>
     </entity>
+    <entity entity-name="ProdPromoCodeContactMech"
+            package-name="org.apache.ofbiz.product.promo"
+            title="Product Promotion ContactMech">
+        <field name="productPromoCodeId" type="id"></field>
+        <field name="contactMechId" type="id"></field>
+        <prim-key field="productPromoCodeId"/>
+        <prim-key field="contactMechId"/>
+        <relation type="one" fk-name="PROD_PRCDE_PCD" rel-entity-name="ProductPromoCode">
+            <key-map field-name="productPromoCodeId"/>
+        </relation>
+        <relation type="one" fk-name="PROD_PRCDE_CM" rel-entity-name="ContactMech">
+            <key-map field-name="contactMechId"/>
+        </relation>
+    </entity>
     <view-entity entity-name="ProductPromoCodeEmailParty"
             package-name="org.apache.ofbiz.product.promo"
             title="Product Promotion Email and Party View">
-      <member-entity entity-alias="PPCE" entity-name="ProductPromoCodeEmail"/>
+      <member-entity entity-alias="PPCCM" entity-name="ProdPromoCodeContactMech"/>
       <member-entity entity-alias="CM" entity-name="ContactMech"/>
       <member-entity entity-alias="PCM" entity-name="PartyContactMech"/>
-      <alias entity-alias="PPCE" name="productPromoCodeId"/>
+      <alias entity-alias="PPCCM" name="productPromoCodeId"/>
       <alias entity-alias="CM" name="infoString"/>
       <alias entity-alias="PCM" name="partyId"/>
       <alias entity-alias="PCM" name="fromDate"/>
       <alias entity-alias="PCM" name="thruDate"/>
-      <view-link entity-alias="PPCE" rel-entity-alias="CM">
-          <key-map field-name="emailAddress" rel-field-name="infoString"/>
+      <view-link entity-alias="PPCCM" rel-entity-alias="CM">
+          <key-map field-name="contactMechId"/>
       </view-link>
       <view-link entity-alias="CM" rel-entity-alias="PCM">
           <key-map field-name="contactMechId"/>
diff --git a/applications/product/groovyScripts/catalog/promo/EditProductPromoCode.groovy b/applications/product/groovyScripts/catalog/promo/EditProductPromoCode.groovy
index ee9403c..085580a 100644
--- a/applications/product/groovyScripts/catalog/promo/EditProductPromoCode.groovy
+++ b/applications/product/groovyScripts/catalog/promo/EditProductPromoCode.groovy
@@ -38,7 +38,7 @@ if (productPromoId) {
 productPromoCodeEmails = null
 productPromoCodeParties = null
 if (productPromoCode) {
-    productPromoCodeEmails = productPromoCode.getRelated("ProductPromoCodeEmail", null, null, false)
+    productPromoCodeEmails = productPromoCode.getRelated("ProdPromoCodeContactMech", null, null, false)
     productPromoCodeParties = productPromoCode.getRelated("ProductPromoCodeParty", null, null, false)
 }
 
diff --git a/applications/product/ofbiz-component.xml b/applications/product/ofbiz-component.xml
index 9a203d0..1cc86f0 100644
--- a/applications/product/ofbiz-component.xml
+++ b/applications/product/ofbiz-component.xml
@@ -42,6 +42,7 @@ under the License.
     <service-resource type="model" loader="main" location="servicedef/services_feature.xml"/>
     <service-resource type="model" loader="main" location="servicedef/services_inventory.xml"/>
     <service-resource type="model" loader="main" location="servicedef/services_maint.xml"/>
+    <service-resource type="model" loader="main" location="servicedef/services_migration.xml"/>
     <service-resource type="model" loader="main" location="servicedef/services_picklist.xml"/>
     <service-resource type="model" loader="main" location="servicedef/services_price.xml"/>
     <service-resource type="model" loader="main" location="servicedef/services_pricepromo.xml"/>
diff --git a/applications/product/servicedef/services_migration.xml b/applications/product/servicedef/services_migration.xml
new file mode 100644
index 0000000..56255d3
--- /dev/null
+++ b/applications/product/servicedef/services_migration.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<services xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/services.xsd">
+    <description>Product Component Services</description>
+    <vendor>OFBiz</vendor>
+    <version>1.0</version>
+
+    <service name="migrateProductPromoCodeEmail" engine="java"
+             location="org.apache.ofbiz.product.migrate.MigrationServices" invoke="migrateProductPromoCodeEmail" auth="true">
+        <description>Copy the ProductPromoCodeEmail entity to ProductPromoCodeContactMech</description>
+        <permission-service service-name="productPriceGenericPermission" main-action="CREATE"/>
+    </service>
+</services>
diff --git a/applications/product/servicedef/services_pricepromo.xml b/applications/product/servicedef/services_pricepromo.xml
index 86bbdb8..df0ee3d 100644
--- a/applications/product/servicedef/services_pricepromo.xml
+++ b/applications/product/servicedef/services_pricepromo.xml
@@ -212,14 +212,14 @@ under the License.
         <auto-attributes mode="IN" entity-name="ProductPromoCode" include="nonpk" optional="true"/>
     </service>
 
-    <service name="createProductPromoCodeEmail" default-entity-name="ProductPromoCodeEmail" engine="entity-auto" invoke="create" auth="true">
-        <description>Create a ProductPromoCodeEmail</description>
+    <service name="createProductPromoCodeContactMech" default-entity-name="ProdPromoCodeContactMech" engine="entity-auto" invoke="create" auth="true">
+        <description>Create a ProdPromoCodeContactMech</description>
         <permission-service service-name="productPriceGenericPermission" main-action="CREATE"/>
         <auto-attributes include="pk" mode="IN" optional="false"/>
         <auto-attributes include="nonpk" mode="IN" optional="true"/>
     </service>
-    <service name="deleteProductPromoCodeEmail" default-entity-name="ProductPromoCodeEmail" engine="entity-auto" invoke="delete" auth="true">
-        <description>Delete a ProductPromoCodeEmail</description>
+    <service name="deleteProductPromoCodeContactMech" default-entity-name="ProdPromoCodeContactMech" engine="entity-auto" invoke="delete" auth="true">
+        <description>Delete a ProdPromoCodeContactMech</description>
         <permission-service service-name="productPriceGenericPermission" main-action="DELETE"/>
         <auto-attributes include="pk" mode="IN" optional="false"/>
     </service>
diff --git a/applications/product/src/main/java/org/apache/ofbiz/product/migrate/MigrationServices.java b/applications/product/src/main/java/org/apache/ofbiz/product/migrate/MigrationServices.java
new file mode 100644
index 0000000..9a50a9c
--- /dev/null
+++ b/applications/product/src/main/java/org/apache/ofbiz/product/migrate/MigrationServices.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *******************************************************************************/
+package org.apache.ofbiz.product.migrate;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ofbiz.base.util.Debug;
+import org.apache.ofbiz.base.util.UtilValidate;
+import org.apache.ofbiz.entity.Delegator;
+import org.apache.ofbiz.entity.GenericEntityException;
+import org.apache.ofbiz.entity.GenericValue;
+import org.apache.ofbiz.entity.util.EntityListIterator;
+import org.apache.ofbiz.entity.util.EntityQuery;
+import org.apache.ofbiz.service.DispatchContext;
+import org.apache.ofbiz.service.ServiceUtil;
+
+public class MigrationServices {
+    public static final String module = MigrationServices.class.getName();
+
+    public static Map<String, Object> migrateProductPromoCodeEmail(DispatchContext dctx, Map<String, Object> context) {
+        Delegator delegator = dctx.getDelegator();
+        List<Object> errors = new LinkedList<>();
+        EntityQuery eq = EntityQuery.use(delegator).from("OldProductPromoCodeEmail");
+
+        try (EntityListIterator eli = eq.queryIterator()) {
+            GenericValue productPromoCodeEmail = null;
+            while ((productPromoCodeEmail = eli.next()) != null) {
+                String contactMechId;
+
+                String emailAddress = productPromoCodeEmail.getString("emailAddress");
+                if (!UtilValidate.isEmail(emailAddress)) {
+                    Debug.logError(emailAddress + ": is not a valid email address", module);
+                    errors.add(emailAddress + ": is not a valid email address ");
+                    continue;
+                }
+
+                long contactMechs = EntityQuery.use(delegator)
+                        .from("ContactMech")
+                        .where("infoString", emailAddress)
+                        .queryCount();
+                if (contactMechs > 1) {
+                    errors.add(emailAddress + ": Too many contactMechIds found ");
+                    continue;
+                }
+
+                GenericValue contactMech = EntityQuery.use(delegator)
+                        .from("ContactMech")
+                        .where("infoString", emailAddress)
+                        .queryOne();
+                if (contactMech == null) {
+                    //If no contactMech found create new
+                    GenericValue newContactMech = delegator.makeValue("ContactMech");
+                    contactMechId = delegator.getNextSeqId("ContactMech");
+                    newContactMech.set("contactMechId", contactMechId);
+                    newContactMech.set("contactMechTypeId", "EMAIL_ADDRESS");
+                    newContactMech.set("infoString", emailAddress);
+                    delegator.create(newContactMech);
+                } else {
+                    contactMechId = contactMech.getString("contactMechId");
+                }
+
+                GenericValue prodPromoCodeContMech = delegator.makeValue("ProdPromoCodeContactMech");
+                prodPromoCodeContMech.set("productPromoCodeId", productPromoCodeEmail.getString("productPromoCodeId"));
+                prodPromoCodeContMech.set("contactMechId", contactMechId);
+                //createOrStore to avoid duplicate data for same email.
+                delegator.createOrStore(prodPromoCodeContMech);
+            }
+
+        } catch (GenericEntityException e) {
+            Debug.logError(e, module);
+        }
+        return ServiceUtil.returnSuccess("Data has been migrated with following errors: " + errors);
+    }
+}
diff --git a/applications/product/src/main/java/org/apache/ofbiz/product/promo/PromoServices.java b/applications/product/src/main/java/org/apache/ofbiz/product/promo/PromoServices.java
index f162e3b..c601844 100644
--- a/applications/product/src/main/java/org/apache/ofbiz/product/promo/PromoServices.java
+++ b/applications/product/src/main/java/org/apache/ofbiz/product/promo/PromoServices.java
@@ -255,9 +255,37 @@ public class PromoServices {
                 if (line.length() > 0 && !line.startsWith("#")) {
                     if (UtilValidate.isEmail(line)) {
                         // valid email address
-                        Map<String, Object> result = dispatcher.runSync("createProductPromoCodeEmail", UtilMisc.<String, Object>toMap("productPromoCodeId",
-                                productPromoCodeId, "emailAddress", line, "userLogin", userLogin));
-                        if (result != null && ServiceUtil.isError(result)) {
+                        GenericValue contactMech;
+                        String contactMechId;
+                        try {
+                            //check for existing contactMechId
+                            contactMech = EntityQuery.use(dctx.getDelegator()).from("ContactMech")
+                                    .where("infoString", line).queryOne();
+                        } catch (GenericEntityException e) {
+                            Debug.logError(e, module);
+                            errors.add(line + ": Too many contactMechIds found ");
+                            continue;
+                        }
+                        Map<String, Object> result = new HashMap<>();
+                        if (contactMech == null) {
+                            //If no contactMech found create new
+                            result = dispatcher.runSync("createContactMech",
+                                    UtilMisc.toMap("contactMechTypeId", "EMAIL_ADDRESS", "infoString", line,
+                                            "userLogin", userLogin));
+                            if (ServiceUtil.isError(result)) {
+                                errors.add(line + ": " + ServiceUtil.getErrorMessage(result));
+                                continue;
+                            } else {
+                                contactMechId = (String) result.get("contactMechId");
+                            }
+                        } else {
+                            contactMechId = contactMech.getString("contactMechId");
+                        }
+                        result.clear();
+                        result = dispatcher.runSync("createProductPromoCodeContactMech",
+                                UtilMisc.<String, Object>toMap("productPromoCodeId",
+                                productPromoCodeId, "contactMechId", contactMechId, "userLogin", userLogin));
+                        if (ServiceUtil.isError(result)) {
                             errors.add(line + ": " + ServiceUtil.getErrorMessage(result));
                         }
                     } else {
diff --git a/applications/product/template/promo/EditProductPromoCode.ftl b/applications/product/template/promo/EditProductPromoCode.ftl
index ba791c1..40eb6a8 100644
--- a/applications/product/template/promo/EditProductPromoCode.ftl
+++ b/applications/product/template/promo/EditProductPromoCode.ftl
@@ -24,11 +24,12 @@ under the License.
         <div class="screenlet-body">
             <#list productPromoCodeEmails as productPromoCodeEmail>
               <div>
+                <#assign contactMech = EntityQuery.use(delegator).from("ContactMech").where("contactMechId", productPromoCodeEmail.contactMechId).queryOne()!/>
                 <form name="deleteProductPromoCodeEmail_${productPromoCodeEmail_index}" method="post" action="<@o...@ofbizUrl>">
                   <input type="hidden" name="productPromoCodeId" value="${productPromoCodeEmail.productPromoCodeId}"/>                
-                  <input type="hidden" name="emailAddress" value="${productPromoCodeEmail.emailAddress}"/>                
+                  <input type="hidden" name="contactMechId" value="${productPromoCodeEmail.contactMechId}"/>
                   <input type="hidden" name="productPromoId" value="${productPromoId}"/>                
-                  <a href='javascript:document.deleteProductPromoCodeEmail_${productPromoCodeEmail_index}.submit()' class='buttontext'>${uiLabelMap.CommonRemove}</a>&nbsp;${productPromoCodeEmail.emailAddress}
+                  <a href='javascript:document.deleteProductPromoCodeEmail_${productPromoCodeEmail_index}.submit()' class='buttontext'>${uiLabelMap.CommonRemove}</a>&nbsp;${contactMech.infoString!}
                 </form>
               </div>                
             </#list>
diff --git a/applications/product/webapp/catalog/WEB-INF/controller.xml b/applications/product/webapp/catalog/WEB-INF/controller.xml
index 496f99b..5ba2873 100644
--- a/applications/product/webapp/catalog/WEB-INF/controller.xml
+++ b/applications/product/webapp/catalog/WEB-INF/controller.xml
@@ -1965,7 +1965,7 @@ under the License.
     </request-map>
     <request-map uri="deleteProductPromoCodeEmail">
         <security https="true" auth="true"/>
-        <event type="service" path="" invoke="deleteProductPromoCodeEmail"/>
+        <event type="service" path="" invoke="deleteProductPromoCodeContactMech"/>
         <response name="success" type="view" value="EditProductPromoCode"/>
         <response name="error" type="view" value="EditProductPromoCode"/>
     </request-map>
diff --git a/framework/webtools/groovyScripts/entity/XmlDsDump.groovy b/framework/webtools/groovyScripts/entity/XmlDsDump.groovy
index 54844a8..c0a7fa0 100644
--- a/framework/webtools/groovyScripts/entity/XmlDsDump.groovy
+++ b/framework/webtools/groovyScripts/entity/XmlDsDump.groovy
@@ -86,7 +86,7 @@ if ("Product1".equals(preConfiguredSetName)) {
     passedEntityNames.add("ProductFeatureGroup")
     passedEntityNames.add("ProductPriceChange")
     passedEntityNames.add("ProductPromoAction")
-    passedEntityNames.add("ProductPromoCodeEmail")
+    passedEntityNames.add("ProdPromoCodeContactMech")
     passedEntityNames.add("ProductPromoCodeParty")
     passedEntityNames.add("ProductPromoCond")
 } else if ("Product4".equals(preConfiguredSetName)) {
@@ -128,7 +128,7 @@ if ("Product1".equals(preConfiguredSetName)) {
     passedEntityNames.add("ProductPromoProduct")
     passedEntityNames.add("ProductPromoRule")
     passedEntityNames.add("ProductPromoAction")
-    passedEntityNames.add("ProductPromoCodeEmail")
+    passedEntityNames.add("ProdPromoCodeContactMech")
     passedEntityNames.add("ProductPromoCodeParty")
     passedEntityNames.add("ProductPromoCond")