diff --git a/shopify/HELP.adoc b/shopify/HELP.adoc new file mode 100644 index 000000000..c7c07ab54 --- /dev/null +++ b/shopify/HELP.adoc @@ -0,0 +1 @@ +The Shopify Help file template. \ No newline at end of file diff --git a/shopify/README.adoc b/shopify/README.adoc new file mode 100644 index 000000000..1fef6b4d0 --- /dev/null +++ b/shopify/README.adoc @@ -0,0 +1,3 @@ + +The files in this directory are used as templates for the ant create-component target, + +please do not modify them without understanding the effect that it will have on that build target. \ No newline at end of file diff --git a/shopify/config/ShopifyUiLabels.xml b/shopify/config/ShopifyUiLabels.xml new file mode 100644 index 000000000..21272c820 --- /dev/null +++ b/shopify/config/ShopifyUiLabels.xml @@ -0,0 +1,72 @@ + + + + + + Shopify Application + Shopify应用程序 + Shopify應用程式 + + + OFBiz: Shopify + OFBiz: Shopify + + + Part of the Apache OFBiz Family of Open Source Software + Un modulo della famiglia di software open source Apache OFBiz + 开源软件OFBiz的组成部分 + 開源軟體OFBiz的組成部分 + + + You are not allowed to view this page. + 不允许你浏览这个页面。 + 不允許您檢視這個頁面. + + + Shopify Configurations + + + Add Shopify Configuration + + + Shopify Configuration added successfully + + + Required Field is missing : API Url + + + Required Field is missing : Username + + + Required Field is missing : Password + + + Exception in createUpdateShopifyConfiguration + + + Shopify api url is not configured. + + + Shopify api username is not configured. + + + Shopify api password is not configured. + + diff --git a/shopify/data/ShopifyDemoData.xml b/shopify/data/ShopifyDemoData.xml new file mode 100644 index 000000000..ad7d88fdb --- /dev/null +++ b/shopify/data/ShopifyDemoData.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/shopify/data/ShopifySecurityGroupDemoData.xml b/shopify/data/ShopifySecurityGroupDemoData.xml new file mode 100644 index 000000000..ed98da0af --- /dev/null +++ b/shopify/data/ShopifySecurityGroupDemoData.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + diff --git a/shopify/data/ShopifySecurityPermissionSeedData.xml b/shopify/data/ShopifySecurityPermissionSeedData.xml new file mode 100644 index 000000000..47d6aa721 --- /dev/null +++ b/shopify/data/ShopifySecurityPermissionSeedData.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + diff --git a/shopify/data/ShopifyTypeData.xml b/shopify/data/ShopifyTypeData.xml new file mode 100644 index 000000000..b76e67e05 --- /dev/null +++ b/shopify/data/ShopifyTypeData.xml @@ -0,0 +1,23 @@ + + + + + + \ No newline at end of file diff --git a/shopify/data/helpdata/HELP_Shopify.xml b/shopify/data/helpdata/HELP_Shopify.xml new file mode 100644 index 000000000..5502e64bb --- /dev/null +++ b/shopify/data/helpdata/HELP_Shopify.xml @@ -0,0 +1,29 @@ + + + +
+ Shopify Overview + The Shopify Help file template. +
+ diff --git a/shopify/documents/Shopify.xml b/shopify/documents/Shopify.xml new file mode 100644 index 000000000..87812afff --- /dev/null +++ b/shopify/documents/Shopify.xml @@ -0,0 +1,35 @@ + + + + + + <anchor xml:id="Shopify"/>The Shopify Component +
+ Introduction + + +
+ + +
diff --git a/shopify/entitydef/entitymodel.xml b/shopify/entitydef/entitymodel.xml new file mode 100644 index 000000000..77f21fcf5 --- /dev/null +++ b/shopify/entitydef/entitymodel.xml @@ -0,0 +1,31 @@ + + + + + + + + Entity of Shopify Component + None + + + + \ No newline at end of file diff --git a/shopify/ofbiz-component.xml b/shopify/ofbiz-component.xml new file mode 100644 index 000000000..aef00932e --- /dev/null +++ b/shopify/ofbiz-component.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shopify/servicedef/services.xml b/shopify/servicedef/services.xml new file mode 100644 index 000000000..4aa424f9e --- /dev/null +++ b/shopify/servicedef/services.xml @@ -0,0 +1,46 @@ + + + + + Shopify Services + + 1.0 + + + Create Update Shopify Configuration + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/shopify/src/main/java/org/apache/ofbiz/shopify/ShopifyServices.java b/shopify/src/main/java/org/apache/ofbiz/shopify/ShopifyServices.java new file mode 100644 index 000000000..276bcc722 --- /dev/null +++ b/shopify/src/main/java/org/apache/ofbiz/shopify/ShopifyServices.java @@ -0,0 +1,210 @@ +package org.apache.ofbiz.shopify; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.ofbiz.base.lang.JSON; +import org.apache.ofbiz.base.util.*; +import org.apache.ofbiz.entity.Delegator; +import org.apache.ofbiz.entity.GenericEntityException; +import org.apache.ofbiz.entity.GenericValue; +import org.apache.ofbiz.entity.util.EntityQuery; +import org.apache.ofbiz.entity.util.EntityUtilProperties; +import org.apache.ofbiz.service.DispatchContext; +import org.apache.ofbiz.service.LocalDispatcher; +import org.apache.ofbiz.service.ModelService; +import org.apache.ofbiz.service.ServiceUtil; + +import java.io.IOException; +import java.io.InputStream; +import java.util.*; + +public class ShopifyServices { + + public static final String MODULE = ShopifyServices.class.getName(); + public static final String resource = "ShopifyUiLabels"; + + public static Map createUpdateShopifyConfiguration(DispatchContext dctx, Map context) { + Delegator delegator = dctx.getDelegator(); + LocalDispatcher dispatcher = dctx.getDispatcher(); + Locale locale = (Locale) context.get("locale"); + Map result = new HashMap<>(); + String apiUrl = (String) context.get("apiUrl"); + String username = (String) context.get("username"); + String password = (String) context.get("password"); + try { + if (UtilValidate.isNotEmpty(apiUrl)) { + GenericValue apiUrlProperty = EntityQuery.use(delegator).from("SystemProperty").where("systemResourceId", "ShopifyConfig", "systemPropertyId", "shopifyApiUrl").queryOne(); + if (apiUrlProperty == null) { + GenericValue systemProperty = delegator.makeValue("SystemProperty", UtilMisc.toMap("systemResourceId", "ShopifyConfig", "systemPropertyId", "shopifyApiUrl", "systemPropertyValue", apiUrl)); + systemProperty.create(); + } else { + apiUrlProperty.set("systemPropertyValue", apiUrl); + apiUrlProperty.store(); + } + } + if (UtilValidate.isNotEmpty(username)) { + GenericValue usernameProperty = EntityQuery.use(delegator).from("SystemProperty").where("systemResourceId", "ShopifyConfig", "systemPropertyId", "shopifyUsername").queryOne(); + if (usernameProperty == null) { + GenericValue systemProperty = delegator.makeValue("SystemProperty", UtilMisc.toMap("systemResourceId", "ShopifyConfig", "systemPropertyId", "shopifyUsername", "systemPropertyValue", username)); + systemProperty.create(); + } else { + usernameProperty.set("systemPropertyValue", username); + usernameProperty.store(); + } + } + if (UtilValidate.isNotEmpty(password)) { + GenericValue passwordProperty = EntityQuery.use(delegator).from("SystemProperty").where("systemResourceId", "ShopifyConfig", "systemPropertyId", "shopifyPassword").queryOne(); + if (passwordProperty == null) { + GenericValue systemProperty = delegator.makeValue("SystemProperty", UtilMisc.toMap("systemResourceId", "ShopifyConfig", "systemPropertyId", "shopifyPassword", "systemPropertyValue", password)); + systemProperty.create(); + } else { + passwordProperty.set("systemPropertyValue", password); + passwordProperty.store(); + } + } + } catch (GenericEntityException e) { + Debug.logError("Exception in createUpdateShopifyConfiguration " + e, MODULE); + return ServiceUtil.returnFailure(UtilProperties.getMessage(resource, "ExceptionInCreateUpdateShopifyConfiguration", locale)); + } + result.put(ModelService.SUCCESS_MESSAGE, UtilProperties.getMessage(resource, "ShopifyConfigurationAdded", locale)); + return result; + } + + private static Map sendShopifyRequest(Map context) { + Map parameters = (Map) (context.get("parameters")); + Map queryMap = (Map) (context.get("queryMap")); + Map headerMap = (Map) (context.get("headerMap")); + Delegator delegator = (Delegator) context.get("delegator"); + Locale locale = (Locale) context.get("locale"); + String endpoint = (String) context.get("endpoint"); + String contentType = (String) context.get("contentType"); + String requestType = (String) context.get("requestType"); + Map httpResponse = new HashMap<>(); + + try { + Properties configProperties = EntityUtilProperties.getProperties(delegator, "ShopifyConfig"); + String apiUrl = (String) configProperties.get("shopifyApiUrl"); + if (UtilValidate.isEmpty(apiUrl)) { + Debug.logError(UtilProperties.getMessage(resource, "ShopifyApiUrlMissing", locale), MODULE); + return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ShopifyApiUrlMissing", locale)); + } else { + String nextLink = ""; + List responseStringList = new ArrayList<>(); + String username = (String) configProperties.get("shopifyUsername"); + String password = (String) configProperties.get("shopifyPassword"); + if (UtilValidate.isEmpty(username)) { + Debug.logError(UtilProperties.getMessage(resource, "ShopifyApiUsernameMissing", locale), MODULE); + return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ShopifyApiUsernameMissing", locale)); + } + if (UtilValidate.isEmpty(password)) { + Debug.logError(UtilProperties.getMessage(resource, "ShopifyApiPasswordMissing", locale), MODULE); + return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ShopifyApiPasswordMissing", locale)); + } + do { + String url = ""; + url = apiUrl + endpoint; + if (UtilValidate.isNotEmpty(nextLink)) { + url = nextLink; + } + HttpClient httpClient = new HttpClient(url); + httpClient.setBasicAuthInfo(username, password); + if (UtilValidate.isNotEmpty(headerMap)) { + httpClient.setHeaders(headerMap); + } + + // Setting default limit + if (UtilValidate.isEmpty(parameters.get("limit"))) { + parameters.put("limit", 250); + } + + if (UtilValidate.isNotEmpty(parameters)) { + httpClient.setParameters(parameters); + } + if (UtilValidate.isNotEmpty(queryMap)) { + JSON json = JSON.from(queryMap); + String jsonStr = null; + if (UtilValidate.isNotEmpty(json)) { + jsonStr = json.toString(); + } + httpClient.setRawStream(jsonStr); + } + httpClient.setTimeout(60 * 1000); + httpClient.setContentType(contentType); + httpClient.setDebug(false); + + String httpResponseString = null; + if ("GET".equalsIgnoreCase(requestType)) { + httpResponseString = httpClient.get(); + } else { + httpResponseString = httpClient.post(); + } + if (httpResponseString != null) { + //Preparing a list of responses, this will be later iterated to prepare a combined response coming from paginated requests + responseStringList.add(httpResponseString); + } + + /* Handling pagination, Shopify returns 250 records at maximum. It does return links to previous and next set of records in the response header.*/ + String paginationLink = httpClient.getResponseHeader("Link"); + List links = StringUtil.split(paginationLink, ","); // May contain previous and next link + if (UtilValidate.isNotEmpty(links)) { + for (String link : links) { + List parsedLink = StringUtil.split(link, ";"); + // obtaining next link + if (link.contains("\"next\"")) { + nextLink = parsedLink.get(0); + if (UtilValidate.isNotEmpty(nextLink)) { + if (nextLink.indexOf('<') >= 0 && nextLink.lastIndexOf('>') >= 0) { + nextLink = nextLink.substring(nextLink.indexOf('<') + 1, nextLink.lastIndexOf('>')); + } + } + } else { + nextLink = ""; + } + } + } else { + nextLink = ""; + } + } while (UtilValidate.isNotEmpty(nextLink)); + + if (UtilValidate.isNotEmpty(responseStringList)) { + if (responseStringList.size() > 1) { + String key = ""; + List> value = new ArrayList<>(); + for (String response : responseStringList) { + Map responseMap = new HashMap(); + ObjectMapper mapper = new ObjectMapper(); + try { + //convert JSON string to Map + responseMap = mapper.readValue(response, new TypeReference>(){}); + } catch (Exception e) { + Debug.logError(e, MODULE); + } + for (Map.Entry entry : responseMap.entrySet()) { + key = entry.getKey(); + if (entry.getValue() instanceof List) { + if (UtilValidate.isNotEmpty(value)) { + value.addAll((List) entry.getValue()); + } else { + value = (List) (entry.getValue()); + } + } + } + } + JSON json = JSON.from(UtilMisc.toMap(key, value)); + String combinedResponse = null; + if (UtilValidate.isNotEmpty(json)) { + combinedResponse = json.toString(); + } + httpResponse.put("httpResponse", combinedResponse); + } else { + httpResponse.put("httpResponse", responseStringList.get(0)); + } + } + } + } catch (HttpClientException | IOException e) { + Debug.logError(e, "Could not complete transaction: " + e.toString(), MODULE); + } + return httpResponse; + } + +} \ No newline at end of file diff --git a/shopify/webapp/shopify/WEB-INF/controller.xml b/shopify/webapp/shopify/WEB-INF/controller.xml new file mode 100644 index 000000000..34ef602eb --- /dev/null +++ b/shopify/webapp/shopify/WEB-INF/controller.xml @@ -0,0 +1,61 @@ + + + + + + + + Shopify Component Site Configuration File + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/shopify/webapp/shopify/WEB-INF/web.xml b/shopify/webapp/shopify/WEB-INF/web.xml new file mode 100644 index 000000000..a2112ef81 --- /dev/null +++ b/shopify/webapp/shopify/WEB-INF/web.xml @@ -0,0 +1,96 @@ + + + + + Apache OFBiz - Shopify Component + Shopify Component of the Apache OFBiz Project + + + + A unique name used to identify/recognize the local dispatcher for the Service Engine + localDispatcherNameshopify + + + The Name of the Entity Delegator to use, defined in entityengine.xml + entityDelegatorNamedefault + + + The location of the main-decorator screen to use for this webapp; referred to as a context variable in screen def XML files. + mainDecoratorLocation + component://shopify/widget/CommonScreens.xml + + + Remove unnecessary whitespace from HTML output. + compressHTML + false + + + + ControlFilter + ControlFilter + org.apache.ofbiz.webapp.control.ControlFilter + + allowedPaths + /error:/control:/select:/index.html:/index.jsp:/default.html:/default.jsp:/images + + redirectPath/control/main + + + ContextFilter + ContextFilter + org.apache.ofbiz.webapp.control.ContextFilter + + + SameSiteFilter + SameSiteFilter + org.apache.ofbiz.webapp.control.SameSiteFilter + + ControlFilter/* + ContextFilter/* + SameSiteFilter/* + + org.apache.ofbiz.webapp.control.ControlEventListener + org.apache.ofbiz.webapp.control.LoginEventListener + + + + + Main Control Servlet + ControlServlet + ControlServlet + org.apache.ofbiz.webapp.control.ControlServlet + 1 + + ControlServlet/control/* + + + 60 + + + + index.jsp + index.html + index.htm + + diff --git a/shopify/webapp/shopify/index.jsp b/shopify/webapp/shopify/index.jsp new file mode 100644 index 000000000..4ea7d0c8b --- /dev/null +++ b/shopify/webapp/shopify/index.jsp @@ -0,0 +1,20 @@ +<%-- +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. +--%> + +<%response.sendRedirect("control/main");%> \ No newline at end of file diff --git a/shopify/widget/CommonScreens.xml b/shopify/widget/CommonScreens.xml new file mode 100644 index 000000000..be1c2352d --- /dev/null +++ b/shopify/widget/CommonScreens.xml @@ -0,0 +1,101 @@ + + + + + + +
+ + + + + + + + + + + + + + + +
+
+ + +
+ + + + + +
+ + + + + + + + + +
+
+
+
+
+
+ + +
+ + + + + + +
+ + + + + + +
+ + + + + +
+ +
+ + +
+
+
+
+
+
+
\ No newline at end of file diff --git a/shopify/widget/ShopifyForms.xml b/shopify/widget/ShopifyForms.xml new file mode 100644 index 000000000..7bfc01103 --- /dev/null +++ b/shopify/widget/ShopifyForms.xml @@ -0,0 +1,31 @@ + + + + + +
+ + + + +
+ +
\ No newline at end of file diff --git a/shopify/widget/ShopifyMenus.xml b/shopify/widget/ShopifyMenus.xml new file mode 100644 index 000000000..02dd9cd6b --- /dev/null +++ b/shopify/widget/ShopifyMenus.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/shopify/widget/ShopifyScreens.xml b/shopify/widget/ShopifyScreens.xml new file mode 100644 index 000000000..1ea313792 --- /dev/null +++ b/shopify/widget/ShopifyScreens.xml @@ -0,0 +1,74 @@ + + + + + + +
+ + + + + + + + + +
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+
+
+
+
+
+ +
\ No newline at end of file