├── src
├── main
│ ├── resources
│ │ ├── application-dev.yml
│ │ ├── static
│ │ │ ├── css
│ │ │ │ ├── app.css
│ │ │ │ └── primary.css
│ │ │ ├── img
│ │ │ │ └── app.jpg
│ │ │ └── js
│ │ │ │ ├── app.js
│ │ │ │ └── primary.js
│ │ ├── graphql
│ │ │ ├── createProductVariables.json
│ │ │ ├── getShop.graphql
│ │ │ ├── createProduct.graphql
│ │ │ └── getProducts.graphql
│ │ ├── application-prd.yml
│ │ ├── templates
│ │ │ ├── fragments
│ │ │ │ ├── footer.html
│ │ │ │ └── header.html
│ │ │ ├── dash-embedded.html
│ │ │ └── layout
│ │ │ │ └── layout.html
│ │ ├── application-local-example.yml
│ │ ├── META-INF
│ │ │ └── additional-spring-configuration-metadata.json
│ │ └── application.yml
│ ├── java
│ │ └── com
│ │ │ └── justblackmagic
│ │ │ └── shopify
│ │ │ ├── auth
│ │ │ ├── package-info.java
│ │ │ ├── util
│ │ │ │ ├── package-info.java
│ │ │ │ ├── AuthConstants.java
│ │ │ │ ├── JWTUtil.java
│ │ │ │ └── CryptoConverter.java
│ │ │ ├── service
│ │ │ │ ├── package-info.java
│ │ │ │ ├── ShopifyUserService.java
│ │ │ │ └── ShopifyStoreUser.java
│ │ │ ├── customization
│ │ │ │ ├── package-info.java
│ │ │ │ ├── CustomTokenResponseConverter.java
│ │ │ │ └── ShopifyOAuthAuthenticationSuccessHandler.java
│ │ │ ├── persistence
│ │ │ │ ├── model
│ │ │ │ │ ├── package-info.java
│ │ │ │ │ ├── AuthorizedClientId.java
│ │ │ │ │ └── AuthorizedClient.java
│ │ │ │ └── repository
│ │ │ │ │ ├── package-info.java
│ │ │ │ │ └── JPAAuthorizedClientRepository.java
│ │ │ └── filter
│ │ │ │ ├── ShopifyShopNameFilter.java
│ │ │ │ ├── FilterRegistrationConfig.java
│ │ │ │ └── HMACVerificationFilter.java
│ │ │ ├── api
│ │ │ ├── graphql
│ │ │ │ ├── model
│ │ │ │ │ ├── Extensions.java
│ │ │ │ │ ├── GraphQLResponse.java
│ │ │ │ │ ├── Cost.java
│ │ │ │ │ ├── ProductNode.java
│ │ │ │ │ ├── ThrottleStatus.java
│ │ │ │ │ ├── Product.java
│ │ │ │ │ ├── ProductCreate.java
│ │ │ │ │ ├── Shop.java
│ │ │ │ │ ├── Products.java
│ │ │ │ │ └── InputWrapper.java
│ │ │ │ ├── GraphqlRequestBody.java
│ │ │ │ ├── ShopifyGraphQLClientService.java
│ │ │ │ └── GraphqlSchemaReaderUtil.java
│ │ │ ├── package-info.java
│ │ │ └── rest
│ │ │ │ ├── model
│ │ │ │ ├── ShopifyRefundCreationRequest.java
│ │ │ │ ├── ShopifyOrderUpdateRoot.java
│ │ │ │ ├── ShopifyVariantRequest.java
│ │ │ │ ├── ShopifyInventoryLevelRoot.java
│ │ │ │ ├── FulfillmentService.java
│ │ │ │ ├── ShopifyProductRequest.java
│ │ │ │ ├── Count.java
│ │ │ │ ├── ShopifyShop.java
│ │ │ │ ├── MetafieldRoot.java
│ │ │ │ ├── ShopifyImageRoot.java
│ │ │ │ ├── ShopifyOrderRoot.java
│ │ │ │ ├── ShopifyRefundRoot.java
│ │ │ │ ├── ShopifyVariantRoot.java
│ │ │ │ ├── ShopifyProductRoot.java
│ │ │ │ ├── ShopifyAttribute.java
│ │ │ │ ├── ShopifyCancelOrderRequest.java
│ │ │ │ ├── ShopifyFulfillmentRoot.java
│ │ │ │ ├── ShopifyErrorsRoot.java
│ │ │ │ ├── ShopifyCustomerRoot.java
│ │ │ │ ├── ShopifyCustomerUpdateRoot.java
│ │ │ │ ├── ShopifyTaxLine.java
│ │ │ │ ├── ShopifyOrdersRoot.java
│ │ │ │ ├── MetafieldsRoot.java
│ │ │ │ ├── ShopifyAccessTokenRoot.java
│ │ │ │ ├── ShopifyOrderRisksRoot.java
│ │ │ │ ├── ShopifyLocationsRoot.java
│ │ │ │ ├── ShopifyProductsRoot.java
│ │ │ │ ├── ShopifyCustomersRoot.java
│ │ │ │ ├── ShopifyGiftCardRoot.java
│ │ │ │ ├── ShopifyTransactionReceipt.java
│ │ │ │ ├── ShopifyAdjustmentsRoot.java
│ │ │ │ ├── ShopifyTransactionsRoot.java
│ │ │ │ ├── ShopifyCustomCollectionRoot.java
│ │ │ │ ├── ShopifyShippingLine.java
│ │ │ │ ├── ShopifyRecurringApplicationChargeRoot.java
│ │ │ │ ├── ShopifyVariantRequestPositionComparator.java
│ │ │ │ ├── ShopifyInventoryLevel.java
│ │ │ │ ├── ShopifyCustomCollectionsRoot.java
│ │ │ │ ├── InventoryPolicy.java
│ │ │ │ ├── ShopifyRefundShippingDetails.java
│ │ │ │ ├── MetafieldValueType.java
│ │ │ │ ├── ShopifyVariantRequestOption1Comparator.java
│ │ │ │ ├── ShopifyAdjustment.java
│ │ │ │ ├── ShopifyErrors.java
│ │ │ │ ├── serializer
│ │ │ │ │ ├── CurrencySerializer.java
│ │ │ │ │ ├── CurrencyDeserializer.java
│ │ │ │ │ ├── EscapedStringSerializer.java
│ │ │ │ │ ├── InventoryPolicySerializer.java
│ │ │ │ │ ├── MetafieldValueTypeSerializer.java
│ │ │ │ │ ├── OrderRiskRecommendationSerializer.java
│ │ │ │ │ ├── InventoryPolicyDeserializer.java
│ │ │ │ │ ├── MetafieldValueTypeDeserializer.java
│ │ │ │ │ ├── EscapedStringsSerializer.java
│ │ │ │ │ ├── OrderRiskRecommendationDeserializer.java
│ │ │ │ │ ├── TagsDeserializer.java
│ │ │ │ │ └── TagsSerializer.java
│ │ │ │ ├── OrderRiskRecommendation.java
│ │ │ │ ├── ShopifyRefundLineItem.java
│ │ │ │ ├── ShopifyLocation.java
│ │ │ │ ├── Option.java
│ │ │ │ ├── Image.java
│ │ │ │ ├── ShopifyAddress.java
│ │ │ │ ├── ShopifyCustomer.java
│ │ │ │ ├── ShopifyCustomCollection.java
│ │ │ │ ├── ShopifyPage.java
│ │ │ │ ├── ShopifyAddressUpdateRequest.java
│ │ │ │ ├── ImageAltTextCreationRequest.java
│ │ │ │ ├── Webhook.java
│ │ │ │ ├── Metafield.java
│ │ │ │ ├── ShopifyTransaction.java
│ │ │ │ ├── ShopifyOrderRisk.java
│ │ │ │ ├── ShopifyGiftCard.java
│ │ │ │ ├── ShopifyLineItem.java
│ │ │ │ ├── ShopifyRefund.java
│ │ │ │ ├── ShopifyRecurringApplicationCharge.java
│ │ │ │ ├── ShopifyProducts.java
│ │ │ │ ├── ShopifyGiftCardCreationRequest.java
│ │ │ │ ├── Shop.java
│ │ │ │ ├── ShopifyFulfillment.java
│ │ │ │ ├── ShopifyProductMetafieldCreationRequest.java
│ │ │ │ ├── ShopifyVariantMetafieldCreationRequest.java
│ │ │ │ ├── ShopifyVariant.java
│ │ │ │ ├── ShopifyCustomCollectionCreationRequest.java
│ │ │ │ ├── ShopifyCustomerUpdateRequest.java
│ │ │ │ ├── ShopifyGetCustomersRequest.java
│ │ │ │ ├── ShopifyProduct.java
│ │ │ │ ├── ShopifyFulfillmentCreationRequest.java
│ │ │ │ ├── ShopifyRecurringApplicationChargeCreationRequest.java
│ │ │ │ ├── ShopifyFulfillmentUpdateRequest.java
│ │ │ │ └── ShopifyOrder.java
│ │ │ │ ├── package-info.java
│ │ │ │ ├── exceptions
│ │ │ │ ├── ShopifyClientException.java
│ │ │ │ ├── ShopifyErrorCode.java
│ │ │ │ ├── ShopifyErrorResponseException.java
│ │ │ │ └── ShopifyErrorCodeFactory.java
│ │ │ │ ├── ShopifyRestClientService.java
│ │ │ │ └── mappers
│ │ │ │ ├── ResponseEntityToStringMapper.java
│ │ │ │ └── ShopifySdkObjectMapper.java
│ │ │ ├── app
│ │ │ └── controller
│ │ │ │ ├── AuthCheckResponse.java
│ │ │ │ ├── webhooks
│ │ │ │ ├── UninstallWebhook.java
│ │ │ │ ├── GDPRShopDeleteWebhook.java
│ │ │ │ ├── GDPRDataRequestWebhook.java
│ │ │ │ └── GDPRCustomerDeleteWebhook.java
│ │ │ │ └── DemoStandaloneAppController.java
│ │ │ ├── ShopifyApplication.java
│ │ │ └── event
│ │ │ ├── events
│ │ │ └── AppInstallEvent.java
│ │ │ └── listener
│ │ │ └── AppInstallListener.java
│ └── webapp
│ │ └── javascript
│ │ └── Main.jsx
└── test
│ └── java
│ └── com
│ └── justblackmagic
│ └── shopify
│ └── ShopifyApplicationTests.java
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── HELP.md
├── webpack.config.js
├── .github
├── dependabot.yml
└── workflows
│ └── codeql-analysis.yml
├── .vscode
└── settings.json
├── package.json
├── gradlew.bat
└── README.md
/src/main/resources/application-dev.yml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/static/css/app.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/static/img/app.jpg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/static/js/app.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/static/js/primary.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'shopify'
2 |
--------------------------------------------------------------------------------
/src/main/resources/graphql/createProductVariables.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "$titleValue"
3 | }
4 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/auth/package-info.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.auth;
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/auth/util/package-info.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.auth.util;
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/auth/service/package-info.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.auth.service;
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/auth/customization/package-info.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.auth.customization;
--------------------------------------------------------------------------------
/src/main/resources/application-prd.yml:
--------------------------------------------------------------------------------
1 | ---
2 | server:
3 | address: 127.0.0.1
4 |
5 | spring:
6 | thymeleaf:
7 | cache: true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devondragon/SpringShopifyAppFramework/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/auth/persistence/model/package-info.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.auth.persistence.model;
--------------------------------------------------------------------------------
/src/main/resources/static/css/primary.css:
--------------------------------------------------------------------------------
1 | .Polaris-Breadcrumbs__Breadcrumb {
2 | float:left;
3 | margin-right: 0.4em !important;
4 | }
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/auth/persistence/repository/package-info.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.auth.persistence.repository;
--------------------------------------------------------------------------------
/src/main/resources/graphql/getShop.graphql:
--------------------------------------------------------------------------------
1 | {
2 | shop {
3 | name
4 | currencyCode
5 | checkoutApiSupported
6 | taxesIncluded
7 | }
8 | }
--------------------------------------------------------------------------------
/src/main/resources/graphql/createProduct.graphql:
--------------------------------------------------------------------------------
1 | mutation productCreate($input: ProductInput!) {
2 | productCreate(input: $input) {
3 | product {
4 | id
5 | title
6 | handle
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/src/main/resources/graphql/getProducts.graphql:
--------------------------------------------------------------------------------
1 | {
2 | products(first: 50, reverse: true) {
3 | edges {
4 | node {
5 | id
6 | title
7 | handle
8 | }
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/graphql/model/Extensions.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.graphql.model;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class Extensions {
7 | public Cost cost;
8 | }
9 |
--------------------------------------------------------------------------------
/HELP.md:
--------------------------------------------------------------------------------
1 | # Getting Started
2 |
3 | Read the Quick Start documentation here: [https://github.com/devondragon/SpringShopifyAppFramework/wiki/Quick-Start-Guide](https://github.com/devondragon/SpringShopifyAppFramework/wiki/Quick-Start-Guide)
4 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This package contains all of the Shopify API clients, services, models, and helpers for both the REST and GraphQL APIs.
3 | */
4 | package com.justblackmagic.shopify.api;
5 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/auth/util/AuthConstants.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.auth.util;
2 |
3 | public abstract class AuthConstants {
4 |
5 | public static final String SHOP_ATTRIBUE_NAME = "shop";
6 |
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/graphql/model/GraphQLResponse.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.graphql.model;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public abstract class GraphQLResponse {
7 | private Extensions extensions;
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/resources/templates/fragments/footer.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Shopify App Testing Footer
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/main/resources/templates/fragments/header.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Shopify App Testing Header
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyRefundCreationRequest.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class ShopifyRefundCreationRequest {
7 |
8 | private ShopifyRefund request;
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyOrderUpdateRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class ShopifyOrderUpdateRoot {
7 |
8 | private ShopifyOrderShippingAddressUpdateRequest order;
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/graphql/model/Cost.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.graphql.model;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class Cost {
7 | public int requestedQueryCost;
8 | public int actualQueryCost;
9 | public ThrottleStatus throttleStatus;
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/resources/templates/dash-embedded.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React on Spring
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/graphql/model/ProductNode.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.graphql.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import lombok.Data;
5 |
6 | @Data
7 | public class ProductNode {
8 | @JsonProperty("node")
9 | private Product product;
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/graphql/model/ThrottleStatus.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.graphql.model;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class ThrottleStatus {
7 | public double maximumAvailable;
8 | public int currentlyAvailable;
9 | public double restoreRate;
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/java/com/justblackmagic/shopify/ShopifyApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify;
2 |
3 | import org.springframework.boot.test.context.SpringBootTest;
4 |
5 | @SpringBootTest
6 | class ShopifyApplicationTests {
7 |
8 | // @Test
9 | // void testTrue() {
10 | // assertTrue(true);
11 | // }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/graphql/model/Product.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.graphql.model;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class Product {
7 |
8 | public static String NODE_NAME = "product";
9 |
10 | private String id;
11 | private String title;
12 | private String handle;
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyVariantRequest.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | public interface ShopifyVariantRequest {
4 |
5 | public ShopifyVariant getRequest();
6 |
7 | public String getImageSource();
8 |
9 | public boolean hasImageSource();
10 |
11 | public boolean hasChanged();
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/app/controller/AuthCheckResponse.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.app.controller;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class AuthCheckResponse {
7 | private boolean authenticated;
8 |
9 | private String authRedirectURL;
10 |
11 | private String shopName;
12 |
13 | private String scopes;
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyInventoryLevelRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import lombok.Data;
5 |
6 | @Data
7 | public class ShopifyInventoryLevelRoot {
8 |
9 | @JsonProperty("inventory_level")
10 | private ShopifyInventoryLevel inventoryLevel;
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Most of the contents of this package originated as a clone of the https://github.com/ChannelApe/shopify-sdk project. We have made many changes to
3 | * the original code, and likely have many more changes to make to fully support newer versions of the Shopify API.
4 | */
5 | package com.justblackmagic.shopify.api.rest;
6 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/FulfillmentService.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | public enum FulfillmentService {
4 |
5 | MANUAL("manual");
6 |
7 | private final String value;
8 |
9 | private FulfillmentService(final String value) {
10 | this.value = value;
11 | }
12 |
13 | @Override
14 | public String toString() {
15 | return value;
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyProductRequest.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | public interface ShopifyProductRequest {
4 |
5 | public ShopifyProduct getRequest();
6 |
7 | public int getVariantImagePosition(final int variantPosition);
8 |
9 | public boolean hasVariantImagePosition(final int variantPosition);
10 |
11 | public boolean hasChanged();
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/graphql/model/ProductCreate.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.graphql.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.annotation.JsonRootName;
5 | import lombok.Data;
6 |
7 | @Data
8 | @JsonRootName(value = "productCreate")
9 | public class ProductCreate {
10 | public static String NODE_NAME = "productCreate";
11 |
12 | @JsonProperty("product")
13 | private Product product;
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | devtool: 'source-map',
3 | output: {
4 | filename: 'react-app.js'
5 | },
6 | module: {
7 | rules: [{
8 | test: /\.(js|jsx)$/,
9 | exclude: /node_modules/,
10 | loader: "babel-loader",
11 | options: {
12 | presets: ['@babel/preset-env', '@babel/preset-react']
13 | }
14 | }]
15 | },
16 | resolve: {
17 | extensions: ['.js', '.jsx']
18 | }
19 | };
--------------------------------------------------------------------------------
/src/main/webapp/javascript/Main.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import ReactDOM from 'react-dom';
3 |
4 | class Main extends Component {
5 | render() {
6 | return (
7 |
8 |
Demo Component
9 |

10 |
11 | );
12 | }
13 | }
14 |
15 | ReactDOM.render(
16 | ,
17 | document.getElementById('react-mountpoint')
18 | );
19 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/exceptions/ShopifyClientException.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.exceptions;
2 |
3 | public class ShopifyClientException extends RuntimeException {
4 |
5 | private static final long serialVersionUID = -5992356578452439224L;
6 |
7 | public ShopifyClientException(final Throwable throwable) {
8 | super(throwable);
9 | }
10 |
11 | public ShopifyClientException(final String message, final Throwable throwable) {
12 | super(message, throwable);
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "gradle" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "weekly"
12 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/Count.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import lombok.Data;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 |
9 | @Data
10 | public class Count {
11 |
12 | private int count;
13 |
14 |
15 | /**
16 | * @param name
17 | * @param value
18 | */
19 | @JsonAnySetter
20 | public void ignored(String name, Object value) {
21 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyShop.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import lombok.Data;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 | @Data
9 | public class ShopifyShop {
10 |
11 | private Shop shop;
12 |
13 |
14 | /**
15 | * @param name
16 | * @param value
17 | */
18 | @JsonAnySetter
19 | public void ignored(String name, Object value) {
20 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/ShopifyApplication.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
6 |
7 | @EnableJpaAuditing
8 | @SpringBootApplication
9 | public class ShopifyApplication {
10 |
11 |
12 | /**
13 | * @param args
14 | */
15 | public static void main(String[] args) {
16 | SpringApplication.run(ShopifyApplication.class, args);
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/MetafieldRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import lombok.Data;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 | @Data
9 | public class MetafieldRoot {
10 |
11 | private Metafield metafield;
12 |
13 |
14 | /**
15 | * @param name
16 | * @param value
17 | */
18 | @JsonAnySetter
19 | public void ignored(String name, Object value) {
20 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyImageRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import lombok.Data;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 | @Data
9 | public class ShopifyImageRoot {
10 |
11 | private Image image;
12 |
13 |
14 | /**
15 | * @param name
16 | * @param value
17 | */
18 | @JsonAnySetter
19 | public void ignored(String name, Object value) {
20 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyOrderRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import lombok.Data;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 | @Data
9 | public class ShopifyOrderRoot {
10 |
11 | private ShopifyOrder order;
12 |
13 |
14 | /**
15 | * @param name
16 | * @param value
17 | */
18 | @JsonAnySetter
19 | public void ignored(String name, Object value) {
20 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyRefundRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import lombok.Data;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 | @Data
9 | public class ShopifyRefundRoot {
10 |
11 | private ShopifyRefund refund;
12 |
13 |
14 | /**
15 | * @param name
16 | * @param value
17 | */
18 | @JsonAnySetter
19 | public void ignored(String name, Object value) {
20 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyVariantRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import lombok.Data;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 | @Data
9 | public class ShopifyVariantRoot {
10 |
11 | private ShopifyVariant variant;
12 |
13 |
14 | /**
15 | * @param name
16 | * @param value
17 | */
18 | @JsonAnySetter
19 | public void ignored(String name, Object value) {
20 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyProductRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import lombok.Data;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 | @Data
9 | public class ShopifyProductRoot {
10 |
11 | private ShopifyProduct product;
12 |
13 |
14 | /**
15 | * @param name
16 | * @param value
17 | */
18 | @JsonAnySetter
19 | public void ignored(String name, Object value) {
20 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/graphql/model/Shop.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.graphql.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonRootName;
4 | import lombok.Data;
5 | import lombok.EqualsAndHashCode;
6 |
7 | @Data
8 | @EqualsAndHashCode(callSuper = true)
9 | @JsonRootName(value = "shop")
10 | public class Shop extends GraphQLResponse {
11 |
12 | public static String NODE_NAME = "shop";
13 |
14 | private String name;
15 | private String currencyCode;
16 | private boolean checkoutApiSupported;
17 | private boolean taxesIncluded;
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyAttribute.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import lombok.Data;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 | @Data
9 | public class ShopifyAttribute {
10 |
11 | private String name;
12 | private String value;
13 |
14 |
15 | /**
16 | * @param name
17 | * @param value
18 | */
19 | @JsonAnySetter
20 | public void ignored(String name, Object value) {
21 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyCancelOrderRequest.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import lombok.Data;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 | @Data
9 | public class ShopifyCancelOrderRequest {
10 |
11 | private String reason;
12 |
13 |
14 | /**
15 | * @param name
16 | * @param value
17 | */
18 | @JsonAnySetter
19 | public void ignored(String name, Object value) {
20 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyFulfillmentRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import lombok.Data;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 | @Data
9 | public class ShopifyFulfillmentRoot {
10 |
11 | private ShopifyFulfillment fulfillment;
12 |
13 |
14 | /**
15 | * @param name
16 | * @param value
17 | */
18 | @JsonAnySetter
19 | public void ignored(String name, Object value) {
20 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyErrorsRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import lombok.Data;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 | @Data
9 | public class ShopifyErrorsRoot {
10 |
11 | private ShopifyErrors errors = new ShopifyErrors();
12 |
13 |
14 | /**
15 | * @param name
16 | * @param value
17 | */
18 | @JsonAnySetter
19 | public void ignored(String name, Object value) {
20 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/graphql/GraphqlRequestBody.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.graphql;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.NoArgsConstructor;
6 | import lombok.Setter;
7 |
8 | /**
9 | * @author justblackmagic
10 | * @since 0.0.1
11 | */
12 |
13 | @Getter
14 | @Setter
15 | @AllArgsConstructor
16 | @NoArgsConstructor
17 | /**
18 | * GraphqlRequestBody
19 | */
20 | public class GraphqlRequestBody {
21 | /* GraphQL query */
22 | private String query;
23 |
24 | /* GraphQL variables */
25 | private Object variables;
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyCustomerRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import lombok.Data;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 | @Data
9 | public class ShopifyCustomerRoot {
10 |
11 | private ShopifyCustomer customer;
12 |
13 |
14 | /**
15 | * @param name
16 | * @param value
17 | */
18 | @JsonAnySetter
19 | public void ignored(String name, Object value) {
20 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyCustomerUpdateRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import lombok.Data;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 | @Data
9 | public class ShopifyCustomerUpdateRoot {
10 |
11 | private ShopifyCustomerUpdateRequest customer;
12 |
13 |
14 | /**
15 | * @param name
16 | * @param value
17 | */
18 | @JsonAnySetter
19 | public void ignored(String name, Object value) {
20 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyTaxLine.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.math.BigDecimal;
4 | import com.fasterxml.jackson.annotation.JsonAnySetter;
5 | import lombok.Data;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | @Slf4j
9 | @Data
10 | public class ShopifyTaxLine {
11 |
12 | private String title;
13 | private BigDecimal price;
14 | private BigDecimal rate;
15 |
16 |
17 | /**
18 | * @param name
19 | * @param value
20 | */
21 | @JsonAnySetter
22 | public void ignored(String name, Object value) {
23 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyOrdersRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.LinkedList;
4 | import java.util.List;
5 | import com.fasterxml.jackson.annotation.JsonAnySetter;
6 | import lombok.Data;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | @Data
11 | public class ShopifyOrdersRoot {
12 |
13 | private List orders = new LinkedList<>();
14 |
15 |
16 | /**
17 | * @param name
18 | * @param value
19 | */
20 | @JsonAnySetter
21 | public void ignored(String name, Object value) {
22 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/MetafieldsRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.LinkedList;
4 | import java.util.List;
5 | import com.fasterxml.jackson.annotation.JsonAnySetter;
6 | import lombok.Data;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | @Data
11 | public class MetafieldsRoot {
12 |
13 | private List metafields = new LinkedList<>();
14 |
15 |
16 | /**
17 | * @param name
18 | * @param value
19 | */
20 | @JsonAnySetter
21 | public void ignored(String name, Object value) {
22 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "java.configuration.updateBuildConfiguration": "automatic",
3 | "java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx4G -Xms100m -javaagent:\"/Users/devon/.vscode/extensions/gabrielbb.vscode-lombok-1.0.1/server/lombok.jar\"",
4 | "java.import.gradle.java.home": "/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home",
5 | "java.configuration.runtimes": [],
6 | "terminal.integrated.altClickMovesCursor": false,
7 | "java.compile.nullAnalysis.mode": "automatic",
8 | "githubPullRequests.ignoredPullRequestBranches": [
9 | "main"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyAccessTokenRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import lombok.Data;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | @Slf4j
9 | @Data
10 | public class ShopifyAccessTokenRoot {
11 |
12 | @JsonProperty("access_token")
13 | private String accessToken;
14 |
15 |
16 | /**
17 | * @param name
18 | * @param value
19 | */
20 | @JsonAnySetter
21 | public void ignored(String name, Object value) {
22 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyOrderRisksRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.LinkedList;
4 | import java.util.List;
5 | import com.fasterxml.jackson.annotation.JsonAnySetter;
6 | import lombok.Data;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | @Data
11 | public class ShopifyOrderRisksRoot {
12 |
13 | private List risks = new LinkedList<>();
14 |
15 |
16 | /**
17 | * @param name
18 | * @param value
19 | */
20 | @JsonAnySetter
21 | public void ignored(String name, Object value) {
22 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyLocationsRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.LinkedList;
4 | import java.util.List;
5 | import com.fasterxml.jackson.annotation.JsonAnySetter;
6 | import lombok.Data;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | @Data
11 | public class ShopifyLocationsRoot {
12 |
13 | private List locations = new LinkedList<>();
14 |
15 |
16 | /**
17 | * @param name
18 | * @param value
19 | */
20 | @JsonAnySetter
21 | public void ignored(String name, Object value) {
22 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyProductsRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.LinkedList;
4 | import java.util.List;
5 | import com.fasterxml.jackson.annotation.JsonAnySetter;
6 | import lombok.Data;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | @Data
11 | public class ShopifyProductsRoot {
12 |
13 | private List products = new LinkedList();
14 |
15 |
16 | /**
17 | * @param name
18 | * @param value
19 | */
20 | @JsonAnySetter
21 | public void ignored(String name, Object value) {
22 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyCustomersRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.LinkedList;
4 | import java.util.List;
5 | import com.fasterxml.jackson.annotation.JsonAnySetter;
6 | import lombok.Data;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | @Data
11 | public class ShopifyCustomersRoot {
12 | private List customers = new LinkedList<>();
13 |
14 |
15 | /**
16 | * @param name
17 | * @param value
18 | */
19 | @JsonAnySetter
20 | public void ignored(String name, Object value) {
21 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyGiftCardRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import lombok.Data;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | @Slf4j
9 | @Data
10 | public class ShopifyGiftCardRoot {
11 | @JsonProperty("gift_card")
12 | private ShopifyGiftCard giftCard;
13 |
14 |
15 | /**
16 | * @param name
17 | * @param value
18 | */
19 | @JsonAnySetter
20 | public void ignored(String name, Object value) {
21 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyTransactionReceipt.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import lombok.Data;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | @Slf4j
9 | @Data
10 | public class ShopifyTransactionReceipt {
11 |
12 | @JsonProperty("apple_pay")
13 | private boolean applePay;
14 |
15 |
16 | /**
17 | * @param name
18 | * @param value
19 | */
20 | @JsonAnySetter
21 | public void ignored(String name, Object value) {
22 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyAdjustmentsRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.LinkedList;
4 | import java.util.List;
5 | import com.fasterxml.jackson.annotation.JsonAnySetter;
6 | import lombok.Data;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | @Data
11 | public class ShopifyAdjustmentsRoot {
12 |
13 | private List adjustments = new LinkedList<>();
14 |
15 |
16 | /**
17 | * @param name
18 | * @param value
19 | */
20 | @JsonAnySetter
21 | public void ignored(String name, Object value) {
22 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyTransactionsRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.LinkedList;
4 | import java.util.List;
5 | import com.fasterxml.jackson.annotation.JsonAnySetter;
6 | import lombok.Data;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | @Data
11 | public class ShopifyTransactionsRoot {
12 |
13 | private List transactions = new LinkedList<>();
14 |
15 |
16 | /**
17 | * @param name
18 | * @param value
19 | */
20 | @JsonAnySetter
21 | public void ignored(String name, Object value) {
22 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyCustomCollectionRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import lombok.Data;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | @Slf4j
9 | @Data
10 | public class ShopifyCustomCollectionRoot {
11 |
12 | @JsonProperty("custom_collection")
13 | private ShopifyCustomCollection customCollection;
14 |
15 |
16 | /**
17 | * @param name
18 | * @param value
19 | */
20 | @JsonAnySetter
21 | public void ignored(String name, Object value) {
22 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyShippingLine.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.math.BigDecimal;
4 | import com.fasterxml.jackson.annotation.JsonAnySetter;
5 | import lombok.Data;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | @Slf4j
9 | @Data
10 | public class ShopifyShippingLine {
11 |
12 | private String id;
13 | private String title;
14 | private BigDecimal price;
15 | private String code;
16 | private String source;
17 |
18 |
19 | /**
20 | * @param name
21 | * @param value
22 | */
23 | @JsonAnySetter
24 | public void ignored(String name, Object value) {
25 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyRecurringApplicationChargeRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import lombok.Data;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | @Slf4j
9 | @Data
10 | public class ShopifyRecurringApplicationChargeRoot {
11 |
12 | @JsonProperty("recurring_application_charge")
13 | private ShopifyRecurringApplicationCharge recurringApplicationCharge;
14 |
15 |
16 | /**
17 | * @param name
18 | * @param value
19 | */
20 | @JsonAnySetter
21 | public void ignored(String name, Object value) {
22 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyVariantRequestPositionComparator.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.Comparator;
4 |
5 | public class ShopifyVariantRequestPositionComparator implements Comparator
6 |
7 | {
8 |
9 | /**
10 | * @param shopifyVariantRequest
11 | * @param otherShopifyVariantRequest
12 | * @return int
13 | */
14 | @Override
15 | public int compare(final ShopifyVariantRequest shopifyVariantRequest, final ShopifyVariantRequest otherShopifyVariantRequest) {
16 | final int position1 = shopifyVariantRequest.getRequest().getPosition();
17 | final int position2 = otherShopifyVariantRequest.getRequest().getPosition();
18 | return position1 - position2;
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyInventoryLevel.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import lombok.Data;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | @Slf4j
9 | @Data
10 | public class ShopifyInventoryLevel {
11 |
12 | @JsonProperty("inventory_item_id")
13 | private String inventoryItemId;
14 |
15 | @JsonProperty("location_id")
16 | private String locationId;
17 |
18 | private long available;
19 |
20 |
21 | /**
22 | * @param name
23 | * @param value
24 | */
25 | @JsonAnySetter
26 | public void ignored(String name, Object value) {
27 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "spring-shopify-react-app",
3 | "description": "Sample application using React with Spring Boot for Embedded Shopify App",
4 | "dependencies": {
5 | "@babel/core": "^7.17.5",
6 | "@babel/preset-env": "^7.12.13",
7 | "@babel/preset-react": "^7.12.13",
8 | "@babel/runtime": "^7.17.2",
9 | "@shopify/app-bridge": "^3.7.9",
10 | "@shopify/app-bridge-react": "^3.7.9",
11 | "@shopify/app-bridge-utils": "^3.5.1",
12 | "@shopify/polaris": "^11.20.0",
13 | "babel-loader": "^9.1.3",
14 | "buffer": "^6.0.3",
15 | "graphql": "^16.8.1",
16 | "react": "^18.2.0",
17 | "react-dom": "^18.2.0",
18 | "webpack": "^5.94.0",
19 | "webpack-cli": "^5.1.4"
20 | },
21 | "devDependencies": {
22 | "@babel/plugin-transform-runtime": "^7.17.0"
23 | }
24 | }
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyCustomCollectionsRoot.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.LinkedList;
4 | import java.util.List;
5 | import com.fasterxml.jackson.annotation.JsonAnySetter;
6 | import com.fasterxml.jackson.annotation.JsonProperty;
7 | import lombok.Data;
8 | import lombok.extern.slf4j.Slf4j;
9 |
10 | @Slf4j
11 | @Data
12 | public class ShopifyCustomCollectionsRoot {
13 |
14 | @JsonProperty("custom_collections")
15 | private List customCollections = new LinkedList();
16 |
17 |
18 | /**
19 | * @param name
20 | * @param value
21 | */
22 | @JsonAnySetter
23 | public void ignored(String name, Object value) {
24 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/auth/persistence/model/AuthorizedClientId.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.auth.persistence.model;
2 |
3 | import java.io.Serializable;
4 |
5 | import lombok.Data;
6 |
7 | /**
8 | * This class is to provide a composite (multi-column) id for the Authorized Client model's table.
9 | */
10 | @Data
11 | public class AuthorizedClientId implements Serializable {
12 |
13 | /**
14 | * Generated SerialVersionUID
15 | */
16 | private static final long serialVersionUID = 1L;
17 |
18 | private String clientRegistrationId;
19 |
20 | private String principalName;
21 |
22 | public AuthorizedClientId(String clientRegistrationId, String principalName) {
23 | this.clientRegistrationId = clientRegistrationId;
24 | this.principalName = principalName;
25 | }
26 |
27 | public AuthorizedClientId() {}
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/exceptions/ShopifyErrorCode.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.exceptions;
2 |
3 | import java.io.Serializable;
4 |
5 | public class ShopifyErrorCode implements Serializable {
6 |
7 | private static final long serialVersionUID = -3870975240510101019L;
8 |
9 | public enum Type {
10 | SHIPPING_ADDRESS, UNKNOWN
11 | }
12 |
13 | private final Type type;
14 | private final String message;
15 |
16 | public ShopifyErrorCode(final Type type, final String message) {
17 | this.type = type;
18 | this.message = message;
19 | }
20 |
21 |
22 | /**
23 | * @return Type
24 | */
25 | public Type getType() {
26 | return type;
27 | }
28 |
29 |
30 | /**
31 | * @return String
32 | */
33 | public String getMessage() {
34 | return message;
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/InventoryPolicy.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | public enum InventoryPolicy {
4 |
5 | DENY("deny"), CONTINUE("continue");
6 |
7 | static final String NO_MATCHING_ENUMS_ERROR_MESSAGE = "No matching enum found for %s";
8 | private final String value;
9 |
10 | private InventoryPolicy(final String value) {
11 | this.value = value;
12 | }
13 |
14 | public static InventoryPolicy toEnum(String value) {
15 | if (DENY.toString().equals(value)) {
16 | return InventoryPolicy.DENY;
17 | } else if (CONTINUE.toString().equals(value)) {
18 | return InventoryPolicy.CONTINUE;
19 | }
20 | throw new IllegalArgumentException(String.format(NO_MATCHING_ENUMS_ERROR_MESSAGE, value));
21 | }
22 |
23 | @Override
24 | public String toString() {
25 | return value;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyRefundShippingDetails.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.math.BigDecimal;
4 | import com.fasterxml.jackson.annotation.JsonAnySetter;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 | import lombok.Data;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | @Data
11 | public class ShopifyRefundShippingDetails {
12 |
13 | private BigDecimal amount;
14 | private BigDecimal tax;
15 | @JsonProperty("maximum_refundable")
16 | private BigDecimal maximumRefundable;
17 | @JsonProperty("full_refund")
18 | private boolean fullRefund;
19 |
20 |
21 | /**
22 | * @param name
23 | * @param value
24 | */
25 | @JsonAnySetter
26 | public void ignored(String name, Object value) {
27 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/MetafieldValueType.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | public enum MetafieldValueType {
4 |
5 | STRING("string"), INTEGER("integer");
6 |
7 | static final String NO_MATCHING_ENUMS_ERROR_MESSAGE = "No matching enum found for %s";
8 | private final String value;
9 |
10 | private MetafieldValueType(final String value) {
11 | this.value = value;
12 | }
13 |
14 | public static MetafieldValueType toEnum(final String value) {
15 | if (STRING.toString().equals(value)) {
16 | return MetafieldValueType.STRING;
17 | } else if (INTEGER.toString().equals(value)) {
18 | return MetafieldValueType.INTEGER;
19 | }
20 | throw new IllegalArgumentException(String.format(NO_MATCHING_ENUMS_ERROR_MESSAGE, value));
21 | }
22 |
23 | @Override
24 | public String toString() {
25 | return value;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/graphql/model/Products.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.graphql.model;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 | import com.fasterxml.jackson.annotation.JsonRootName;
7 | import lombok.Data;
8 |
9 | @Data
10 | @JsonRootName(value = "products")
11 | public class Products {
12 |
13 | public static String NODE_NAME = "products";
14 |
15 | @JsonProperty("edges")
16 | private ArrayList productNodes;
17 |
18 |
19 | /**
20 | * @return List
21 | */
22 | public List getProducts() {
23 | List products = new ArrayList();
24 | for (ProductNode productNode : productNodes) {
25 | products.add(productNode.getProduct());
26 | }
27 | return products;
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyVariantRequestOption1Comparator.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.Comparator;
4 |
5 | import org.apache.commons.lang3.ObjectUtils;
6 |
7 | public class ShopifyVariantRequestOption1Comparator implements Comparator {
8 |
9 | /**
10 | * @param shopifyVariantRequest
11 | * @param otherShopifyVariantRequest
12 | * @return int
13 | */
14 | @Override
15 | public int compare(final ShopifyVariantRequest shopifyVariantRequest, final ShopifyVariantRequest otherShopifyVariantRequest) {
16 | final String option1 = shopifyVariantRequest.getRequest().getOption1();
17 | final String otherOption1 = otherShopifyVariantRequest.getRequest().getOption1();
18 | return (option1 == null || otherOption1 == null) ? ObjectUtils.compare(option1, otherOption1) : option1.compareToIgnoreCase(otherOption1);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyAdjustment.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.math.BigDecimal;
4 | import com.fasterxml.jackson.annotation.JsonAnySetter;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 | import lombok.Data;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | @Data
11 | public class ShopifyAdjustment {
12 |
13 | private String id;
14 | @JsonProperty("order_id")
15 | private String orderId;
16 | @JsonProperty("refund_id")
17 | private String refundId;
18 | private BigDecimal amount;
19 | @JsonProperty("tax_amount")
20 | private BigDecimal taxAmount;
21 | private String kind;
22 | private String reason;
23 |
24 |
25 | /**
26 | * @param name
27 | * @param value
28 | */
29 | @JsonAnySetter
30 | public void ignored(String name, Object value) {
31 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/graphql/model/InputWrapper.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.graphql.model;
2 |
3 | import java.util.Map;
4 | import com.fasterxml.jackson.core.JsonProcessingException;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import lombok.Data;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | @Data
11 | public class InputWrapper {
12 |
13 | private Map input;
14 |
15 | public InputWrapper(Map input) {
16 | this.input = input;
17 | }
18 |
19 | public InputWrapper() {}
20 |
21 | @SuppressWarnings("unchecked")
22 | public InputWrapper(String jsonString) {
23 | ObjectMapper mapper = new ObjectMapper();
24 | try {
25 | this.input = mapper.readValue(jsonString, Map.class);
26 | } catch (JsonProcessingException e) {
27 | log.error("Error while parsing json string", e);
28 | }
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyErrors.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.LinkedList;
4 | import java.util.List;
5 | import com.fasterxml.jackson.annotation.JsonAnySetter;
6 | import com.fasterxml.jackson.annotation.JsonProperty;
7 | import lombok.Data;
8 | import lombok.extern.slf4j.Slf4j;
9 |
10 | @Slf4j
11 | @Data
12 | public class ShopifyErrors {
13 |
14 | private String errorMessage;
15 |
16 | public ShopifyErrors() {
17 | super();
18 | }
19 |
20 | public ShopifyErrors(String errorMessage) {
21 | this.errorMessage = errorMessage;
22 | }
23 |
24 |
25 |
26 | @JsonProperty("shipping_address")
27 | private List shippingAddressErrors = new LinkedList<>();
28 |
29 |
30 | /**
31 | * @param name
32 | * @param value
33 | */
34 | @JsonAnySetter
35 | public void ignored(String name, Object value) {
36 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/serializer/CurrencySerializer.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model.serializer;
2 |
3 | import java.io.IOException;
4 | import java.util.Currency;
5 | import com.fasterxml.jackson.core.JsonGenerator;
6 | import com.fasterxml.jackson.databind.SerializerProvider;
7 | import com.fasterxml.jackson.databind.ser.std.StdSerializer;
8 |
9 | public class CurrencySerializer extends StdSerializer {
10 |
11 | public CurrencySerializer() {
12 | this(Currency.class);
13 | }
14 |
15 | protected CurrencySerializer(Class t) {
16 | super(t);
17 | }
18 |
19 |
20 | /**
21 | * @param value
22 | * @param gen
23 | * @param provider
24 | * @throws IOException
25 | */
26 | @Override
27 | public void serialize(Currency value, JsonGenerator gen, SerializerProvider provider) throws IOException {
28 | gen.writeString(value.getCurrencyCode());
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/OrderRiskRecommendation.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | public enum OrderRiskRecommendation {
4 |
5 | ACCEPT("accept"), INVESTIGATE("investigate"), CANCEL("cancel");
6 |
7 | static final String NO_MATCHING_ENUMS_ERROR_MESSAGE = "No matching enum found for %s";
8 | private final String value;
9 |
10 | private OrderRiskRecommendation(final String value) {
11 | this.value = value;
12 | }
13 |
14 | public static OrderRiskRecommendation toEnum(String value) {
15 | if (ACCEPT.toString().equals(value)) {
16 | return OrderRiskRecommendation.ACCEPT;
17 | } else if (INVESTIGATE.toString().equals(value)) {
18 | return OrderRiskRecommendation.INVESTIGATE;
19 | } else if (CANCEL.toString().equals(value)) {
20 | return OrderRiskRecommendation.CANCEL;
21 | }
22 | throw new IllegalArgumentException(String.format(NO_MATCHING_ENUMS_ERROR_MESSAGE, value));
23 | }
24 |
25 | @Override
26 | public String toString() {
27 | return value;
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyRefundLineItem.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.math.BigDecimal;
4 | import com.fasterxml.jackson.annotation.JsonAnySetter;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 | import lombok.Data;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | @Data
11 | public class ShopifyRefundLineItem {
12 |
13 | private String id;
14 | private long quantity;
15 | @JsonProperty("line_item_id")
16 | private String lineItemId;
17 | @JsonProperty("location_id")
18 | private String locationId;
19 | @JsonProperty("restock_type")
20 | private String restockType;
21 | private BigDecimal subtotal;
22 | @JsonProperty("total_tax")
23 | private BigDecimal totalTax;
24 | @JsonProperty("line_item")
25 | private ShopifyLineItem lineItem;
26 |
27 |
28 | /**
29 | * @param name
30 | * @param value
31 | */
32 | @JsonAnySetter
33 | public void ignored(String name, Object value) {
34 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyLocation.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import lombok.Data;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | @Slf4j
9 | @Data
10 | public class ShopifyLocation {
11 |
12 | private String id;
13 | private String name;
14 | private String address1;
15 | private String address2;
16 | private String city;
17 | private String zip;
18 | private String country;
19 | private String phone;
20 | private String province;
21 |
22 | @JsonProperty("country_code")
23 | private String countryCode;
24 |
25 | @JsonProperty("country_name")
26 | private String countryName;
27 |
28 | @JsonProperty("province_code")
29 | private String provinceCode;
30 |
31 |
32 | /**
33 | * @param name
34 | * @param value
35 | */
36 | @JsonAnySetter
37 | public void ignored(String name, Object value) {
38 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/serializer/CurrencyDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model.serializer;
2 |
3 | import java.io.IOException;
4 | import java.util.Currency;
5 | import com.fasterxml.jackson.core.JsonParser;
6 | import com.fasterxml.jackson.databind.DeserializationContext;
7 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
8 |
9 | public class CurrencyDeserializer extends StdDeserializer {
10 |
11 | public CurrencyDeserializer() {
12 | super(Currency.class);
13 | }
14 |
15 | protected CurrencyDeserializer(Class> vc) {
16 | super(vc);
17 | }
18 |
19 |
20 | /**
21 | * @param jsonParser
22 | * @param deserializationContext
23 | * @return Currency
24 | * @throws IOException
25 | */
26 | @Override
27 | public Currency deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException {
28 | return Currency.getInstance(jsonParser.getText().toUpperCase());
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/serializer/EscapedStringSerializer.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model.serializer;
2 |
3 | import java.io.IOException;
4 | import com.fasterxml.jackson.core.JsonGenerator;
5 | import com.fasterxml.jackson.core.JsonProcessingException;
6 | import com.fasterxml.jackson.databind.SerializerProvider;
7 | import com.fasterxml.jackson.databind.ser.std.StdSerializer;
8 | import org.apache.commons.text.StringEscapeUtils;
9 |
10 | public class EscapedStringSerializer extends StdSerializer {
11 |
12 | public EscapedStringSerializer() {
13 | super(String.class);
14 | }
15 |
16 |
17 | /**
18 | * @param value
19 | * @param jgen
20 | * @param provider
21 | * @throws IOException
22 | * @throws JsonProcessingException
23 | */
24 | @Override
25 | public void serialize(String value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
26 | jgen.writeString(StringEscapeUtils.unescapeHtml4(value));
27 | }
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/serializer/InventoryPolicySerializer.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model.serializer;
2 |
3 | import java.io.IOException;
4 | import com.fasterxml.jackson.core.JsonGenerator;
5 | import com.fasterxml.jackson.databind.SerializerProvider;
6 | import com.fasterxml.jackson.databind.ser.std.StdSerializer;
7 | import com.justblackmagic.shopify.api.rest.model.InventoryPolicy;
8 |
9 | public class InventoryPolicySerializer extends StdSerializer {
10 |
11 | public InventoryPolicySerializer() {
12 | this(InventoryPolicy.class);
13 | }
14 |
15 | protected InventoryPolicySerializer(Class t) {
16 | super(t);
17 | }
18 |
19 |
20 | /**
21 | * @param value
22 | * @param gen
23 | * @param provider
24 | * @throws IOException
25 | */
26 | @Override
27 | public void serialize(InventoryPolicy value, JsonGenerator gen, SerializerProvider provider) throws IOException {
28 | gen.writeString(value.toString());
29 |
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/serializer/MetafieldValueTypeSerializer.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model.serializer;
2 |
3 | import java.io.IOException;
4 | import com.fasterxml.jackson.core.JsonGenerator;
5 | import com.fasterxml.jackson.databind.SerializerProvider;
6 | import com.fasterxml.jackson.databind.ser.std.StdSerializer;
7 | import com.justblackmagic.shopify.api.rest.model.MetafieldValueType;
8 |
9 | public class MetafieldValueTypeSerializer extends StdSerializer {
10 |
11 | public MetafieldValueTypeSerializer() {
12 | this(MetafieldValueType.class);
13 | }
14 |
15 | protected MetafieldValueTypeSerializer(Class t) {
16 | super(t);
17 | }
18 |
19 |
20 | /**
21 | * @param value
22 | * @param gen
23 | * @param provider
24 | * @throws IOException
25 | */
26 | @Override
27 | public void serialize(MetafieldValueType value, JsonGenerator gen, SerializerProvider provider) throws IOException {
28 | gen.writeString(value.toString());
29 |
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/Option.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.List;
4 | import com.fasterxml.jackson.annotation.JsonAnySetter;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
7 | import com.justblackmagic.shopify.api.rest.model.serializer.EscapedStringSerializer;
8 | import com.justblackmagic.shopify.api.rest.model.serializer.EscapedStringsSerializer;
9 | import lombok.Data;
10 | import lombok.extern.slf4j.Slf4j;
11 |
12 | @Slf4j
13 | @Data
14 | public class Option {
15 |
16 | public String id;
17 | @JsonProperty("product_id")
18 | public String productId;
19 | @JsonSerialize(using = EscapedStringSerializer.class)
20 | public String name;
21 | public int position;
22 | @JsonSerialize(using = EscapedStringsSerializer.class)
23 | public List values;
24 |
25 |
26 | /**
27 | * @param name
28 | * @param value
29 | */
30 | @JsonAnySetter
31 | public void ignored(String name, Object value) {
32 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/serializer/OrderRiskRecommendationSerializer.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model.serializer;
2 |
3 | import java.io.IOException;
4 | import com.fasterxml.jackson.core.JsonGenerator;
5 | import com.fasterxml.jackson.databind.SerializerProvider;
6 | import com.fasterxml.jackson.databind.ser.std.StdSerializer;
7 | import com.justblackmagic.shopify.api.rest.model.OrderRiskRecommendation;
8 |
9 | public class OrderRiskRecommendationSerializer extends StdSerializer {
10 |
11 | public OrderRiskRecommendationSerializer() {
12 | this(OrderRiskRecommendation.class);
13 | }
14 |
15 | protected OrderRiskRecommendationSerializer(Class t) {
16 | super(t);
17 | }
18 |
19 |
20 | /**
21 | * @param value
22 | * @param gen
23 | * @param provider
24 | * @throws IOException
25 | */
26 | @Override
27 | public void serialize(OrderRiskRecommendation value, JsonGenerator gen, SerializerProvider provider) throws IOException {
28 | gen.writeString(value.toString());
29 |
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/Image.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.LinkedList;
4 | import java.util.List;
5 | import com.fasterxml.jackson.annotation.JsonAnySetter;
6 | import com.fasterxml.jackson.annotation.JsonProperty;
7 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
8 | import com.justblackmagic.shopify.api.rest.model.serializer.EscapedStringSerializer;
9 | import lombok.Data;
10 | import lombok.extern.slf4j.Slf4j;
11 |
12 | @Slf4j
13 | @Data
14 | public class Image {
15 | private String id;
16 | @JsonProperty("product_id")
17 | private String productId;
18 | @JsonSerialize(using = EscapedStringSerializer.class)
19 | private String name;
20 | private int position;
21 | @JsonProperty("src")
22 | private String source;
23 | @JsonProperty("variant_ids")
24 | private List variantIds = new LinkedList<>();
25 | private List metafields = new LinkedList<>();
26 |
27 |
28 | /**
29 | * @param name
30 | * @param value
31 | */
32 | @JsonAnySetter
33 | public void ignored(String name, Object value) {
34 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/serializer/InventoryPolicyDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model.serializer;
2 |
3 | import java.io.IOException;
4 | import com.fasterxml.jackson.core.JsonParser;
5 | import com.fasterxml.jackson.core.JsonProcessingException;
6 | import com.fasterxml.jackson.databind.DeserializationContext;
7 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
8 | import com.justblackmagic.shopify.api.rest.model.InventoryPolicy;
9 |
10 | public class InventoryPolicyDeserializer extends StdDeserializer {
11 |
12 | public InventoryPolicyDeserializer() {
13 | this(InventoryPolicy.class);
14 | }
15 |
16 | protected InventoryPolicyDeserializer(Class> vc) {
17 | super(vc);
18 | }
19 |
20 |
21 | /**
22 | * @param p
23 | * @param ctxt
24 | * @return InventoryPolicy
25 | * @throws IOException
26 | * @throws JsonProcessingException
27 | */
28 | @Override
29 | public InventoryPolicy deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
30 | return InventoryPolicy.toEnum(p.getText());
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyAddress.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.math.BigDecimal;
4 | import com.fasterxml.jackson.annotation.JsonAnySetter;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 | import lombok.Data;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | @Data
11 | public class ShopifyAddress {
12 |
13 | @JsonProperty("first_name")
14 | private String firstName;
15 | @JsonProperty("last_name")
16 | private String lastname;
17 | private String name;
18 | private String company;
19 | private String address1;
20 | private String address2;
21 | private String city;
22 | private String zip;
23 | private String province;
24 | private String country;
25 | @JsonProperty("province_code")
26 | private String provinceCode;
27 | @JsonProperty("country_code")
28 | private String countryCode;
29 | private String phone;
30 | private BigDecimal latitude;
31 | private BigDecimal longitude;
32 |
33 |
34 | /**
35 | * @param name
36 | * @param value
37 | */
38 | @JsonAnySetter
39 | public void ignored(String name, Object value) {
40 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/graphql/ShopifyGraphQLClientService.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.graphql;
2 |
3 | import org.springframework.beans.factory.annotation.Value;
4 | import org.springframework.stereotype.Service;
5 | import lombok.Data;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | /*
9 | * Spring Service component which generates GraphQL client instances with the given shop name and access token, using the API version configured in
10 | * shopify.api.graphql.version property.
11 | */
12 | @Slf4j
13 | @Service
14 | @Data
15 | public class ShopifyGraphQLClientService {
16 |
17 |
18 | @Value("${shopify.api.graphql.version}")
19 | private String apiVersion = "2021-10";
20 |
21 |
22 | /**
23 | * @param shopName
24 | * @param accessToken
25 | * @return ShopifyGraphQLClient
26 | */
27 | public ShopifyGraphQLClient getShopifyGraphQLClient(final String shopName, final String accessToken) {
28 | log.debug("getShopifyGraphQLClient called with shopName: {}", shopName);
29 | log.trace("getShopifyGraphQLClient called with accessToken: {}", accessToken);
30 |
31 | return new ShopifyGraphQLClient(shopName, accessToken, apiVersion);
32 |
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/serializer/MetafieldValueTypeDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model.serializer;
2 |
3 | import java.io.IOException;
4 | import com.fasterxml.jackson.core.JsonParser;
5 | import com.fasterxml.jackson.core.JsonProcessingException;
6 | import com.fasterxml.jackson.databind.DeserializationContext;
7 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
8 | import com.justblackmagic.shopify.api.rest.model.MetafieldValueType;
9 |
10 | public class MetafieldValueTypeDeserializer extends StdDeserializer {
11 |
12 | public MetafieldValueTypeDeserializer() {
13 | this(MetafieldValueType.class);
14 | }
15 |
16 | protected MetafieldValueTypeDeserializer(Class t) {
17 | super(t);
18 | }
19 |
20 |
21 | /**
22 | * @param p
23 | * @param ctxt
24 | * @return MetafieldValueType
25 | * @throws IOException
26 | * @throws JsonProcessingException
27 | */
28 | @Override
29 | public MetafieldValueType deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
30 | return MetafieldValueType.toEnum(p.getText());
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/ShopifyRestClientService.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest;
2 |
3 |
4 | import org.springframework.beans.factory.annotation.Value;
5 | import org.springframework.stereotype.Service;
6 | import lombok.Data;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | /*
10 | * This class is a Spring Service component which generates Shopify REST client instances with the given shop name and access token, using the API
11 | * version configured in shopify.api.rest.version property.
12 | */
13 | @Slf4j
14 | @Service
15 | @Data
16 | public class ShopifyRestClientService {
17 |
18 | @Value("${shopify.api.rest.version}")
19 | private String apiVersion = "2021-10";
20 |
21 |
22 | /**
23 | * @param shopName
24 | * @param accessToken
25 | * @return ShopifyRestClient
26 | */
27 | public ShopifyRestClient getShopifyRestClient(final String shopName, final String accessToken) {
28 | log.debug("getShopifyRestClient called with shopName: {}", shopName);
29 | log.trace("getShopifyRestClient called with accessToken: {}", accessToken);
30 | return ShopifyRestClient.newBuilder().withSubdomain(shopName).withAccessToken(accessToken).withApiVersion(apiVersion).build();
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyCustomer.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.math.BigDecimal;
4 | import com.fasterxml.jackson.annotation.JsonAnySetter;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 | import org.joda.time.DateTime;
7 | import lombok.Data;
8 | import lombok.extern.slf4j.Slf4j;
9 |
10 | @Slf4j
11 | @Data
12 | public class ShopifyCustomer {
13 |
14 | private String id;
15 | private String email;
16 | @JsonProperty("accepts_marketing")
17 | private boolean acceptsMarketing;
18 | @JsonProperty("created_at")
19 |
20 | private DateTime createdAt;
21 | @JsonProperty("updated_at")
22 |
23 | private DateTime updatedAt;
24 | @JsonProperty("first_name")
25 | private String firstName;
26 | @JsonProperty("last_name")
27 | private String lastname;
28 | private String phone;
29 | @JsonProperty("orders_count")
30 | private long ordersCount;
31 | private String state;
32 | @JsonProperty("total_spent")
33 | private BigDecimal totalSpent;
34 | private String note;
35 |
36 |
37 | /**
38 | * @param name
39 | * @param value
40 | */
41 | @JsonAnySetter
42 | public void ignored(String name, Object value) {
43 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/serializer/EscapedStringsSerializer.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model.serializer;
2 |
3 | import java.io.IOException;
4 | import java.util.Collection;
5 | import com.fasterxml.jackson.core.JsonGenerator;
6 | import com.fasterxml.jackson.core.JsonProcessingException;
7 | import com.fasterxml.jackson.databind.SerializerProvider;
8 | import com.fasterxml.jackson.databind.ser.std.StdSerializer;
9 | import org.apache.commons.text.StringEscapeUtils;
10 |
11 | public class EscapedStringsSerializer extends StdSerializer> {
12 |
13 | public EscapedStringsSerializer() {
14 | this(null);
15 | }
16 |
17 | protected EscapedStringsSerializer(Class> t) {
18 | super(t);
19 | }
20 |
21 |
22 | /**
23 | * @param value
24 | * @param jgen
25 | * @param provider
26 | * @throws IOException
27 | * @throws JsonProcessingException
28 | */
29 | @Override
30 | public void serialize(Collection value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
31 | jgen.writeString((value == null) ? null : value.stream().map(StringEscapeUtils::unescapeHtml4).toString());
32 | }
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyCustomCollection.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import org.joda.time.DateTime;
6 | import lombok.Data;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | @Data
11 | public class ShopifyCustomCollection {
12 |
13 | private String id;
14 | private String title;
15 | private String handle;
16 | private boolean published;
17 |
18 | @JsonProperty("body_html")
19 | private String bodyHtml;
20 |
21 | @JsonProperty("published_scope")
22 | private String publishedScope;
23 |
24 | @JsonProperty("sort_order")
25 | private String sortOrder;
26 |
27 | @JsonProperty("template_suffix")
28 | private String templateSuffix;
29 |
30 | @JsonProperty("published_at")
31 | private DateTime publishedAt;
32 |
33 | @JsonProperty("updated_at")
34 | private DateTime updatedAt;
35 |
36 | @JsonProperty("admin_graphql_api_id")
37 | private String adminGraphqlApiId;
38 |
39 |
40 | /**
41 | * @param name
42 | * @param value
43 | */
44 | @JsonAnySetter
45 | public void ignored(String name, Object value) {
46 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/serializer/OrderRiskRecommendationDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model.serializer;
2 |
3 | import java.io.IOException;
4 | import com.fasterxml.jackson.core.JsonParser;
5 | import com.fasterxml.jackson.core.JsonProcessingException;
6 | import com.fasterxml.jackson.databind.DeserializationContext;
7 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
8 | import com.justblackmagic.shopify.api.rest.model.OrderRiskRecommendation;
9 |
10 | public class OrderRiskRecommendationDeserializer extends StdDeserializer {
11 |
12 | public OrderRiskRecommendationDeserializer() {
13 | this(OrderRiskRecommendation.class);
14 | }
15 |
16 | protected OrderRiskRecommendationDeserializer(Class t) {
17 | super(t);
18 | }
19 |
20 |
21 | /**
22 | * @param p
23 | * @param ctxt
24 | * @return OrderRiskRecommendation
25 | * @throws IOException
26 | * @throws JsonProcessingException
27 | */
28 | @Override
29 | public OrderRiskRecommendation deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
30 | return OrderRiskRecommendation.toEnum(p.getText());
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/resources/application-local-example.yml:
--------------------------------------------------------------------------------
1 | # Copy this file to application-local.yml and set your specific local test settings (e.g. Shopify Test Store Name, Shopify API key and secret, and token encryption key)
2 | debug: true
3 |
4 | spring:
5 | mvc:
6 | log-request-details: true
7 | application:
8 | admin:
9 | enabled: true
10 |
11 | logging:
12 | level:
13 | "[org.springframework.web]": DEBUG
14 | "[org.springframework.web.filter.CommonsRequestLoggingFilter]": TRACE
15 | "[org.springframework.security]": TRACE
16 | "[com.justblackmagic]": TRACE
17 | # reactor.netty.http.client: TRACE
18 |
19 | server:
20 | servlet:
21 | session:
22 | cookie.secure: false
23 | persistent: false
24 |
25 | shopify:
26 | app:
27 | hostname: $YOUR-APP-HOSTNAME
28 | embedded: true
29 | auth:
30 | client-id: $YOUR-client-id
31 | client-secret: $YOUR-client-secret
32 | tokenEncryptionKey: $YOUR-token-encryption-key - can generate here - https://www.digitalsanctuary.com/aes-key-generator-free
33 | test:
34 | storeName: $YOUR-TEST-STORE.myshopify.com
35 | security:
36 | unprotectedURIs: /,/index.html,/favicon.ico,/error,/css/*,/js/*,/dist/*,/img/*,/dash-embedded,/embedded-auth-check,/product-list
37 | authSuccessPage: /dash-embedded
38 |
39 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/auth/persistence/repository/JPAAuthorizedClientRepository.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.auth.persistence.repository;
2 |
3 | import java.util.List;
4 | import com.justblackmagic.shopify.auth.persistence.model.AuthorizedClient;
5 | import com.justblackmagic.shopify.auth.persistence.model.AuthorizedClientId;
6 | import org.springframework.data.jpa.repository.JpaRepository;
7 |
8 | /**
9 | * A simple JPA repository for {@link AuthorizedClient} entity.
10 | *
11 | * @author justblackmagic
12 | */
13 | public interface JPAAuthorizedClientRepository extends JpaRepository {
14 |
15 | /**
16 | * Find the shop that matches the full shop name provided.
17 | *
18 | * @param store The full shop name
19 | * @return The PersistedStoreAccessToken that matches the shop name, or null if not found
20 | */
21 | AuthorizedClient findByPrincipalName(String store);
22 |
23 | /**
24 | * the client reg id should probably be unique but the model does not enforce it so we have to assume we could get a List of AuthorizedClients
25 | *
26 | * @param clientRegistrationId the client registration id
27 | * @return the list of AuthorizedClients
28 | */
29 | List findByClientRegistrationId(String clientRegistrationId);
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyPage.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.ArrayList;
4 | import com.fasterxml.jackson.annotation.JsonAnySetter;
5 | import lombok.Data;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | @Slf4j
9 | @Data
10 | public class ShopifyPage extends ArrayList {
11 |
12 | private static final long serialVersionUID = 7202410951814178409L;
13 |
14 | private String nextPageInfo;
15 | private String previousPageInfo;
16 |
17 |
18 |
19 | /**
20 | * @return int
21 | */
22 | @Override
23 | public int hashCode() {
24 | final int prime = 31;
25 | int result = super.hashCode();
26 | result = prime * result + ((nextPageInfo == null) ? 0 : nextPageInfo.hashCode());
27 | result = prime * result + ((previousPageInfo == null) ? 0 : previousPageInfo.hashCode());
28 | return result;
29 | }
30 |
31 |
32 | /**
33 | * @param obj
34 | * @return boolean
35 | */
36 | @Override
37 | public boolean equals(final Object obj) {
38 | return super.equals(obj);
39 | }
40 |
41 |
42 | /**
43 | * @param name
44 | * @param value
45 | */
46 | @JsonAnySetter
47 | public void ignored(String name, Object value) {
48 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyAddressUpdateRequest.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.math.BigDecimal;
4 | import com.fasterxml.jackson.annotation.JsonAnySetter;
5 | import com.fasterxml.jackson.annotation.JsonInclude;
6 | import com.fasterxml.jackson.annotation.JsonInclude.Include;
7 | import com.fasterxml.jackson.annotation.JsonProperty;
8 | import lombok.Data;
9 | import lombok.extern.slf4j.Slf4j;
10 |
11 | @Slf4j
12 | @Data
13 | @JsonInclude(Include.ALWAYS)
14 | public class ShopifyAddressUpdateRequest {
15 |
16 | @JsonProperty("first_name")
17 | private String firstName;
18 | @JsonProperty("last_name")
19 | private String lastname;
20 | private String company;
21 | private String address1;
22 | private String address2;
23 | private String city;
24 | private String zip;
25 | private String province;
26 | private String country;
27 | @JsonProperty("province_code")
28 | private String provinceCode;
29 | @JsonProperty("country_code")
30 | private String countryCode;
31 | private String phone;
32 | private BigDecimal latitude;
33 | private BigDecimal longitude;
34 |
35 |
36 | /**
37 | * @param name
38 | * @param value
39 | */
40 | @JsonAnySetter
41 | public void ignored(String name, Object value) {
42 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ImageAltTextCreationRequest.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.Arrays;
4 | import java.util.List;
5 |
6 | public class ImageAltTextCreationRequest {
7 |
8 | static final String KEY = "alt";
9 | static final String NAMESPACE = "tags";
10 | static final MetafieldValueType VALUE_TYPE = MetafieldValueType.STRING;
11 |
12 | public static interface ImageAltTextStep {
13 | public BuildStep withImageAltText(final String imageAltText);
14 | }
15 | public static interface BuildStep {
16 | public List build();
17 | }
18 |
19 |
20 | /**
21 | * @return ImageAltTextStep
22 | */
23 | public static ImageAltTextStep newBuilder() {
24 | return new Steps();
25 | }
26 |
27 | private static class Steps implements ImageAltTextStep, BuildStep {
28 |
29 | private Metafield imageAltTextMetafield;
30 |
31 | @Override
32 | public List build() {
33 | return Arrays.asList(imageAltTextMetafield);
34 | }
35 |
36 | @Override
37 | public BuildStep withImageAltText(String imageAltText) {
38 | this.imageAltTextMetafield = new Metafield();
39 | imageAltTextMetafield.setKey(KEY);
40 | imageAltTextMetafield.setValue(imageAltText);
41 | imageAltTextMetafield.setNamespace(NAMESPACE);
42 | imageAltTextMetafield.setValueType(VALUE_TYPE);
43 | return this;
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/event/events/AppInstallEvent.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.event.events;
2 |
3 | import java.util.Locale;
4 | import org.springframework.context.ApplicationEvent;
5 | import org.springframework.scheduling.annotation.Async;
6 | import lombok.Data;
7 | import lombok.EqualsAndHashCode;
8 |
9 | /**
10 | * The AppInstallEvent class is triggered when a Shopify Shop installs our application. This event might drive data load or push actions, welcome
11 | * emails, and more.
12 | */
13 | @Async
14 | @Data
15 | @EqualsAndHashCode(callSuper = false)
16 | public class AppInstallEvent extends ApplicationEvent {
17 |
18 | /** The Constant serialVersionUID. */
19 | private static final long serialVersionUID = -7313587378037149313L;
20 |
21 | /** The app url. */
22 | private final String shopName;
23 |
24 | /** The locale. */
25 | private final Locale locale;
26 |
27 | private String appUrl;
28 |
29 | /**
30 | * Instantiates a new on registration complete event.
31 | *
32 | * @param user the user
33 | * @param locale the locale
34 | * @param appUrl the app url
35 | * @return
36 | */
37 | public AppInstallEvent(final String shopName, final Locale locale, final String appUrl) {
38 | super(shopName);
39 | this.shopName = shopName;
40 | this.locale = locale;
41 | this.appUrl = appUrl;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/mappers/ResponseEntityToStringMapper.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.mappers;
2 |
3 | import java.io.InputStream;
4 | import java.nio.charset.StandardCharsets;
5 | import org.apache.commons.io.IOUtils;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import jakarta.ws.rs.core.Response;
9 |
10 | public class ResponseEntityToStringMapper {
11 |
12 | private static final Logger LOGGER = LoggerFactory.getLogger(ResponseEntityToStringMapper.class);
13 |
14 | private ResponseEntityToStringMapper() {}
15 |
16 | /**
17 | * JAXRS Jersey Client implementation closes stream buffers when reading entity by string. To combat this and be able to read entities via a
18 | * string more than once, this deals with the input streams involved and resets where necessary.
19 | *
20 | * @param response
21 | * @return
22 | */
23 | public static String map(final Response response) {
24 |
25 | try {
26 | response.bufferEntity();
27 | final InputStream entityBytes = (InputStream) response.getEntity();
28 | final String responseBody = IOUtils.toString(entityBytes, StandardCharsets.UTF_8.toString());
29 | entityBytes.reset();
30 | return responseBody;
31 | } catch (final Exception e) {
32 | LOGGER.error("There was an error parsing response body on response with status {}, returning null", response.getStatus());
33 | return null;
34 | }
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/Webhook.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
6 | import com.fasterxml.jackson.annotation.JsonTypeName;
7 | import org.joda.time.DateTime;
8 | import org.springframework.data.annotation.ReadOnlyProperty;
9 | import lombok.Data;
10 | import lombok.extern.slf4j.Slf4j;
11 |
12 | @Slf4j
13 | @Data
14 | @JsonTypeName(value = "webhook")
15 | @JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
16 | public class Webhook {
17 |
18 | private String topic;
19 |
20 | private String address;
21 |
22 | private String format;
23 |
24 | private String[] fields;
25 |
26 | private String[] metafieldNamespaces;
27 |
28 | @ReadOnlyProperty
29 | private int id;
30 |
31 | @ReadOnlyProperty
32 | @JsonProperty("api_version")
33 | private String apiVersion;
34 |
35 | @JsonProperty("created_at")
36 | private DateTime createdAt;
37 |
38 | @JsonProperty("updated_at")
39 | private DateTime updatedAt;
40 |
41 |
42 |
43 | /**
44 | * @param name
45 | * @param value
46 | */
47 | @JsonAnySetter
48 | public void ignored(String name, Object value) {
49 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/serializer/TagsDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model.serializer;
2 |
3 | import java.io.IOException;
4 | import java.util.Arrays;
5 | import java.util.Collections;
6 | import java.util.HashSet;
7 | import java.util.Set;
8 | import com.fasterxml.jackson.core.JsonParser;
9 | import com.fasterxml.jackson.core.JsonProcessingException;
10 | import com.fasterxml.jackson.databind.DeserializationContext;
11 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
12 | import org.apache.commons.lang3.StringUtils;
13 |
14 | public class TagsDeserializer extends StdDeserializer> {
15 |
16 |
17 | public TagsDeserializer() {
18 | this(null);
19 | }
20 |
21 | protected TagsDeserializer(Class> t) {
22 | super(t);
23 | }
24 |
25 |
26 | /**
27 | * @param p
28 | * @param ctxt
29 | * @return Set
30 | * @throws IOException
31 | * @throws JsonProcessingException
32 | */
33 | @Override
34 | public Set deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
35 | String tags = p.getText();
36 | if (StringUtils.isBlank(tags)) {
37 | return Collections.emptySet();
38 | }
39 | final String[] tagArray = tags.split(TagsSerializer.TAG_SERIALIZATION_DELIMITTER);
40 | return new HashSet<>(Arrays.asList(tagArray));
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/Metafield.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnySetter;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
6 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
7 | import com.justblackmagic.shopify.api.rest.model.serializer.MetafieldValueTypeDeserializer;
8 | import com.justblackmagic.shopify.api.rest.model.serializer.MetafieldValueTypeSerializer;
9 | import org.joda.time.DateTime;
10 | import lombok.Data;
11 | import lombok.extern.slf4j.Slf4j;
12 |
13 | @Slf4j
14 | @Data
15 | public class Metafield {
16 | private String id;
17 | private String key;
18 | private String value;
19 | @JsonProperty("value_type")
20 | @JsonSerialize(using = MetafieldValueTypeSerializer.class)
21 | @JsonDeserialize(using = MetafieldValueTypeDeserializer.class)
22 | private MetafieldValueType valueType;
23 | private String namespace;
24 | @JsonProperty("owner_id")
25 | private String ownerId;
26 | @JsonProperty("owner_resource")
27 | private String ownerResource;
28 | @JsonProperty("created_at")
29 | private DateTime createdAt;
30 | @JsonProperty("updated_at")
31 | private DateTime updatedAt;
32 |
33 |
34 | /**
35 | * @param name
36 | * @param value
37 | */
38 | @JsonAnySetter
39 | public void ignored(String name, Object value) {
40 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyTransaction.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.math.BigDecimal;
4 | import java.util.Currency;
5 | import com.fasterxml.jackson.annotation.JsonAnySetter;
6 | import com.fasterxml.jackson.annotation.JsonProperty;
7 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
8 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
9 | import com.justblackmagic.shopify.api.rest.model.serializer.CurrencyDeserializer;
10 | import com.justblackmagic.shopify.api.rest.model.serializer.CurrencySerializer;
11 | import lombok.Data;
12 | import lombok.extern.slf4j.Slf4j;
13 |
14 | @Slf4j
15 | @Data
16 | public class ShopifyTransaction {
17 |
18 | private String id;
19 | @JsonProperty("order_id")
20 | private String orderId;
21 | private String kind;
22 | private String gateway;
23 | @JsonProperty("parent_id")
24 | private String parentId;
25 | private String status;
26 | private String message;
27 | private BigDecimal amount;
28 | @JsonSerialize(using = CurrencySerializer.class)
29 | @JsonDeserialize(using = CurrencyDeserializer.class)
30 | private Currency currency;
31 | @JsonProperty("maximum_refundable")
32 | private BigDecimal maximumRefundable;
33 | private ShopifyTransactionReceipt receipt;
34 |
35 |
36 | /**
37 | * @param name
38 | * @param value
39 | */
40 | @JsonAnySetter
41 | public void ignored(String name, Object value) {
42 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/auth/filter/ShopifyShopNameFilter.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.auth.filter;
2 |
3 | import java.io.IOException;
4 | import com.justblackmagic.shopify.auth.util.AuthConstants;
5 | import jakarta.servlet.Filter;
6 | import jakarta.servlet.FilterChain;
7 | import jakarta.servlet.ServletException;
8 | import jakarta.servlet.ServletRequest;
9 | import jakarta.servlet.ServletResponse;
10 | import jakarta.servlet.http.HttpServletRequest;
11 | import lombok.extern.slf4j.Slf4j;
12 |
13 | /**
14 | * Filter that grabs the Shopify shop name from the request and stores it in the session for later use.
15 | *
16 | * @author justblackmagic
17 | */
18 | @Slf4j
19 | public class ShopifyShopNameFilter implements Filter {
20 |
21 | /**
22 | * This method looks for the shop name in the request and stores it in the session.
23 | */
24 | @Override
25 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
26 | String shopName = request.getParameter(AuthConstants.SHOP_ATTRIBUE_NAME);
27 | log.debug("ShopName found: {}", shopName);
28 | if (shopName != null) {
29 | HttpServletRequest httpRequest = (HttpServletRequest) request;
30 | httpRequest.getSession().setAttribute(AuthConstants.SHOP_ATTRIBUE_NAME, shopName);
31 | request.setAttribute("shopName", shopName);
32 | log.debug("ShopName added to session.");
33 | }
34 | chain.doFilter(request, response);
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyOrderRisk.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.math.BigDecimal;
4 | import com.fasterxml.jackson.annotation.JsonAnySetter;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
7 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
8 | import com.justblackmagic.shopify.api.rest.model.serializer.OrderRiskRecommendationDeserializer;
9 | import com.justblackmagic.shopify.api.rest.model.serializer.OrderRiskRecommendationSerializer;
10 | import lombok.Data;
11 | import lombok.extern.slf4j.Slf4j;
12 |
13 | @Slf4j
14 | @Data
15 | public class ShopifyOrderRisk {
16 |
17 | private String id;
18 | @JsonProperty("order_id")
19 | private String orderId;
20 | @JsonProperty("checkout_id")
21 | private String checkoutId;
22 | private String source;
23 | private BigDecimal score;
24 | @JsonSerialize(using = OrderRiskRecommendationSerializer.class)
25 | @JsonDeserialize(using = OrderRiskRecommendationDeserializer.class)
26 | private OrderRiskRecommendation recommendation;
27 | private boolean display;
28 | @JsonProperty("cause_cancel")
29 | private boolean causeCancel;
30 | private String message;
31 | @JsonProperty("merchant_message")
32 | private String merchantMessage;
33 |
34 |
35 | /**
36 | * @param name
37 | * @param value
38 | */
39 | @JsonAnySetter
40 | public void ignored(String name, Object value) {
41 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyGiftCard.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.math.BigDecimal;
4 | import com.fasterxml.jackson.annotation.JsonAnySetter;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 | import org.joda.time.DateTime;
7 | import lombok.Data;
8 | import lombok.extern.slf4j.Slf4j;
9 |
10 | @Slf4j
11 | @Data
12 | public class ShopifyGiftCard {
13 |
14 | private String id;
15 | private String note;
16 | @JsonProperty("api_client_id")
17 | private String apiClientId;
18 | private BigDecimal balance;
19 | @JsonProperty("created_at")
20 | private DateTime createdAt;
21 | @JsonProperty("initial_value")
22 | private BigDecimal initialValue;
23 | private String currency;
24 | @JsonProperty("customer_id")
25 | private String customerId;
26 | private String code;
27 | @JsonProperty("disabled_at")
28 |
29 | private DateTime disabledAt;
30 | @JsonProperty("expires_on")
31 |
32 | private DateTime expiresOn;
33 | @JsonProperty("updated_at")
34 |
35 | private DateTime updatedAt;
36 | @JsonProperty("last_characters")
37 | private String lastCharacters;
38 | @JsonProperty("line_item_id")
39 | private String lineItemId;
40 | @JsonProperty("user_id")
41 | private String userId;
42 | @JsonProperty("template_suffix")
43 | private String templateSuffix;
44 |
45 |
46 | /**
47 | * @param name
48 | * @param value
49 | */
50 | @JsonAnySetter
51 | public void ignored(String name, Object value) {
52 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/auth/persistence/model/AuthorizedClient.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.auth.persistence.model;
2 |
3 | import java.time.Instant;
4 | import java.util.Date;
5 | import java.util.Set;
6 | import org.springframework.data.annotation.CreatedDate;
7 | import org.springframework.data.jpa.domain.support.AuditingEntityListener;
8 | import com.justblackmagic.shopify.auth.util.CryptoConverter;
9 | import jakarta.persistence.Convert;
10 | import jakarta.persistence.ElementCollection;
11 | import jakarta.persistence.Entity;
12 | import jakarta.persistence.EntityListeners;
13 | import jakarta.persistence.Id;
14 | import jakarta.persistence.IdClass;
15 | import jakarta.persistence.Temporal;
16 | import jakarta.persistence.TemporalType;
17 | import lombok.Data;
18 |
19 |
20 | /**
21 | * JPA entity for persisting authorized OAuth2 clients
22 | *
23 | * @author justblackmagic
24 | */
25 | @Data
26 | @Entity
27 | @IdClass(AuthorizedClientId.class)
28 | @EntityListeners(AuditingEntityListener.class)
29 | public class AuthorizedClient {
30 | @Id
31 | private String clientRegistrationId;
32 |
33 | @Id
34 | private String principalName;
35 |
36 | private String accessTokenType;
37 |
38 | // We are encrypting the token here to avoid storing it in plain text in the database
39 | @Convert(converter = CryptoConverter.class)
40 | private String accessTokenValue;
41 |
42 | private Instant accessTokenIssuedAt;
43 |
44 | private Instant accessTokenExpiresAt;
45 |
46 | @ElementCollection(fetch = jakarta.persistence.FetchType.EAGER)
47 | private Set accessTokenScopes;
48 |
49 | @CreatedDate
50 | @Temporal(TemporalType.TIMESTAMP)
51 | private Date createdAt;
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/graphql/GraphqlSchemaReaderUtil.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.graphql;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | @Slf4j
8 | public class GraphqlSchemaReaderUtil {
9 |
10 | /**
11 | * @param filename
12 | * @return String
13 | * @throws IOException
14 | */
15 | /* Load GraphQL schema from file in the classpath. */
16 | public static String getSchemaFromFileName(final String filename) throws IOException {
17 | InputStream inputStream = GraphqlSchemaReaderUtil.class.getClassLoader().getResourceAsStream("graphql/" + filename + ".graphql");
18 | if (inputStream == null) {
19 | log.error("getSchemaFromFileName: no file found with name: {}", "graphql/" + filename + ".graphql");
20 | return null;
21 | } else {
22 | return new String(inputStream.readAllBytes());
23 | }
24 | }
25 |
26 |
27 | /**
28 | * @param filename
29 | * @return String
30 | * @throws IOException
31 | */
32 | /* Load GraphQL variables from file in the classpath. */
33 | public static String getVariablesFromFileName(final String filename) throws IOException {
34 | InputStream inputStream = GraphqlSchemaReaderUtil.class.getClassLoader().getResourceAsStream("graphql/" + filename + "Variables.json");
35 | if (inputStream == null) {
36 | log.error("getVariablesFromFileName: no file found with name: {}", "graphql/" + filename + "Variables.json");
37 | return null;
38 | } else {
39 | return new String(inputStream.readAllBytes());
40 | }
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/serializer/TagsSerializer.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model.serializer;
2 |
3 | import java.io.IOException;
4 | import java.util.Iterator;
5 | import java.util.Set;
6 | import com.fasterxml.jackson.core.JsonGenerator;
7 | import com.fasterxml.jackson.databind.SerializerProvider;
8 | import com.fasterxml.jackson.databind.ser.std.StdSerializer;
9 |
10 | public class TagsSerializer extends StdSerializer> {
11 |
12 |
13 | public static final String TAG_SERIALIZATION_DELIMITTER = ", ";
14 |
15 | public TagsSerializer() {
16 | this(null);
17 | }
18 |
19 | protected TagsSerializer(Class> t) {
20 | super(t);
21 | }
22 |
23 |
24 | /**
25 | * @param value
26 | * @param gen
27 | * @param provider
28 | * @throws IOException
29 | */
30 | @Override
31 | public void serialize(Set value, JsonGenerator gen, SerializerProvider provider) throws IOException {
32 | if ((value == null) || value.isEmpty()) {
33 | gen.writeNull();
34 | }
35 |
36 | final StringBuilder tagStringBuilder = new StringBuilder();
37 | if (value != null) {
38 | final Iterator tagIterator = value.iterator();
39 | while (tagIterator.hasNext()) {
40 | final String tag = tagIterator.next();
41 | tagStringBuilder.append(tag);
42 | if (tagIterator.hasNext()) {
43 | tagStringBuilder.append(TAG_SERIALIZATION_DELIMITTER);
44 | }
45 | }
46 | }
47 | gen.writeFieldName("tags");
48 | gen.writeString(tagStringBuilder.toString());
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/exceptions/ShopifyErrorResponseException.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.exceptions;
2 |
3 | import java.util.List;
4 | import com.justblackmagic.shopify.api.rest.mappers.ResponseEntityToStringMapper;
5 | import jakarta.ws.rs.core.Response;
6 |
7 | public class ShopifyErrorResponseException extends RuntimeException {
8 |
9 | static final String MESSAGE = "Received unexpected Response Status Code of %d\nResponse Headers of:\n%s\nResponse Body of:\n%s";
10 | private final int statusCode;
11 | private static final long serialVersionUID = 5646635633348617058L;
12 | private final String responseBody;
13 | private final List shopifyErrorCodes;
14 |
15 | public ShopifyErrorResponseException(final Response response) {
16 | super(buildMessage(response));
17 | this.responseBody = ResponseEntityToStringMapper.map(response);
18 | this.shopifyErrorCodes = ShopifyErrorCodeFactory.create(responseBody);
19 | this.statusCode = response.getStatus();
20 | }
21 |
22 |
23 | /**
24 | * @param response
25 | * @return String
26 | */
27 | private static String buildMessage(final Response response) {
28 | final String readEntity = ResponseEntityToStringMapper.map(response);
29 | return String.format(MESSAGE, response.getStatus(), response.getStringHeaders(), readEntity);
30 | }
31 |
32 |
33 | /**
34 | * @return int
35 | */
36 | public int getStatusCode() {
37 | return statusCode;
38 | }
39 |
40 |
41 | /**
42 | * @return String
43 | */
44 | public String getResponseBody() {
45 | return responseBody;
46 | }
47 |
48 |
49 | /**
50 | * @return List
51 | */
52 | public List getShopifyErrorCodes() {
53 | return shopifyErrorCodes;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyLineItem.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.math.BigDecimal;
4 | import java.util.LinkedList;
5 | import java.util.List;
6 | import com.fasterxml.jackson.annotation.JsonAnySetter;
7 | import com.fasterxml.jackson.annotation.JsonProperty;
8 | import lombok.Data;
9 | import lombok.extern.slf4j.Slf4j;
10 |
11 | @Slf4j
12 | @Data
13 | public class ShopifyLineItem {
14 |
15 | private String id;
16 | @JsonProperty("variant_id")
17 | private String variantId;
18 | private String title;
19 | private long quantity;
20 | private BigDecimal price;
21 | private long grams;
22 | private String sku;
23 | @JsonProperty("variant_title")
24 | private String variantTitle;
25 | private String vendor;
26 | @JsonProperty("product_id")
27 | private String productId;
28 | @JsonProperty("requires_shipping")
29 | private boolean requiresShipping;
30 | private boolean taxable;
31 | @JsonProperty("gift_card")
32 | private boolean giftCard;
33 | private String name;
34 | @JsonProperty("variant_inventory_management")
35 | private String variantInventoryManagement;
36 | @JsonProperty("fulfillable_quantity")
37 | private long fulfillableQuantity;
38 | @JsonProperty("total_discount")
39 | private BigDecimal totalDiscount;
40 | @JsonProperty("fulfillment_status")
41 | private String fulfillmentStatus;
42 | @JsonProperty("fulfillment_service")
43 | private String fulfillmentService;
44 | @JsonProperty("tax_lines")
45 | private List taxLines = new LinkedList<>();
46 |
47 |
48 | /**
49 | * @param name
50 | * @param value
51 | */
52 | @JsonAnySetter
53 | public void ignored(String name, Object value) {
54 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyRefund.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.Currency;
4 | import java.util.LinkedList;
5 | import java.util.List;
6 | import com.fasterxml.jackson.annotation.JsonAnySetter;
7 | import com.fasterxml.jackson.annotation.JsonProperty;
8 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
9 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
10 | import com.justblackmagic.shopify.api.rest.model.serializer.CurrencyDeserializer;
11 | import com.justblackmagic.shopify.api.rest.model.serializer.CurrencySerializer;
12 | import org.joda.time.DateTime;
13 | import lombok.Data;
14 | import lombok.extern.slf4j.Slf4j;
15 |
16 | @Slf4j
17 | @Data
18 | public class ShopifyRefund {
19 |
20 | private String id;
21 | @JsonProperty("order_id")
22 | private String orderId;
23 | @JsonProperty("created_at")
24 | private DateTime createdAt;
25 | private String note;
26 | @JsonProperty("user_id")
27 | private String userId;
28 | @JsonProperty("processed_at")
29 | private DateTime processedAt;
30 | @JsonProperty("refund_line_items")
31 | private List refundLineItems;
32 | private ShopifyRefundShippingDetails shipping;
33 | private List transactions = new LinkedList<>();
34 | @JsonProperty("order_adjustments")
35 | private List adjustments = new LinkedList<>();
36 | @JsonSerialize(using = CurrencySerializer.class)
37 | @JsonDeserialize(using = CurrencyDeserializer.class)
38 | private Currency currency;
39 |
40 |
41 | /**
42 | * @param name
43 | * @param value
44 | */
45 | @JsonAnySetter
46 | public void ignored(String name, Object value) {
47 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyRecurringApplicationCharge.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.math.BigDecimal;
4 | import com.fasterxml.jackson.annotation.JsonAnySetter;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
7 | import com.justblackmagic.shopify.api.rest.model.serializer.EscapedStringSerializer;
8 | import lombok.Data;
9 | import lombok.extern.slf4j.Slf4j;
10 |
11 | @Slf4j
12 | @Data
13 | public class ShopifyRecurringApplicationCharge {
14 |
15 | private String id;
16 | @JsonProperty("api_client_id")
17 | private String apiClientId;
18 | private String name;
19 | private String terms;
20 | private BigDecimal price;
21 | @JsonProperty("capped_amount")
22 | private BigDecimal cappedAmount;
23 | private String status;
24 | @JsonProperty("return_url")
25 | @JsonSerialize(using = EscapedStringSerializer.class)
26 | private String returnUrl;
27 | @JsonProperty("confirmation_url")
28 | @JsonSerialize(using = EscapedStringSerializer.class)
29 | private String confirmationUrl;
30 | @JsonProperty("trial_days")
31 | private int trialDays;
32 | @JsonProperty("trial_end_on")
33 | private String trialEndsOn;
34 | @JsonProperty("activated_on")
35 | private String activatedOn;
36 | @JsonProperty("billing_on")
37 | private String billingOn;
38 | @JsonProperty("cancelled_on")
39 | private String cancelledOn;
40 | @JsonProperty("created_at")
41 | private String createdAt;
42 | @JsonProperty("updated_on")
43 | private String updatedOn;
44 | private Boolean test;
45 |
46 |
47 | /**
48 | * @param name
49 | * @param value
50 | */
51 | @JsonAnySetter
52 | public void ignored(String name, Object value) {
53 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyProducts.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collection;
5 | import java.util.HashMap;
6 | import java.util.List;
7 | import java.util.Map;
8 |
9 | public class ShopifyProducts {
10 |
11 | private final Map productIdToShopifyProduct;
12 |
13 | public ShopifyProducts(final List shopifyProducts) {
14 | productIdToShopifyProduct = new HashMap<>(shopifyProducts.size());
15 | shopifyProducts.stream().forEach(shopifyProduct -> {
16 | productIdToShopifyProduct.put(shopifyProduct.getId(), shopifyProduct);
17 | });
18 | }
19 |
20 |
21 | /**
22 | * @param productId
23 | * @return ShopifyProduct
24 | */
25 | public ShopifyProduct get(final String productId) {
26 | return productIdToShopifyProduct.get(productId);
27 | }
28 |
29 |
30 | /**
31 | * @return List
32 | */
33 | public List values() {
34 | return new ArrayList<>(productIdToShopifyProduct.values());
35 | }
36 |
37 |
38 | /**
39 | * @return List
40 | */
41 | public List getVariants() {
42 | final Collection shopifyProducts = productIdToShopifyProduct.values();
43 | final List shopifyVariants = new ArrayList<>(shopifyProducts.size());
44 | for (ShopifyProduct shopifyProduct : shopifyProducts) {
45 | shopifyVariants.addAll(shopifyProduct.getVariants());
46 | }
47 | return shopifyVariants;
48 | }
49 |
50 |
51 | /**
52 | * @return int
53 | */
54 | public int size() {
55 | return productIdToShopifyProduct.size();
56 | }
57 |
58 |
59 | /**
60 | * @param productId
61 | * @return boolean
62 | */
63 | public boolean containsKey(final String productId) {
64 | return productIdToShopifyProduct.containsKey(productId);
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/auth/util/JWTUtil.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.auth.util;
2 |
3 | import java.nio.charset.StandardCharsets;
4 | import java.util.Base64;
5 | import java.util.Objects;
6 | import javax.crypto.SecretKey;
7 | import javax.crypto.spec.SecretKeySpec;
8 | import org.springframework.beans.factory.annotation.Value;
9 | import org.springframework.stereotype.Service;
10 | import io.jsonwebtoken.Claims;
11 | import io.jsonwebtoken.Jws;
12 | import io.jsonwebtoken.JwtException;
13 | import io.jsonwebtoken.Jwts;
14 | import lombok.extern.slf4j.Slf4j;
15 |
16 | @Slf4j
17 | @Service
18 | public class JWTUtil {
19 |
20 | @Value("${shopify.auth.client-secret}")
21 | private String clientSecret;
22 |
23 |
24 | /**
25 | * Retrieve the shop name from the given JWT token.
26 | *
27 | * @param token JWT token string
28 | * @return shop name
29 | * @throws JwtException if the token is invalid
30 | */
31 | public String getShopForToken(final String token) throws JwtException {
32 | Objects.requireNonNull(token, "Token cannot be null");
33 |
34 | String shop = "";
35 | try {
36 | final Jws claims = Jwts.parser().verifyWith(getSignInKey()).build().parseSignedClaims(token);
37 | String shopName = (String) claims.getPayload().get("dest");
38 | log.debug("Parsed JWT token body: {}", claims.getPayload());
39 | log.debug("Extracted shop name: {}", shopName);
40 | shop = shopName;
41 | } catch (JwtException e) {
42 | log.error("JWT exception: {}", e.getMessage());
43 | throw (e);
44 | }
45 | return shop;
46 | }
47 |
48 | private SecretKey getSignInKey() {
49 | byte[] bytes = Base64.getDecoder().decode(clientSecret.getBytes(StandardCharsets.UTF_8));
50 | return new SecretKeySpec(bytes, "HmacSHA256");
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyGiftCardCreationRequest.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.math.BigDecimal;
4 |
5 | public class ShopifyGiftCardCreationRequest {
6 |
7 | private final ShopifyGiftCard request;
8 |
9 | public static interface InitialValueStep {
10 | CodeStep withInitialValue(final BigDecimal initialValue);
11 | }
12 |
13 | public static interface CodeStep {
14 | CurrencyStep withCode(final String code);
15 |
16 | CurrencyStep withGeneratedCode();
17 | }
18 |
19 | public static interface CurrencyStep {
20 | BuildStep withCurrency(final String currency);
21 | }
22 |
23 | public static interface BuildStep {
24 | ShopifyGiftCardCreationRequest build();
25 | }
26 |
27 |
28 | /**
29 | * @return InitialValueStep
30 | */
31 | public static InitialValueStep newBuilder() {
32 | return new Steps();
33 | }
34 |
35 |
36 | /**
37 | * @return ShopifyGiftCard
38 | */
39 | public ShopifyGiftCard getRequest() {
40 | return request;
41 | }
42 |
43 | private ShopifyGiftCardCreationRequest(final ShopifyGiftCard request) {
44 | this.request = request;
45 | }
46 |
47 | private static class Steps implements InitialValueStep, CodeStep, CurrencyStep, BuildStep {
48 |
49 | private final ShopifyGiftCard request = new ShopifyGiftCard();
50 |
51 | @Override
52 | public ShopifyGiftCardCreationRequest build() {
53 | return new ShopifyGiftCardCreationRequest(request);
54 | }
55 |
56 | @Override
57 | public CurrencyStep withCode(final String code) {
58 | this.request.setCode(code);
59 | return this;
60 | }
61 |
62 | @Override
63 | public CurrencyStep withGeneratedCode() {
64 | return this;
65 | }
66 |
67 | @Override
68 | public CodeStep withInitialValue(final BigDecimal initialValue) {
69 | this.request.setInitialValue(initialValue);
70 | return this;
71 | }
72 |
73 | @Override
74 | public BuildStep withCurrency(final String currency) {
75 | this.request.setCurrency(currency);
76 | return this;
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/auth/util/CryptoConverter.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.auth.util;
2 |
3 | import java.security.Key;
4 | import java.util.Base64;
5 | import javax.crypto.Cipher;
6 | import javax.crypto.spec.SecretKeySpec;
7 | import org.springframework.beans.factory.annotation.Value;
8 | import jakarta.persistence.AttributeConverter;
9 | import jakarta.persistence.Converter;
10 | import lombok.extern.slf4j.Slf4j;
11 |
12 | /**
13 | * JPA AttributeConverter for encrypting a String value.
14 | *
15 | * @author justblackmagic
16 | *
17 | */
18 | @Slf4j
19 | @Converter
20 | public class CryptoConverter implements AttributeConverter {
21 |
22 | private static final String AES = "AES";
23 |
24 | private static final String ALGORITHM = "AES/ECB/PKCS5Padding";
25 |
26 | /**
27 | * The key used to encrypt and decrypt the data. Base64 encoded AES key with 256 bits of data.
28 | */
29 | @Value("${shopify.auth.tokenEncryptionKey}")
30 | private String encryptionKeyString;
31 |
32 |
33 | /**
34 | * @param ccNumber
35 | * @return String
36 | */
37 | @Override
38 | public String convertToDatabaseColumn(String ccNumber) {
39 | // do some encryption
40 | Key key = new SecretKeySpec(Base64.getDecoder().decode(encryptionKeyString), AES);
41 | try {
42 | Cipher c = Cipher.getInstance(ALGORITHM);
43 | c.init(Cipher.ENCRYPT_MODE, key);
44 | return Base64.getEncoder().encodeToString(c.doFinal(ccNumber.getBytes()));
45 | } catch (Exception e) {
46 | log.error("CryptoConverter.convertToDatabaseColumn: Exception!", e);
47 | throw new RuntimeException(e);
48 | }
49 | }
50 |
51 |
52 | /**
53 | * @param dbData
54 | * @return String
55 | */
56 | @Override
57 | public String convertToEntityAttribute(String dbData) {
58 | // do some decryption
59 | Key key = new SecretKeySpec(Base64.getDecoder().decode(encryptionKeyString), AES);
60 | try {
61 | Cipher c = Cipher.getInstance(ALGORITHM);
62 | c.init(Cipher.DECRYPT_MODE, key);
63 | return new String(c.doFinal(Base64.getDecoder().decode(dbData)));
64 | } catch (Exception e) {
65 | log.error("CryptoConverter.convertToEntityAttribute: Exception!", e);
66 | throw new RuntimeException(e);
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/mappers/ShopifySdkObjectMapper.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.mappers;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude.Include;
4 | import com.fasterxml.jackson.databind.AnnotationIntrospector;
5 | import com.fasterxml.jackson.databind.DeserializationFeature;
6 | import com.fasterxml.jackson.databind.MapperFeature;
7 | import com.fasterxml.jackson.databind.ObjectMapper;
8 | import com.fasterxml.jackson.databind.SerializationFeature;
9 | import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
10 | import com.fasterxml.jackson.databind.json.JsonMapper;
11 | import com.fasterxml.jackson.databind.type.TypeFactory;
12 | import com.fasterxml.jackson.datatype.joda.JodaModule;
13 | import com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector;
14 |
15 |
16 | /**
17 | * Instead of using the default Spring ObjectMapper we are using a custom one for the Shopify REST API. This way, we can customize the serialization
18 | * and deserialization process for the Shopify REST API, seperately from any Jackson based REST services we may wish to vend from our application
19 | * (which can then use the default Spring ObjectMapper).
20 | *
21 | * @author justblackmagic
22 | */
23 | public class ShopifySdkObjectMapper {
24 |
25 | private ShopifySdkObjectMapper() {}
26 |
27 |
28 | /**
29 | * @return ObjectMapper
30 | *
31 | */
32 | public static ObjectMapper buildMapper() {
33 | final AnnotationIntrospector pair = AnnotationIntrospector.pair(new JakartaXmlBindAnnotationIntrospector(TypeFactory.defaultInstance()),
34 | new JacksonAnnotationIntrospector());
35 |
36 | ObjectMapper objectMapper = JsonMapper.builder().enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
37 | .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS).configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
38 | .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).configure(MapperFeature.USE_ANNOTATIONS, true)
39 | .annotationIntrospector(pair).serializationInclusion(Include.NON_NULL).build();
40 | objectMapper.registerModule(new JodaModule());
41 | return objectMapper;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/auth/filter/FilterRegistrationConfig.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.auth.filter;
2 |
3 | import com.justblackmagic.shopify.auth.util.ShopifyHMACValidator;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.boot.web.servlet.FilterRegistrationBean;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 |
9 | /**
10 | * Filter registration configuration class is where we register our filters.
11 | *
12 | * We are doing this instead of using the @Filter annotation because we want to set URL Patterns for the filters.
13 | */
14 | @Configuration
15 | public class FilterRegistrationConfig {
16 |
17 | @Autowired
18 | private ShopifyHMACValidator shopifyHMACValidator;
19 |
20 | /**
21 | * Setting up the HMAC Validation Filter.
22 | *
23 | * @return
24 | */
25 | @Bean
26 | public FilterRegistrationBean hmacFilter() {
27 | FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
28 | registrationBean.setFilter(new HMACVerificationFilter());
29 | registrationBean.getFilter().setShopifyHMACValidator(shopifyHMACValidator);
30 | registrationBean.addUrlPatterns("/dash");
31 | registrationBean.addUrlPatterns("/login/oauth2/code/shopify");
32 | registrationBean.setOrder(-1010); // So it runs before the Spring Security OAuth2 Filter
33 | return registrationBean;
34 | }
35 |
36 | /**
37 | * Setting up the Shopify Shop Name Filter.
38 | *
39 | * This filter grabs the shop name from the request and sets it in the session.
40 | *
41 | * @return
42 | */
43 | @Bean
44 | public FilterRegistrationBean shopNameFilter() {
45 | FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
46 | registrationBean.setFilter(new ShopifyShopNameFilter());
47 | registrationBean.addUrlPatterns("/dash");
48 | registrationBean.addUrlPatterns("/dash-embedded");
49 | registrationBean.setOrder(-1000); // So it runs before the Spring Security OAuth2 Filter
50 | return registrationBean;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/auth/filter/HMACVerificationFilter.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.auth.filter;
2 |
3 | import java.io.IOException;
4 | import com.justblackmagic.shopify.auth.util.ShopifyHMACValidator;
5 | import jakarta.servlet.Filter;
6 | import jakarta.servlet.FilterChain;
7 | import jakarta.servlet.ServletException;
8 | import jakarta.servlet.ServletRequest;
9 | import jakarta.servlet.ServletResponse;
10 | import jakarta.servlet.http.HttpServletRequest;
11 | import lombok.Data;
12 | import lombok.extern.slf4j.Slf4j;
13 |
14 | /**
15 | * This Servlet Filter is responsible for verifying the authenticity of the request from Shopify using the HMAC signature.
16 | *
17 | * @author justblackmagic
18 | */
19 | @Slf4j
20 | @Data
21 | public class HMACVerificationFilter implements Filter {
22 |
23 | // Normally we'd Autowire this, but since we are using the FilterRegistrationConfig class, we have to manually inject it from there
24 | private ShopifyHMACValidator shopifyHMACValidator;
25 |
26 |
27 | /**
28 | * @param request
29 | * @param response
30 | * @param chain
31 | * @throws IOException
32 | * @throws ServletException
33 | */
34 | @Override
35 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
36 | log.debug("HMACVerificationFilter.doFilter() - called...");
37 | HttpServletRequest httpRequest = (HttpServletRequest) request;
38 | if (shopifyHMACValidator.validateHMAC(httpRequest)) {
39 | log.debug("HMACVerificationFilter.doFilter() - HMAC is valid");
40 | request.setAttribute("shopifyHMACValid", true);
41 | chain.doFilter(request, response);
42 | } else {
43 | log.error("HMACVerificationFilter.doFilter() - HMAC is not valid");
44 | request.setAttribute("shopifyHMACValid", false);
45 | // Currently HMAC validation is working for /dash requests but failing for other requests.
46 | // Until the HMAC validation logic is fixed, we will continue on....
47 | // HttpServletResponse httpResponse = (HttpServletResponse) response;
48 | // httpResponse.sendError(403, "Blocked.");
49 | chain.doFilter(request, response);
50 | }
51 |
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/exceptions/ShopifyErrorCodeFactory.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.exceptions;
2 |
3 | import java.util.LinkedList;
4 | import java.util.List;
5 | import java.util.stream.Collectors;
6 |
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import com.fasterxml.jackson.databind.ObjectMapper;
11 | import com.justblackmagic.shopify.api.rest.mappers.ShopifySdkObjectMapper;
12 | import com.justblackmagic.shopify.api.rest.model.ShopifyErrorsRoot;
13 |
14 | public class ShopifyErrorCodeFactory {
15 | private static final Logger LOGGER = LoggerFactory.getLogger(ShopifyErrorCodeFactory.class);
16 | private static final String COULD_NOT_PARSE_ERROR_RESPONSE_MESSAGE = "Could not parse error message from shopify for response body: {}";
17 | private static final String NO_VALID_ERROR_CODES_FOUND_MESSAGE = "Shopify error format is not readable %s";
18 |
19 | private ShopifyErrorCodeFactory() {}
20 |
21 |
22 | /**
23 | * @param responseBody
24 | * @return List
25 | */
26 | public static final List create(final String responseBody) {
27 | final List shopifyErrorCodes = new LinkedList<>();
28 | try {
29 | final ObjectMapper objectMapper = ShopifySdkObjectMapper.buildMapper();
30 |
31 | final ShopifyErrorsRoot shopifyErrorsRoot = objectMapper.readValue(responseBody, ShopifyErrorsRoot.class);
32 | final List shippingAddressErrorCodes = shopifyErrorsRoot.getErrors().getShippingAddressErrors().stream()
33 | .map(shippingAddress -> new ShopifyErrorCode(ShopifyErrorCode.Type.SHIPPING_ADDRESS, shippingAddress))
34 | .collect(Collectors.toList());
35 | shopifyErrorCodes.addAll(shippingAddressErrorCodes);
36 | if (shopifyErrorCodes.isEmpty()) {
37 | shopifyErrorCodes.add(new ShopifyErrorCode(ShopifyErrorCode.Type.UNKNOWN, shopifyErrorsRoot.getErrors().getErrorMessage()));
38 | }
39 | if (shopifyErrorCodes.isEmpty()) {
40 | throw new IllegalArgumentException(String.format(NO_VALID_ERROR_CODES_FOUND_MESSAGE, responseBody));
41 | }
42 | } catch (final Exception e) {
43 | final ShopifyErrorCode shopifyErrorCode = new ShopifyErrorCode(ShopifyErrorCode.Type.UNKNOWN, responseBody);
44 | shopifyErrorCodes.add(shopifyErrorCode);
45 | LOGGER.warn(COULD_NOT_PARSE_ERROR_RESPONSE_MESSAGE, responseBody, e);
46 | }
47 | return shopifyErrorCodes;
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/app/controller/webhooks/UninstallWebhook.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.app.controller.webhooks;
2 |
3 | import java.util.List;
4 | import org.springframework.http.HttpStatus;
5 | import org.springframework.http.MediaType;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.PostMapping;
8 | import org.springframework.web.bind.annotation.RequestBody;
9 | import org.springframework.web.bind.annotation.RequestParam;
10 | import org.springframework.web.bind.annotation.RestController;
11 | import com.justblackmagic.shopify.auth.persistence.model.AuthorizedClient;
12 | import com.justblackmagic.shopify.auth.persistence.repository.JPAAuthorizedClientRepository;
13 | import com.justblackmagic.shopify.auth.util.ShopifyHMACValidator;
14 | import jakarta.persistence.EntityManager;
15 | import jakarta.servlet.http.HttpServletRequest;
16 | import jakarta.transaction.Transactional;
17 | import lombok.extern.slf4j.Slf4j;
18 |
19 | @Slf4j
20 | @RestController
21 | public class UninstallWebhook {
22 |
23 | private final JPAAuthorizedClientRepository authorizedClientRepository;
24 | private final ShopifyHMACValidator shopifyHMACValidator;
25 | private final EntityManager entityManager;
26 |
27 | public UninstallWebhook(JPAAuthorizedClientRepository authorizedClientRepository, ShopifyHMACValidator shopifyHMACValidator,
28 | EntityManager entityManager) {
29 | this.authorizedClientRepository = authorizedClientRepository;
30 | this.shopifyHMACValidator = shopifyHMACValidator;
31 | this.entityManager = entityManager;
32 | }
33 |
34 | @Transactional
35 | @PostMapping(value = "/webhook/uninstall", produces = MediaType.APPLICATION_JSON_VALUE)
36 | public ResponseEntity uninstallApp(HttpServletRequest request, @RequestBody String requestBody, @RequestParam String id) {
37 | log.debug("request: {}", request);
38 | log.debug("id: {}", id);
39 |
40 | if (!shopifyHMACValidator.validatePostHMAC(request, requestBody)) {
41 | return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
42 | }
43 |
44 | if (id == null) {
45 | return ResponseEntity.ok("{\"status\":\"ok\"}");
46 | }
47 |
48 | List clients = authorizedClientRepository.findByClientRegistrationId(id);
49 | clients.forEach(entityManager::remove);
50 | return ResponseEntity.ok("{\"message\": \"success\"}");
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/additional-spring-configuration-metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "properties": [
3 | {
4 | "name": "shopify.app.hostname",
5 | "type": "java.lang.String",
6 | "description": "A description for 'shopify.app.hostname'"
7 | },
8 | {
9 | "name": "shopify.api.rest.version",
10 | "type": "java.lang.String",
11 | "description": "A description for 'shopify.api.rest.version'"
12 | },
13 | {
14 | "name": "shopify.auth.token-encryption-key",
15 | "type": "java.lang.String",
16 | "description": "A description for 'shopify.auth.token-encryption-key'"
17 | },
18 | {
19 | "name": "shopify.auth.client-id",
20 | "type": "java.lang.String",
21 | "description": "A description for 'shopify.auth.client-id'"
22 | },
23 | {
24 | "name": "shopify.auth.client-secret",
25 | "type": "java.lang.String",
26 | "description": "A description for 'shopify.auth.client-secret'"
27 | },
28 | {
29 | "name": "shopify.security.unprotectedURIs",
30 | "type": "java.lang.String",
31 | "description": "A description for 'shopify.security.unprotectedURIs'"
32 | },
33 | {
34 | "name": "shopify.security.authSuccessPage",
35 | "type": "java.lang.String",
36 | "description": "A description for 'shopify.security.authSuccessPag'"
37 | },
38 | {
39 | "name": "shopify.api.graphql.version",
40 | "type": "java.lang.String",
41 | "description": "A description for 'shopify.api.graphql.version'"
42 | },
43 | {
44 | "name": "shopify.app.embedded",
45 | "type": "java.lang.String",
46 | "description": "A description for 'shopify.app.embedded'"
47 | },
48 | {
49 | "name": "shopify.app.embedded",
50 | "type": "java.lang.String",
51 | "description": "A description for 'shopify.app.embedded'"
52 | },
53 | {
54 | "name": "shopify.test.storeName",
55 | "type": "java.lang.String",
56 | "description": "A description for 'shopify.test'"
57 | },
58 | {
59 | "name": "spring.thymeleaf.template-loader-path",
60 | "type": "java.lang.String",
61 | "description": "A description for 'spring.thymeleaf.template-loader-path'"
62 | }
63 | ]
64 | }
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/Shop.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.Date;
4 | import java.util.List;
5 | import com.fasterxml.jackson.annotation.JsonAnySetter;
6 | import lombok.Data;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | @Data
11 | public class Shop {
12 | public String address1;
13 | public String address2;
14 | public Boolean auto_configure_tax_inclusivity;
15 | public boolean checkout_api_supported;
16 | public String city;
17 | public String country;
18 | public String country_code;
19 | public String country_name;
20 | public Boolean county_taxes;
21 | public Date created_at;
22 | public String customer_email;
23 | public String currency;
24 | public String domain;
25 | public List enabled_presentment_currencies;
26 | public boolean eligible_for_card_reader_giveaway;
27 | public boolean eligible_for_payments;
28 | public String email;
29 | public boolean finances;
30 |
31 | @Deprecated
32 | public boolean force_ssl;
33 | public String google_apps_domain;
34 | public Boolean google_apps_login_enabled;
35 | public boolean has_discounts;
36 | public boolean has_gift_cards;
37 | public boolean has_storefront;
38 | public String iana_timezone;
39 | public String id;
40 | public double latitude;
41 | public double longitude;
42 | public String money_format;
43 | public String money_in_emails_format;
44 | public String money_with_currency_format;
45 | public String money_with_currency_in_emails_format;
46 | public boolean multi_location_enabled;
47 | public String myshopify_domain;
48 | public String name;
49 | public boolean password_enabled;
50 | public String phone;
51 | public String plan_display_name;
52 | public boolean pre_launch_enabled;
53 | public String cookie_consent_level;
54 | public String plan_name;
55 | public String primary_locale;
56 | public String primary_location_id;
57 | public String province;
58 | public String province_code;
59 | public boolean requires_extra_payments_agreement;
60 | public boolean setup_required;
61 | public String shop_owner;
62 | public String source;
63 | public Boolean taxes_included;
64 | public boolean tax_shipping;
65 | public String timezone;
66 | public Date updated_at;
67 | public String visitor_tracking_consent_preference;
68 | public String weight_unit;
69 | public String zip;
70 |
71 |
72 | /**
73 | * @param name
74 | * @param value
75 | */
76 | @JsonAnySetter
77 | public void ignored(String name, Object value) {
78 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | ---
2 | logging:
3 | file:
4 | name: /tmp/shopify-test.log
5 |
6 | server:
7 | address: 0.0.0.0
8 | tomcat:
9 | remoteip:
10 | protocol-header: x-forwarded-proto
11 | remote-ip-header: x-forwarded-for
12 |
13 | shopify:
14 | api:
15 | graphql:
16 | version: 2021-10
17 | rest:
18 | version: 2021-10
19 | app:
20 | hostname: https://${SHOPIFY_APP_HOSTNAME}
21 | embedded: false # Set this to true if your App UI should be embedded in the Shopify Admin
22 | auth:
23 | client-id: # Your Shopify App Client Id
24 | client-secret: # Your Shopify App Client Secret
25 | tokenEncryptionKey: # Your encryption key, a 256 bit AES key, Base64 Encoded. You can get one here - https://www.digitalsanctuary.com/aes-key-generator-free
26 | security:
27 | unprotectedURIs: /,/index.html,/favicon.ico,/error,/css/*,/js/*,/dist/*,/img/*,/webhook/*
28 | authSuccessPage: /dash # The page to redirect to after successful OAuth authentication
29 |
30 | spring:
31 | application:
32 | name: Shopify Integration Framework
33 | datasource:
34 | driverClassName: org.mariadb.jdbc.Driver
35 | password: shopifytest
36 | url: jdbc:mariadb://localhost:3306/shopifytest?createDatabaseIfNotExist=true
37 | username: shopifytest
38 | devtools:
39 | restart:
40 | enabled: true
41 | jackson:
42 | serialization:
43 | wrap-root-value: true
44 | deserialization:
45 | unwrap-root-value: true
46 | jpa:
47 | hibernate:
48 | ddl-auto: update
49 | properties:
50 | hibernate:
51 | dialect: org.hibernate.dialect.MariaDB103Dialect
52 | show-sql: false
53 | messages:
54 | basename: messages/messages
55 | security:
56 | oauth2:
57 | client:
58 | provider:
59 | shopify:
60 | authorization-uri: https://shopname.myshopify.com/admin/oauth/authorize # Do not change this
61 | token-uri: https://shopname.myshopify.com/admin/oauth/access_token # Do not change this
62 | user-info-uri: null
63 | user-name-attribute: shop
64 | registration:
65 | shopify:
66 | authorization-grant-type: authorization_code
67 | client-id: ${shopify.auth.client-id}
68 | client-secret: ${shopify.auth.client-secret}
69 | redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
70 | scope: read_products,write_products,read_price_rules,write_price_rules,read_inventory,write_inventory
71 | thymeleaf:
72 | cache: false
73 | suffix: .html
74 | template-loader-path: classpath:/templates
75 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyFulfillment.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.util.LinkedList;
4 | import java.util.List;
5 | import com.fasterxml.jackson.annotation.JsonAnySetter;
6 | import com.fasterxml.jackson.annotation.JsonProperty;
7 | import org.joda.time.DateTime;
8 | import lombok.Data;
9 | import lombok.extern.slf4j.Slf4j;
10 |
11 | @Slf4j
12 | @Data
13 | public class ShopifyFulfillment {
14 |
15 | public enum Status {
16 |
17 | PENDING("pending"), OPEN("open"), SUCCESS("success"), CANCELLED("cancelled"), ERROR("error"), FAILURE("failure");
18 |
19 | static final String NO_MATCHING_ENUMS_ERROR_MESSAGE = "No matching enum found for status: %s";
20 | private final String value;
21 |
22 | private Status(final String value) {
23 | this.value = value;
24 | }
25 |
26 | public static Status toEnum(final String value) {
27 | if (PENDING.toString().equals(value)) {
28 | return Status.PENDING;
29 | } else if (OPEN.toString().equals(value)) {
30 | return Status.OPEN;
31 | } else if (SUCCESS.toString().equals(value)) {
32 | return Status.SUCCESS;
33 | } else if (CANCELLED.toString().equals(value)) {
34 | return Status.CANCELLED;
35 | } else if (ERROR.toString().equals(value)) {
36 | return Status.ERROR;
37 | } else if (FAILURE.toString().equals(value)) {
38 | return Status.FAILURE;
39 | }
40 |
41 | throw new IllegalArgumentException(String.format(NO_MATCHING_ENUMS_ERROR_MESSAGE, value));
42 | }
43 |
44 | @Override
45 | public String toString() {
46 | return value;
47 | }
48 | }
49 |
50 | private String id;
51 | @JsonProperty("order_id")
52 | private String orderId;
53 | private String status;
54 | @JsonProperty("created_at")
55 |
56 | private DateTime createdAt;
57 | @JsonProperty("updated_at")
58 |
59 | private DateTime updatedAt;
60 | @JsonProperty("tracking_company")
61 | private String trackingCompany;
62 | @JsonProperty("tracking_number")
63 | private String trackingNumber;
64 | @JsonProperty("notify_customer")
65 | private boolean notifyCustomer;
66 | @JsonProperty("line_items")
67 | private List lineItems = new LinkedList<>();
68 | @JsonProperty("tracking_url")
69 | private String trackingUrl;
70 | @JsonProperty("tracking_urls")
71 | private List trackingUrls = new LinkedList<>();
72 | @JsonProperty("location_id")
73 | private String locationId;
74 |
75 |
76 | /**
77 | * @param name
78 | * @param value
79 | */
80 | @JsonAnySetter
81 | public void ignored(String name, Object value) {
82 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/resources/templates/layout/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 | Polaris
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
40 |
41 |
42 |
43 |
44 | Page 1
45 | Main content of Page 1
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/app/controller/webhooks/GDPRShopDeleteWebhook.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.app.controller.webhooks;
2 |
3 | import java.io.IOException;
4 | import org.apache.commons.lang3.StringUtils;
5 | import org.springframework.http.HttpStatus;
6 | import org.springframework.http.MediaType;
7 | import org.springframework.http.ResponseEntity;
8 | import org.springframework.web.bind.annotation.PostMapping;
9 | import org.springframework.web.bind.annotation.RequestBody;
10 | import org.springframework.web.bind.annotation.RestController;
11 | import com.fasterxml.jackson.databind.JsonNode;
12 | import com.fasterxml.jackson.databind.ObjectMapper;
13 | import com.justblackmagic.shopify.auth.util.ShopifyHMACValidator;
14 | import jakarta.servlet.http.HttpServletRequest;
15 | import jakarta.transaction.Transactional;
16 | import lombok.extern.slf4j.Slf4j;
17 |
18 | @Slf4j
19 | @RestController
20 | public class GDPRShopDeleteWebhook {
21 |
22 | private final ShopifyHMACValidator shopifyHMACValidator;
23 | private final ObjectMapper objectMapper;
24 |
25 | public GDPRShopDeleteWebhook(ShopifyHMACValidator shopifyHMACValidator, ObjectMapper objectMapper) {
26 | this.shopifyHMACValidator = shopifyHMACValidator;
27 | this.objectMapper = objectMapper;
28 | }
29 |
30 | @Transactional
31 | @PostMapping(value = "/webhook/gdpr/shop-delete", produces = MediaType.APPLICATION_JSON_VALUE)
32 | public ResponseEntity gdprShopDelete(HttpServletRequest request, @RequestBody String requestBody) {
33 | log.debug("request: {}", request);
34 |
35 |
36 | if (!shopifyHMACValidator.validatePostHMAC(request, requestBody)) {
37 | return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
38 | }
39 |
40 | try {
41 | JsonNode jsonNode = objectMapper.readTree(request.getInputStream());
42 | if (jsonNode == null) {
43 | return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
44 | }
45 |
46 | String shopDomain = jsonNode.get("shop_domain").asText();
47 | Long shopId = jsonNode.get("shop_id").asLong();
48 | if (StringUtils.isBlank(shopDomain) || shopId == null) {
49 | return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
50 | }
51 |
52 | // Delete all Shop data for this shop from your system here.....
53 |
54 | return ResponseEntity.ok("{\"status\":\"ok\"}");
55 | } catch (IOException e) {
56 | log.error("IOException while parsing request body into JSON", e);
57 | return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
58 | }
59 | }
60 | }
61 |
62 |
63 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyProductMetafieldCreationRequest.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | public class ShopifyProductMetafieldCreationRequest {
4 |
5 | private final String productId;
6 | private final Metafield request;
7 |
8 | public static interface ProductIdStep {
9 | NamespaceStep withProductId(final String productId);
10 | }
11 |
12 | public static interface NamespaceStep {
13 | KeyStep withNamespace(final String namespace);
14 | }
15 |
16 | public static interface KeyStep {
17 | ValueStep withKey(final String key);
18 | }
19 |
20 | public static interface ValueStep {
21 | ValueTypeStep withValue(final String value);
22 | }
23 |
24 | public static interface ValueTypeStep {
25 | BuildStep withValueType(final MetafieldValueType valueType);
26 | }
27 |
28 | public static interface BuildStep {
29 | ShopifyProductMetafieldCreationRequest build();
30 | }
31 |
32 |
33 | /**
34 | * @return ProductIdStep
35 | */
36 | public static ProductIdStep newBuilder() {
37 | return new Steps();
38 | }
39 |
40 |
41 | /**
42 | * @return String
43 | */
44 | public String getProductId() {
45 | return productId;
46 | }
47 |
48 |
49 | /**
50 | * @return Metafield
51 | */
52 | public Metafield getRequest() {
53 | return request;
54 | }
55 |
56 | private ShopifyProductMetafieldCreationRequest(final Steps steps) {
57 | this.productId = steps.productId;
58 | this.request = steps.request;
59 | }
60 |
61 | private static class Steps implements ProductIdStep, NamespaceStep, KeyStep, ValueStep, ValueTypeStep, BuildStep {
62 |
63 | private String productId;
64 | private Metafield request = new Metafield();
65 |
66 | @Override
67 | public ShopifyProductMetafieldCreationRequest build() {
68 | return new ShopifyProductMetafieldCreationRequest(this);
69 | }
70 |
71 | @Override
72 | public BuildStep withValueType(final MetafieldValueType valueType) {
73 | this.request.setValueType(valueType);
74 | return this;
75 | }
76 |
77 | @Override
78 | public ValueTypeStep withValue(final String value) {
79 | this.request.setValue(value);
80 | return this;
81 | }
82 |
83 | @Override
84 | public ValueStep withKey(final String key) {
85 | this.request.setKey(key);
86 | return this;
87 | }
88 |
89 | @Override
90 | public KeyStep withNamespace(final String namespace) {
91 | this.request.setNamespace(namespace);
92 | return this;
93 | }
94 |
95 | @Override
96 | public NamespaceStep withProductId(final String productId) {
97 | this.productId = productId;
98 | return this;
99 | }
100 |
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyVariantMetafieldCreationRequest.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | public class ShopifyVariantMetafieldCreationRequest {
4 |
5 | private final String variantId;
6 | private final Metafield request;
7 |
8 | public static interface VariantIdStep {
9 | NamespaceStep withVariantId(final String variantId);
10 | }
11 |
12 | public static interface NamespaceStep {
13 | KeyStep withNamespace(final String namespace);
14 | }
15 |
16 | public static interface KeyStep {
17 | ValueStep withKey(final String key);
18 | }
19 |
20 | public static interface ValueStep {
21 | ValueTypeStep withValue(final String value);
22 | }
23 |
24 | public static interface ValueTypeStep {
25 | BuildStep withValueType(final MetafieldValueType valueType);
26 | }
27 |
28 | public static interface BuildStep {
29 | ShopifyVariantMetafieldCreationRequest build();
30 | }
31 |
32 |
33 | /**
34 | * @return VariantIdStep
35 | */
36 | public static VariantIdStep newBuilder() {
37 | return new Steps();
38 | }
39 |
40 |
41 | /**
42 | * @return String
43 | */
44 | public String getVariantId() {
45 | return variantId;
46 | }
47 |
48 |
49 | /**
50 | * @return Metafield
51 | */
52 | public Metafield getRequest() {
53 | return request;
54 | }
55 |
56 | private ShopifyVariantMetafieldCreationRequest(final Steps steps) {
57 | this.variantId = steps.variantId;
58 | this.request = steps.request;
59 | }
60 |
61 | private static class Steps implements VariantIdStep, NamespaceStep, KeyStep, ValueStep, ValueTypeStep, BuildStep {
62 |
63 | private String variantId;
64 | private Metafield request = new Metafield();
65 |
66 | @Override
67 | public ShopifyVariantMetafieldCreationRequest build() {
68 | return new ShopifyVariantMetafieldCreationRequest(this);
69 | }
70 |
71 | @Override
72 | public BuildStep withValueType(final MetafieldValueType valueType) {
73 | this.request.setValueType(valueType);
74 | return this;
75 | }
76 |
77 | @Override
78 | public ValueTypeStep withValue(final String value) {
79 | this.request.setValue(value);
80 | return this;
81 | }
82 |
83 | @Override
84 | public ValueStep withKey(final String key) {
85 | this.request.setKey(key);
86 | return this;
87 | }
88 |
89 | @Override
90 | public KeyStep withNamespace(final String namespace) {
91 | this.request.setNamespace(namespace);
92 | return this;
93 | }
94 |
95 | @Override
96 | public NamespaceStep withVariantId(final String variantId) {
97 | this.variantId = variantId;
98 | return this;
99 | }
100 |
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/app/controller/webhooks/GDPRDataRequestWebhook.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.app.controller.webhooks;
2 |
3 | import java.io.IOException;
4 | import org.apache.commons.lang3.StringUtils;
5 | import org.springframework.http.HttpStatus;
6 | import org.springframework.http.MediaType;
7 | import org.springframework.http.ResponseEntity;
8 | import org.springframework.web.bind.annotation.PostMapping;
9 | import org.springframework.web.bind.annotation.RequestBody;
10 | import org.springframework.web.bind.annotation.RestController;
11 | import com.fasterxml.jackson.databind.JsonNode;
12 | import com.fasterxml.jackson.databind.ObjectMapper;
13 | import com.justblackmagic.shopify.auth.util.ShopifyHMACValidator;
14 | import jakarta.servlet.http.HttpServletRequest;
15 | import jakarta.transaction.Transactional;
16 | import lombok.extern.slf4j.Slf4j;
17 |
18 | @Slf4j
19 | @RestController
20 | public class GDPRDataRequestWebhook {
21 |
22 | private final ShopifyHMACValidator shopifyHMACValidator;
23 | private final ObjectMapper objectMapper;
24 |
25 | public GDPRDataRequestWebhook(ShopifyHMACValidator shopifyHMACValidator, ObjectMapper objectMapper) {
26 | this.shopifyHMACValidator = shopifyHMACValidator;
27 | this.objectMapper = objectMapper;
28 | }
29 |
30 | @Transactional
31 | @PostMapping(value = "/webhook/gdpr/data-request", produces = MediaType.APPLICATION_JSON_VALUE)
32 | public ResponseEntity uninstallApp(HttpServletRequest request, @RequestBody String requestBody) {
33 | log.debug("request: {}", request);
34 |
35 | if (!shopifyHMACValidator.validatePostHMAC(request, requestBody)) {
36 | return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
37 | }
38 |
39 | try {
40 | JsonNode jsonNode = objectMapper.readTree(request.getInputStream());
41 | if (jsonNode == null) {
42 | return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
43 | }
44 |
45 | String shopDomain = jsonNode.get("shop_domain").asText();
46 | Long shopId = jsonNode.get("shop_id").asLong();
47 | if (StringUtils.isBlank(shopDomain) || shopId == null) {
48 | return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
49 | }
50 |
51 | // Handle the Data Request here...
52 | // Payload reference here - https://shopify.dev/apps/webhooks/configuration/mandatory-webhooks
53 |
54 | return ResponseEntity.ok("{\"status\":\"ok\"}");
55 | } catch (IOException e) {
56 | log.error("IOException while parsing request body into JSON", e);
57 | return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
58 | }
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/app/controller/webhooks/GDPRCustomerDeleteWebhook.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.app.controller.webhooks;
2 |
3 | import java.io.IOException;
4 | import org.apache.commons.lang3.StringUtils;
5 | import org.springframework.http.HttpStatus;
6 | import org.springframework.http.MediaType;
7 | import org.springframework.http.ResponseEntity;
8 | import org.springframework.web.bind.annotation.PostMapping;
9 | import org.springframework.web.bind.annotation.RequestBody;
10 | import org.springframework.web.bind.annotation.RestController;
11 | import com.fasterxml.jackson.databind.JsonNode;
12 | import com.fasterxml.jackson.databind.ObjectMapper;
13 | import com.justblackmagic.shopify.auth.util.ShopifyHMACValidator;
14 | import jakarta.servlet.http.HttpServletRequest;
15 | import jakarta.transaction.Transactional;
16 | import lombok.extern.slf4j.Slf4j;
17 |
18 | @Slf4j
19 | @RestController
20 | public class GDPRCustomerDeleteWebhook {
21 |
22 | private final ShopifyHMACValidator shopifyHMACValidator;
23 | private final ObjectMapper objectMapper;
24 |
25 | public GDPRCustomerDeleteWebhook(ShopifyHMACValidator shopifyHMACValidator, ObjectMapper objectMapper) {
26 | this.shopifyHMACValidator = shopifyHMACValidator;
27 | this.objectMapper = objectMapper;
28 | }
29 |
30 | @Transactional
31 | @PostMapping(value = "/webhook/gdpr/customer-delete", produces = MediaType.APPLICATION_JSON_VALUE)
32 | public ResponseEntity uninstallApp(HttpServletRequest request, @RequestBody String requestBody) {
33 | log.debug("request: {}", request);
34 | if (!shopifyHMACValidator.validatePostHMAC(request, requestBody)) {
35 | return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
36 | }
37 |
38 | try {
39 | JsonNode jsonNode = objectMapper.readTree(request.getInputStream());
40 | if (jsonNode == null) {
41 | return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
42 | }
43 |
44 | String shopDomain = jsonNode.get("shop_domain").asText();
45 | Long shopId = jsonNode.get("shop_id").asLong();
46 | if (StringUtils.isBlank(shopDomain) || shopId == null) {
47 | return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
48 | }
49 |
50 | // Handle the Customer Delete here...
51 | // Payload reference here - https://shopify.dev/apps/webhooks/configuration/mandatory-webhooks
52 |
53 | return ResponseEntity.ok("{\"status\":\"ok\"}");
54 | } catch (IOException e) {
55 | log.error("IOException while parsing request body into JSON", e);
56 | return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/api/rest/model/ShopifyVariant.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.api.rest.model;
2 |
3 | import java.math.BigDecimal;
4 | import java.util.Date;
5 | import com.fasterxml.jackson.annotation.JsonAnySetter;
6 | import com.fasterxml.jackson.annotation.JsonProperty;
7 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
8 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
9 | import com.justblackmagic.shopify.api.rest.model.serializer.EscapedStringSerializer;
10 | import com.justblackmagic.shopify.api.rest.model.serializer.InventoryPolicyDeserializer;
11 | import com.justblackmagic.shopify.api.rest.model.serializer.InventoryPolicySerializer;
12 | import lombok.Data;
13 | import lombok.extern.slf4j.Slf4j;
14 |
15 | @Slf4j
16 | @Data
17 | public class ShopifyVariant {
18 |
19 | public String id;
20 |
21 | @JsonProperty("product_id")
22 | public String productId;
23 |
24 | @JsonSerialize(using = EscapedStringSerializer.class)
25 | public String title;
26 | public BigDecimal price;
27 | public String sku;
28 | public int position;
29 |
30 | @JsonProperty("inventory_policy")
31 | @JsonSerialize(using = InventoryPolicySerializer.class)
32 | @JsonDeserialize(using = InventoryPolicyDeserializer.class)
33 | public InventoryPolicy inventoryPolicy;
34 |
35 | @JsonProperty("compare_at_price")
36 | public BigDecimal compareAtPrice;
37 | @JsonProperty("fulfillment_service")
38 | public String fulfillmentService;
39 | @JsonProperty("inventory_management")
40 | public String inventoryManagement;
41 | @JsonSerialize(using = EscapedStringSerializer.class)
42 | public String option1;
43 | @JsonSerialize(using = EscapedStringSerializer.class)
44 | public String option2;
45 | @JsonSerialize(using = EscapedStringSerializer.class)
46 | public String option3;
47 | @JsonProperty("created_at")
48 | public Date createdAt;
49 | @JsonProperty("updated_at")
50 | public Date updatedAt;
51 | public boolean taxable;
52 | public String barcode;
53 | public Long grams;
54 | @JsonProperty("image_id")
55 | public String imageId;
56 | public double weight;
57 | @JsonProperty("weight_unit")
58 | public String weightUnit;
59 | @JsonProperty("inventory_item_id")
60 | public Object inventoryItemId;
61 | @JsonProperty("inventory_quantity")
62 | public Long inventoryQuantity;
63 | @JsonProperty("old_inventory_quantity")
64 | public int oldInventoryQuantity;
65 | @JsonProperty("requires_shipping")
66 | public boolean requiresShipping;
67 | @JsonProperty("admin_graphql_api_id")
68 | public String adminGraphqlApiId;
69 | public long available;
70 |
71 |
72 | /**
73 | * @param name
74 | * @param value
75 | */
76 | @JsonAnySetter
77 | public void ignored(String name, Object value) {
78 | log.debug("ShopifyRestAPI Ignored Property: {} = {}", name, value);
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/com/justblackmagic/shopify/auth/customization/CustomTokenResponseConverter.java:
--------------------------------------------------------------------------------
1 | package com.justblackmagic.shopify.auth.customization;
2 |
3 | import java.util.Arrays;
4 | import java.util.Collections;
5 | import java.util.Map;
6 | import java.util.Set;
7 | import java.util.stream.Collectors;
8 | import java.util.stream.Stream;
9 |
10 | import org.springframework.core.convert.converter.Converter;
11 | import org.springframework.security.oauth2.core.OAuth2AccessToken;
12 | import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
13 | import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
14 | import org.springframework.util.StringUtils;
15 |
16 | import lombok.extern.slf4j.Slf4j;
17 |
18 | /**
19 | * Custom token response converter. This class is used to customize the token response. Shopify returns the token but without expiration date or token
20 | * type, so to make it compatible with standard OAuth2 objects, we set up all the data here.
21 | *
22 | * @author justblackmagic
23 | */
24 | @Slf4j
25 | public class CustomTokenResponseConverter implements Converter