Skip to content

Commit

Permalink
CIF-1330 - GraphQL endpoint used by client-side code should be config…
Browse files Browse the repository at this point in the history
…urable (#244)

Add GraphQL endpoint to StoreConfigExporter and pick it up from client-side code
  • Loading branch information
herzog31 authored Mar 31, 2020
1 parent 0c890ec commit 7ddd3da
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,52 @@
*
******************************************************************************/

package com.adobe.cq.commerce.core.components.internal.models.v1.storeviewexporter;
package com.adobe.cq.commerce.core.components.internal.models.v1.storeconfigexporter;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.caconfig.ConfigurationBuilder;
import org.apache.sling.models.annotations.Model;

import com.adobe.cq.commerce.core.components.models.storeviewexporter.StoreViewExporter;
import com.day.cq.commons.inherit.HierarchyNodeInheritanceValueMap;
import com.day.cq.commons.inherit.InheritanceValueMap;
import com.adobe.cq.commerce.core.components.models.storeconfigexporter.StoreConfigExporter;
import com.day.cq.wcm.api.Page;

@Model(
adaptables = SlingHttpServletRequest.class,
adapters = { StoreViewExporter.class },
resourceType = StoreViewExporterImpl.RESOURCE_TYPE)
public class StoreViewExporterImpl implements StoreViewExporter {
adapters = { StoreConfigExporter.class },
resourceType = StoreConfigExporterImpl.RESOURCE_TYPE)
public class StoreConfigExporterImpl implements StoreConfigExporter {

protected static final String RESOURCE_TYPE = "core/cif/components/structure/page/v1/page";
private static final String CONFIG_NAME = "cloudconfigs/commerce";
private static final String STORE_CODE_PROPERTY = "magentoStore";
private static final String GRAPHQL_ENDPOINT_PROPERTY = "magentoGraphqlEndpoint";

@Inject
private Page currentPage;

private String storeView;
private String graphqlEndpoint = "/magento/graphql";

@PostConstruct
void initModel() {
InheritanceValueMap properties = new HierarchyNodeInheritanceValueMap(currentPage.getContentResource());
storeView = properties.getInherited(STORE_CODE_PROPERTY, String.class);
if (storeView == null) {
storeView = "default";
}
ConfigurationBuilder configurationBuilder = currentPage.adaptTo(ConfigurationBuilder.class);
ValueMap properties = configurationBuilder.name(CONFIG_NAME).asValueMap();

storeView = properties.get(STORE_CODE_PROPERTY, "default");
graphqlEndpoint = properties.get(GRAPHQL_ENDPOINT_PROPERTY, "/magento/graphql");
}

@Override
public String getStoreView() {
return storeView;
}

@Override
public String getGraphqlEndpoint() {
return graphqlEndpoint;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,21 @@
*
******************************************************************************/

package com.adobe.cq.commerce.core.components.models.storeviewexporter;
package com.adobe.cq.commerce.core.components.models.storeconfigexporter;

import org.osgi.annotation.versioning.ProviderType;

@ProviderType
public interface StoreViewExporter {
public interface StoreConfigExporter {

/**
* Returns the Magento store view identifier.
*/
String getStoreView();

/**
* Returns the GraphQL endpoint for client-side components.
*/
String getGraphqlEndpoint();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*******************************************************************************
*
* Copyright 2019 Adobe. All rights reserved.
* This file is licensed 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 REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*
******************************************************************************/

package com.adobe.cq.commerce.core.components.internal.models.v1.storeconfigexporter;

import java.util.Collections;

import org.apache.sling.api.scripting.SlingBindings;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.apache.sling.caconfig.ConfigurationBuilder;
import org.apache.sling.testing.mock.sling.ResourceResolverType;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.scripting.WCMBindingsConstants;
import com.google.common.collect.ImmutableMap;
import io.wcm.testing.mock.aem.junit.AemContext;
import io.wcm.testing.mock.aem.junit.AemContextCallback;

import static org.mockito.Matchers.any;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class StoreConfigExporterTest {

@Rule
public final AemContext context = createContext("/context/jcr-content.json");

private ConfigurationBuilder configurationBuilder;

private static AemContext createContext(String contentPath) {
return new AemContext(
(AemContextCallback) context -> {
context.load().json(contentPath, "/content");
},
ResourceResolverType.JCR_MOCK);
}

@Before
public void setup() {
Page page = mock(Page.class);
configurationBuilder = mock(ConfigurationBuilder.class, RETURNS_DEEP_STUBS);
when(configurationBuilder.name(any()).asValueMap()).thenReturn(new ValueMapDecorator(ImmutableMap.of("magentoStore",
"my-magento-store", "magentoGraphqlEndpoint", "/my/magento/graphql")));
when(page.adaptTo(ConfigurationBuilder.class)).thenReturn(configurationBuilder);

SlingBindings slingBindings = (SlingBindings) context.request().getAttribute(SlingBindings.class.getName());
slingBindings.put(WCMBindingsConstants.NAME_CURRENT_PAGE, page);
}

@Test
public void testStoreView() {
StoreConfigExporterImpl storeConfigExporter = context.request().adaptTo(StoreConfigExporterImpl.class);

Assert.assertEquals("my-magento-store", storeConfigExporter.getStoreView());
}

@Test
public void testStoreViewDefault() {
when(configurationBuilder.name(any()).asValueMap()).thenReturn(new ValueMapDecorator(
Collections.emptyMap()));

StoreConfigExporterImpl storeConfigExporter = context.request().adaptTo(StoreConfigExporterImpl.class);

Assert.assertEquals("default", storeConfigExporter.getStoreView());
}

@Test
public void testGraphqlEndpoint() {
StoreConfigExporterImpl storeConfigExporter = context.request().adaptTo(StoreConfigExporterImpl.class);

Assert.assertEquals("/my/magento/graphql", storeConfigExporter.getGraphqlEndpoint());
}

@Test
public void testGraphqlEndpointDefault() {
when(configurationBuilder.name(any()).asValueMap()).thenReturn(new ValueMapDecorator(
Collections.emptyMap()));

StoreConfigExporterImpl storeConfigExporter = context.request().adaptTo(StoreConfigExporterImpl.class);

Assert.assertEquals("/magento/graphql", storeConfigExporter.getGraphqlEndpoint());
}

}

This file was deleted.

1 change: 1 addition & 0 deletions bundles/core/src/test/resources/context/jcr-content.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"pageA": {
"jcr:primaryType": "cq:Page",
"jcr:content": {
"sling:resourceType": "core/cif/components/structure/page/v1/page",
"cq:cifProductPage": "/content/product-page",
"cq:cifCategoryPage": "/content/category-page",
"jcr:language": "en_US",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,8 @@ class CommerceGraphqlApi {

(function() {
function onDocumentReady() {
const endpoint = '/magento/graphql';
const storeView = document.querySelector('body').dataset.storeView;
window.CIF.CommerceGraphqlApi = new CommerceGraphqlApi({ endpoint, storeView });
const { storeView, graphqlEndpoint } = document.querySelector('body').dataset;
window.CIF.CommerceGraphqlApi = new CommerceGraphqlApi({ endpoint: graphqlEndpoint, storeView });
}

if (document.readyState !== 'loading') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
<!DOCTYPE html>
<html
data-sly-use.page="com.adobe.cq.wcm.core.components.models.Page"
data-sly-use.storeView="com.adobe.cq.commerce.core.components.models.storeviewexporter.StoreViewExporter"
data-sly-use.storeView="com.adobe.cq.commerce.core.components.models.storeconfigexporter.StoreConfigExporter"
lang="${page.language}"
data-sly-use.head="head.html"
data-sly-use.footer="footer.html"
data-sly-use.redirect="redirect.html"
>
<head data-sly-call="${head.head @ page = page}"></head>
<body class="${page.cssClassNames}" data-store-view="${storeView.storeView}">
<body class="${page.cssClassNames}" data-store-view="${storeView.storeView}" data-graphql-endpoint="${storeView.graphqlEndpoint}">
<sly
data-sly-test.isRedirectPage="${page.redirectTarget && (wcmmode.edit || wcmmode.preview)}"
data-sly-call="${redirect.redirect @ redirectTarget = page.redirectTarget}"
Expand Down
4 changes: 2 additions & 2 deletions ui.apps/src/main/javascript/react-components/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import { I18nextProvider } from 'react-i18next';
import i18n from './i18n';

const App = () => {
const storeView = document.querySelector('body').dataset.storeView;
const { storeView, graphqlEndpoint } = document.querySelector('body').dataset;
return (
<I18nextProvider i18n={i18n} defaultNS="common">
<CommerceApp uri={'/magento/graphql'} storeView={storeView}>
<CommerceApp uri={graphqlEndpoint} storeView={storeView}>
<Cart />
<AuthBar />
</CommerceApp>
Expand Down

0 comments on commit 7ddd3da

Please sign in to comment.