From 41a8ab53720f4aee2bc137660386c3a2df888a3d Mon Sep 17 00:00:00 2001 From: Maria Paktiti Date: Wed, 15 Apr 2020 19:00:09 -0500 Subject: [PATCH 1/3] refactor: use npm package for settings plugin Signed-off-by: Maria Paktiti --- jest.config.cjs | 1 + package-lock.json | 66 ++++---- package.json | 1 + src/core-services/settings/index.js | 35 ---- src/core-services/settings/mutations/index.js | 5 - .../settings/mutations/updateAppSettings.js | 62 -------- .../settings/queries/appSettings.js | 16 -- src/core-services/settings/queries/index.js | 5 - .../settings/resolvers/Mutation/index.js | 7 - .../Mutation/updateGlobalSettings.js | 26 --- .../resolvers/Mutation/updateShopSettings.js | 31 ---- .../resolvers/Query/globalSettings.js | 13 -- .../settings/resolvers/Query/index.js | 7 - .../settings/resolvers/Query/shopSettings.js | 19 --- src/core-services/settings/resolvers/index.js | 7 - src/core-services/settings/schemas/index.js | 5 - .../settings/schemas/settings.graphql | 133 ---------------- .../settings/util/settingsConfig.js | 149 ------------------ src/core-services/settings/xforms/id.js | 9 -- src/registerPlugins.js | 2 +- 20 files changed, 41 insertions(+), 558 deletions(-) delete mode 100644 src/core-services/settings/index.js delete mode 100644 src/core-services/settings/mutations/index.js delete mode 100644 src/core-services/settings/mutations/updateAppSettings.js delete mode 100644 src/core-services/settings/queries/appSettings.js delete mode 100644 src/core-services/settings/queries/index.js delete mode 100644 src/core-services/settings/resolvers/Mutation/index.js delete mode 100644 src/core-services/settings/resolvers/Mutation/updateGlobalSettings.js delete mode 100644 src/core-services/settings/resolvers/Mutation/updateShopSettings.js delete mode 100644 src/core-services/settings/resolvers/Query/globalSettings.js delete mode 100644 src/core-services/settings/resolvers/Query/index.js delete mode 100644 src/core-services/settings/resolvers/Query/shopSettings.js delete mode 100644 src/core-services/settings/resolvers/index.js delete mode 100644 src/core-services/settings/schemas/index.js delete mode 100644 src/core-services/settings/schemas/settings.graphql delete mode 100644 src/core-services/settings/util/settingsConfig.js delete mode 100644 src/core-services/settings/xforms/id.js diff --git a/jest.config.cjs b/jest.config.cjs index 543721ce587..a4ade6503af 100644 --- a/jest.config.cjs +++ b/jest.config.cjs @@ -9,6 +9,7 @@ const externalNodeModules = [ "@reactioncommerce/api-plugin-address-validation", "@reactioncommerce/api-plugin-catalogs", "@reactioncommerce/api-plugin-i18n", + "@reactioncommerce/api-plugin-settings", "@reactioncommerce/api-plugin-shops", "@reactioncommerce/api-utils", "@reactioncommerce/db-version-check", diff --git a/package-lock.json b/package-lock.json index 662d525cfd5..212e754a293 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1587,6 +1587,16 @@ "lodash": "~4.17.15" } }, + "@reactioncommerce/api-plugin-settings": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@reactioncommerce/api-plugin-settings/-/api-plugin-settings-1.0.0.tgz", + "integrity": "sha512-VMWM0XrWS6oCGMGtR/PEukNvwa8d80YEvyMmhNiukEZchc+HlM3AmewYXwj+A1lo740+elkrc/B+USh3vHgMAw==", + "requires": { + "@reactioncommerce/api-utils": "^1.9.0", + "@reactioncommerce/reaction-error": "~1.0.1", + "simpl-schema": "~1.5.6" + } + }, "@reactioncommerce/api-plugin-shops": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@reactioncommerce/api-plugin-shops/-/api-plugin-shops-1.0.0.tgz", @@ -1934,9 +1944,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.4.tgz", - "integrity": "sha512-dPs6CaRWxsfHbYDVU51VjEJaUJEcli4UI0fFMT4oWmgCvHj+j7oIxz5MLHVL0Rv++N004c21ylJNdWQvPkkb5w==", + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.5.tgz", + "integrity": "sha512-578YH5Lt88AKoADy0b2jQGwJtrBxezXtVe/MBqWXKZpqx91SnC0pVkVCcxcytz3lWW+cHBYDi3Ysh0WXc+rAYw==", "requires": { "@types/node": "*", "@types/range-parser": "*" @@ -3234,9 +3244,9 @@ }, "dependencies": { "buffer": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.5.0.tgz", - "integrity": "sha512-9FTEDjLjwoAkEwyMGDjYJQN2gfRgOKBKRfiglhvibGbpeeU/pQn1bJxQqm32OD/AIeEuHxU9roxXxg34Byp/Ww==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" @@ -3593,9 +3603,9 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" }, "caniuse-lite": { - "version": "1.0.30001041", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001041.tgz", - "integrity": "sha512-fqDtRCApddNrQuBxBS7kEiSGdBsgO4wiVw4G/IClfqzfhW45MbTumfN4cuUJGTM0YGFNn97DCXPJ683PS6zwvA==", + "version": "1.0.30001042", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001042.tgz", + "integrity": "sha512-igMQ4dlqnf4tWv0xjaaE02op9AJ2oQzXKjWf4EuAHFN694Uo9/EfPVIPJcmn2WkU9RqozCxx5e2KPcVClHDbDw==", "dev": true }, "capture-exit": { @@ -5138,9 +5148,9 @@ "integrity": "sha512-kWa0AKAxDhmr4t6c4pgQqk6yL52/M67xOMh60HRnAeydzo5QIxOitN5bE1+e0rbdnxfly7FTB9e2Ny0ypLMbag==" }, "electron-to-chromium": { - "version": "1.3.405", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.405.tgz", - "integrity": "sha512-D+xkP+hAQY/790DzImC8bI8QJLaArNG4b74bYvkhkK/fli51JmNyUYxwKLSl/8VPGkkXEqKCupSDD05/E5P72w==", + "version": "1.3.408", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.408.tgz", + "integrity": "sha512-vn1zWIxIdyl0MR72lr81/7kHYTRlDRjJT4ocp8dtb85VhH46J3lNqDMEBljAKPKgguqjK0+WAbf3IL6ZKw72kQ==", "dev": true }, "emoji-regex": { @@ -5712,18 +5722,18 @@ "dev": true }, "esquery": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.2.1.tgz", - "integrity": "sha512-/IcAXa9GWOX9BUIb/Tz2QrrAWFWzWGrFIeLeMRwtiuwg9qTFhSYemsi9DixwrFFqVbhBZ47vGcxEnu5mbPqbig==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.0.tgz", + "integrity": "sha512-/5qB+Mb0m2bh86tjGbA8pB0qBfdmCIK6ZNPjcw4/TtEH0+tTf0wLA5HK4KMTweSMwLGHwBDWCBV+6+2+EuHmgg==", "dev": true, "requires": { "estraverse": "^5.0.0" }, "dependencies": { "estraverse": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.0.0.tgz", - "integrity": "sha512-j3acdrMzqrxmJTNj5dbr1YbjacrYgAxVMeF0gK16E3j494mOe7xygM/ZLIguEQ0ETwAg2hlJCtHRGav+y0Ny5A==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", + "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", "dev": true } } @@ -6566,9 +6576,9 @@ } }, "graphql-schema-linter": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/graphql-schema-linter/-/graphql-schema-linter-0.2.5.tgz", - "integrity": "sha512-kROp2+1huToojoNEFHSUXz2pz8QfwPjFYB+ZSAjSas9C08d8T0vIjZQ+9pxrzzbIgYUABODLuZsfzutjYjRsig==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/graphql-schema-linter/-/graphql-schema-linter-0.2.6.tgz", + "integrity": "sha512-3KNchi1yqo8OiglBT17SN2aukgijSrwrWO/SGtMAd4dUpQJ0pzm+/0SomemqStyagEckF1cVibRY5wUdS4X1Bw==", "dev": true, "requires": { "chalk": "^2.0.1", @@ -6665,11 +6675,11 @@ "integrity": "sha512-4FOv3ZKfA4WdOKJeHdz6B3F/vxBLSgmBcGeAFPf4n1F64ltJUvOOerNj0rsJxONQGdhUMynQIvd6LzB+1J5oKA==" }, "graphql-tools": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/graphql-tools/-/graphql-tools-4.0.7.tgz", - "integrity": "sha512-rApl8sT8t/W1uQRcwzxMYyUBiCl/XicluApiDkNze5TX/GR0BSTQMjM2UcRGdTmkbsb1Eqq6afkyyeG/zMxZYQ==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/graphql-tools/-/graphql-tools-4.0.8.tgz", + "integrity": "sha512-MW+ioleBrwhRjalKjYaLQbr+920pHBgy9vM/n47sswtns8+96sRn5M/G+J1eu7IMeKWiN/9p6tmwCHU7552VJg==", "requires": { - "apollo-link": "^1.2.3", + "apollo-link": "^1.2.14", "apollo-utilities": "^1.0.1", "deprecated-decorator": "^0.1.6", "iterall": "^1.1.3", @@ -11797,9 +11807,9 @@ } }, "uglify-js": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.0.tgz", - "integrity": "sha512-j5wNQBWaql8gr06dOUrfaohHlscboQZ9B8sNsoK5o4sBjm7Ht9dxSbrMXyktQpA16Acaij8AcoozteaPYZON0g==", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.1.tgz", + "integrity": "sha512-JUPoL1jHsc9fOjVFHdQIhqEEJsQvfKDjlubcCilu8U26uZ73qOg8VsN8O1jbuei44ZPlwL7kmbAdM4tzaUvqnA==", "optional": true, "requires": { "commander": "~2.20.3" diff --git a/package.json b/package.json index ebd8d5745b3..5a472108db0 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@reactioncommerce/api-plugin-address-validation-test": "~1.0.0", "@reactioncommerce/api-plugin-catalogs": "~1.0.0", "@reactioncommerce/api-plugin-i18n": "~1.0.0", + "@reactioncommerce/api-plugin-settings": "^1.0.0", "@reactioncommerce/api-plugin-shops": "~1.0.0", "@reactioncommerce/api-utils": "~1.10.0", "@reactioncommerce/db-version-check": "~1.0.0", diff --git a/src/core-services/settings/index.js b/src/core-services/settings/index.js deleted file mode 100644 index bc3aa5b852f..00000000000 --- a/src/core-services/settings/index.js +++ /dev/null @@ -1,35 +0,0 @@ -import mutations from "./mutations/index.js"; -import queries from "./queries/index.js"; -import resolvers from "./resolvers/index.js"; -import schemas from "./schemas/index.js"; -import { registerPluginHandlerForAppSettings } from "./util/settingsConfig.js"; - -/** - * @summary Import and call this function to add this plugin to your API. - * @param {ReactionAPI} app The ReactionAPI instance - * @returns {undefined} - */ -export default async function register(app) { - await app.registerPlugin({ - label: "App Settings", - name: "reaction-settings", - version: app.context.appVersion, - collections: { - AppSettings: { - name: "AppSettings", - indexes: [ - [{ shopId: 1 }, { unique: true }] - ] - } - }, - functionsByType: { - registerPluginHandler: [registerPluginHandlerForAppSettings] - }, - mutations, - queries, - graphQL: { - resolvers, - schemas - } - }); -} diff --git a/src/core-services/settings/mutations/index.js b/src/core-services/settings/mutations/index.js deleted file mode 100644 index f390ca0f45d..00000000000 --- a/src/core-services/settings/mutations/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import updateAppSettings from "./updateAppSettings.js"; - -export default { - updateAppSettings -}; diff --git a/src/core-services/settings/mutations/updateAppSettings.js b/src/core-services/settings/mutations/updateAppSettings.js deleted file mode 100644 index d4df4bfa044..00000000000 --- a/src/core-services/settings/mutations/updateAppSettings.js +++ /dev/null @@ -1,62 +0,0 @@ -import ReactionError from "@reactioncommerce/reaction-error"; -import { - addGlobalSettingDefaults, - addShopSettingDefaults, - permissionsThatCanEditGlobalSetting, - permissionsThatCanEditShopSetting, - runAfterUpdateHooks -} from "../util/settingsConfig.js"; - -/** - * @summary Updates app settings for a shop or global app settings. - * @param {Object} context App context - * @param {Object} settingsUpdates Fields to be updated - * @param {String} [shopId] Shop ID. Pass `null` for global settings. - * @returns {Promise} Updated app settings for a shop or global app settings - */ -export default async function updateAppSettings(context, settingsUpdates, shopId = null) { - const { collections } = context; - const { AppSettings } = collections; - - const updateKeys = Object.keys(settingsUpdates); - if (updateKeys.length === 0) { - throw new ReactionError("invalid-param", "You must request at least one update"); - } - - // Look up roles that are allowed to set each setting. Throw if not allowed. - for (const updateKey of updateKeys) { - const permissionsNeededToEdit = shopId ? permissionsThatCanEditShopSetting(updateKey) : permissionsThatCanEditGlobalSetting(updateKey); - if (permissionsNeededToEdit.length === 0) { - throw new ReactionError("access-denied", `You are not allowed to edit the "${updateKey}" setting`); - } - - // eslint-disable-next-line no-await-in-loop - const permissionChecks = await Promise.all(permissionsNeededToEdit.map(async (permission) => { - const [resource, action] = permission.split("/"); - if (resource && action) { - return context.userHasPermission(resource, action, { shopId }); - } - return false; - })); - - if (permissionChecks.every((permission) => permission === false)) { - throw new ReactionError("access-denied", "Access Denied"); - } - } - - const { value: updatedDoc } = await AppSettings.findOneAndUpdate( - { shopId }, - { - $set: settingsUpdates - }, - { - returnOriginal: false, - upsert: true - } - ); - - // We don't want to await these and delay sending a response back - runAfterUpdateHooks(context, settingsUpdates, shopId); - - return shopId ? addShopSettingDefaults(updatedDoc || {}) : addGlobalSettingDefaults(updatedDoc || {}); -} diff --git a/src/core-services/settings/queries/appSettings.js b/src/core-services/settings/queries/appSettings.js deleted file mode 100644 index cb832530b5c..00000000000 --- a/src/core-services/settings/queries/appSettings.js +++ /dev/null @@ -1,16 +0,0 @@ -import { addGlobalSettingDefaults, addShopSettingDefaults } from "../util/settingsConfig.js"; - -/** - * @summary Returns app settings for a shop or global app settings. - * @param {Object} context App context - * @param {String} [shopId] Shop ID. Pass `null` for global settings. - * @returns {Promise} App settings for a shop or global app settings - */ -export default async function appSettings(context, shopId = null) { - const { collections } = context; - const { AppSettings } = collections; - - const settings = (await AppSettings.findOne({ shopId })) || {}; - - return shopId ? addShopSettingDefaults(settings) : addGlobalSettingDefaults(settings); -} diff --git a/src/core-services/settings/queries/index.js b/src/core-services/settings/queries/index.js deleted file mode 100644 index 9b03f99e3c5..00000000000 --- a/src/core-services/settings/queries/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import appSettings from "./appSettings.js"; - -export default { - appSettings -}; diff --git a/src/core-services/settings/resolvers/Mutation/index.js b/src/core-services/settings/resolvers/Mutation/index.js deleted file mode 100644 index 9ceeede8620..00000000000 --- a/src/core-services/settings/resolvers/Mutation/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import updateGlobalSettings from "./updateGlobalSettings.js"; -import updateShopSettings from "./updateShopSettings.js"; - -export default { - updateGlobalSettings, - updateShopSettings -}; diff --git a/src/core-services/settings/resolvers/Mutation/updateGlobalSettings.js b/src/core-services/settings/resolvers/Mutation/updateGlobalSettings.js deleted file mode 100644 index 84a9c774b09..00000000000 --- a/src/core-services/settings/resolvers/Mutation/updateGlobalSettings.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @name Mutation/updateGlobalSettings - * @method - * @memberof Shop/GraphQL - * @summary resolver for the updateGlobalSettings GraphQL mutation - * @param {Object} _ - unused - * @param {Object} args - an object of all mutation arguments that were sent by the client - * @param {Object} args.input - mutation input object - * @param {String} args.input.shopId - Shop ID - * @param {Object} args.input.settingsUpdates - Updated fields - * @param {Object} context - an object containing the per-request state - * @returns {Promise} ShopsPayload - */ -export default async function updateGlobalSettings(_, { input }, context) { - const { - settingsUpdates, - clientMutationId = null - } = input; - - const globalSettings = await context.mutations.updateAppSettings(context, settingsUpdates, null); - - return { - clientMutationId, - globalSettings - }; -} diff --git a/src/core-services/settings/resolvers/Mutation/updateShopSettings.js b/src/core-services/settings/resolvers/Mutation/updateShopSettings.js deleted file mode 100644 index d99fb993c94..00000000000 --- a/src/core-services/settings/resolvers/Mutation/updateShopSettings.js +++ /dev/null @@ -1,31 +0,0 @@ -import { decodeShopOpaqueId } from "../../xforms/id.js"; - -/** - * @name Mutation/updateShopSettings - * @method - * @memberof Shop/GraphQL - * @summary resolver for the updateShopSettings GraphQL mutation - * @param {Object} _ - unused - * @param {Object} args - an object of all mutation arguments that were sent by the client - * @param {Object} args.input - mutation input object - * @param {String} args.input.shopId - Shop ID - * @param {Object} args.input.settingsUpdates - Updated fields - * @param {Object} context - an object containing the per-request state - * @returns {Promise} ShopsPayload - */ -export default async function updateShopSettings(_, { input }, context) { - const { - shopId: opaqueShopId, - settingsUpdates, - clientMutationId = null - } = input; - - const shopId = decodeShopOpaqueId(opaqueShopId); - - const shopSettings = await context.mutations.updateAppSettings(context, settingsUpdates, shopId); - - return { - clientMutationId, - shopSettings - }; -} diff --git a/src/core-services/settings/resolvers/Query/globalSettings.js b/src/core-services/settings/resolvers/Query/globalSettings.js deleted file mode 100644 index f21530bfcb8..00000000000 --- a/src/core-services/settings/resolvers/Query/globalSettings.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @name Query/globalSettings - * @method - * @memberof Core/GraphQL - * @summary Gets global settings - * @param {Object} _ - unused - * @param {Object} __ - unused - * @param {Object} context - an object containing the per-request state - * @returns {Promise} The global settings object - */ -export default async function globalSettings(_, __, context) { - return context.queries.appSettings(context); -} diff --git a/src/core-services/settings/resolvers/Query/index.js b/src/core-services/settings/resolvers/Query/index.js deleted file mode 100644 index 2c4051594f7..00000000000 --- a/src/core-services/settings/resolvers/Query/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import globalSettings from "./globalSettings.js"; -import shopSettings from "./shopSettings.js"; - -export default { - globalSettings, - shopSettings -}; diff --git a/src/core-services/settings/resolvers/Query/shopSettings.js b/src/core-services/settings/resolvers/Query/shopSettings.js deleted file mode 100644 index 5cc6e7ebb3c..00000000000 --- a/src/core-services/settings/resolvers/Query/shopSettings.js +++ /dev/null @@ -1,19 +0,0 @@ -import { decodeShopOpaqueId } from "../../xforms/id.js"; - -/** - * @name Query/shopSettings - * @method - * @memberof Core/GraphQL - * @summary Gets global settings - * @param {Object} _ - unused - * @param {Object} args - Args passed by the client - * @param {Object} context - an object containing the per-request state - * @returns {Promise} The global settings object - */ -export default async function shopSettings(_, args, context) { - const { shopId } = args; - - const internalShopId = decodeShopOpaqueId(shopId); - - return context.queries.appSettings(context, internalShopId); -} diff --git a/src/core-services/settings/resolvers/index.js b/src/core-services/settings/resolvers/index.js deleted file mode 100644 index 6fa2b1943e3..00000000000 --- a/src/core-services/settings/resolvers/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import Mutation from "./Mutation/index.js"; -import Query from "./Query/index.js"; - -export default { - Mutation, - Query -}; diff --git a/src/core-services/settings/schemas/index.js b/src/core-services/settings/schemas/index.js deleted file mode 100644 index 23f7c656f88..00000000000 --- a/src/core-services/settings/schemas/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import importAsString from "@reactioncommerce/api-utils/importAsString.js"; - -const settings = importAsString("./settings.graphql"); - -export default [settings]; diff --git a/src/core-services/settings/schemas/settings.graphql b/src/core-services/settings/schemas/settings.graphql deleted file mode 100644 index 3b96bf3b479..00000000000 --- a/src/core-services/settings/schemas/settings.graphql +++ /dev/null @@ -1,133 +0,0 @@ -""" -App settings that are not shop specific. Plugins extend the GlobalSettings type to support -whatever settings they need. -""" -type GlobalSettings { - "A fake setting necessary until some plugin extends this with a real setting" - doNotUse: String -} - -""" -App settings for a specific shop. Plugins extend the ShopSettings type to support -whatever settings they need. -""" -type ShopSettings { - # Although the spec allows and Apollo supports defining an empty type - # that is extended later in other files, the graphql-schema-linter - # package currently has a problem with this, so we must add a fake field. - # - # https://github.com/cjoudrey/graphql-schema-linter/issues/151 - "A fake setting necessary until some plugin extends this with a real setting" - doNotUse: String -} - -extend type Query { - """ - Returns app settings that are not shop specific. Plugins extend the GlobalSettings type to support - whatever settings they need. - """ - globalSettings: GlobalSettings! - - """ - Returns app settings for a specific shop. Plugins extend the ShopSettings type to support - whatever settings they need. - """ - shopSettings( - "The shop to get app settings for" - shopId: ID! - ): ShopSettings! -} - -## -# updateGlobalSettings -## - -extend type Mutation { - """ - Returns app settings that are not shop specific. Plugins extend the GlobalSettings type to support - whatever settings they need. - """ - updateGlobalSettings( - "Mutation input" - input: UpdateGlobalSettingsInput! - ): UpdateGlobalSettingsPayload! -} - -"Input for the `updateGlobalSettings` mutation" -input UpdateGlobalSettingsInput { - "An optional string identifying the mutation call, which will be returned in the response payload" - clientMutationId: String - - "Updated settings values. Only includes settings to be changed." - settingsUpdates: GlobalSettingsUpdates! -} - -""" -Updates for app settings that are not shop specific. Plugins extend -this input type to support whatever settings they need. All fields -must be optional. -""" -input GlobalSettingsUpdates { - "Do not use this field" - doNotUse: String -} - -"Response payload for the `updateGlobalSettings` mutation" -type UpdateGlobalSettingsPayload { - "The same string you sent with the mutation params, for matching mutation calls with their responses" - clientMutationId: String - - "Updated global settings" - globalSettings: GlobalSettings! -} - -## -# updateShopSettings -## - -extend type Mutation { - """ - Returns app settings for a specific shop. Plugins extend the ShopSettings type to support - whatever settings they need. - """ - updateShopSettings( - "Mutation input" - input: UpdateShopSettingsInput! - ): UpdateShopSettingsPayload! -} - -"Input for the `updateShopSettings` mutation" -input UpdateShopSettingsInput { - "An optional string identifying the mutation call, which will be returned in the response payload" - clientMutationId: String - - "Updated settings values. Only includes settings to be changed." - settingsUpdates: ShopSettingsUpdates! - - "The ID of the shop to update some settings for" - shopId: ID! -} - -""" -Updates for app settings that are not shop specific. Plugins extend -this input type to support whatever settings they need. All fields -must be optional. -""" -input ShopSettingsUpdates { - # Although the spec allows and Apollo supports defining an empty type - # that is extended later in other files, the graphql-schema-linter - # package currently has a problem with this, so we must add a fake field. - # - # https://github.com/cjoudrey/graphql-schema-linter/issues/151 - "Do not use this field" - doNotUse: String -} - -"Response payload for the `updateShopSettings` mutation" -type UpdateShopSettingsPayload { - "The same string you sent with the mutation params, for matching mutation calls with their responses" - clientMutationId: String - - "Updated shop settings" - shopSettings: ShopSettings! -} diff --git a/src/core-services/settings/util/settingsConfig.js b/src/core-services/settings/util/settingsConfig.js deleted file mode 100644 index 3a8dd42f5c8..00000000000 --- a/src/core-services/settings/util/settingsConfig.js +++ /dev/null @@ -1,149 +0,0 @@ -import SimpleSchema from "simpl-schema"; - -export const globalSettingsConfig = {}; -export const shopSettingsConfig = {}; - -export const globalSettingsSchema = new SimpleSchema(); -export const shopSettingsSchema = new SimpleSchema(); - -/** - * @param {Object} settings The settings object - * @returns {Object} Settings object with default values added - */ -export function addGlobalSettingDefaults(settings) { - Object.getOwnPropertyNames(globalSettingsSchema).forEach((field) => { - const value = settings[field]; - if (value === undefined || value === null) { - const config = globalSettingsSchema[field]; - if (config.defaultValue !== undefined) { - settings[field] = config.defaultValue; - } - } - }); - return settings; -} - -/** - * @param {Object} settings The settings object - * @returns {Object} Settings object with default values added - */ -export function addShopSettingDefaults(settings) { - Object.getOwnPropertyNames(shopSettingsConfig).forEach((field) => { - const value = settings[field]; - if (value === undefined || value === null) { - const config = shopSettingsConfig[field]; - if (config.defaultValue !== undefined) { - settings[field] = config.defaultValue; - } - } - }); - return settings; -} - -/** - * @param {String} field The setting field name - * @returns {String[]} List of roles that can edit this setting. - */ -export function permissionsThatCanEditGlobalSetting(field) { - const config = globalSettingsConfig[field]; - if (!config) return []; - - return config.permissionsThatCanEdit || []; -} - -/** - * @param {String} field The setting field name - * @returns {String[]} List of roles that can edit this setting. - */ -export function permissionsThatCanEditShopSetting(field) { - const config = shopSettingsConfig[field]; - if (!config) return []; - - return config.permissionsThatCanEdit || []; -} - -/** - * @summary Run all afterUpdate hooks that were registered for each updated setting - * @param {Object} context App context - * @param {Object} updates Object with setting name as key and new setting value as value - * @param {String} [shopId] Shop ID. Pass `null` for global settings. - * @return {undefined} - */ -export function runAfterUpdateHooks(context, updates, shopId) { - Object.keys(updates).forEach((field) => { - const config = shopId ? shopSettingsConfig[field] : globalSettingsSchema[field]; - if (!config || !config.afterUpdate) return; - - config.afterUpdate(context, { shopId, value: updates[field] }); - }); -} - -const configSchema = new SimpleSchema({ - "afterUpdate": { - type: Function, - optional: true - }, - "defaultValue": { - type: SimpleSchema.oneOf(String, Number, Date, Boolean), - optional: true - }, - "permissionsThatCanEdit": { - type: Array, - optional: true - }, - "permissionsThatCanEdit.$": String, - "simpleSchema": { - type: Object, - blackbox: true - } -}); - -/** - * @summary Reads and merges `appSettingsConfig` from all plugin registration. - * @returns {undefined} - */ -export function registerPluginHandlerForAppSettings({ - globalSettingsConfig: globalSettingsConfigFromPlugin, - name, - shopSettingsConfig: shopSettingsConfigFromPlugin -}) { - if (globalSettingsConfigFromPlugin) { - Object.getOwnPropertyNames(globalSettingsConfigFromPlugin).forEach((field) => { - if (globalSettingsConfig[field]) { - throw new Error(`Plugin ${name} has field "${field}" in "globalSettingsConfig" but another plugin already defined this field`); - } - - const config = globalSettingsConfigFromPlugin[field]; - configSchema.validate(config); - - globalSettingsConfig[field] = config; - - globalSettingsSchema.extend({ - [field]: { - ...config.simpleSchema, - optional: true - } - }); - }); - } - - if (shopSettingsConfigFromPlugin) { - Object.getOwnPropertyNames(shopSettingsConfigFromPlugin).forEach((field) => { - if (shopSettingsConfig[field]) { - throw new Error(`Plugin ${name} has field "${field}" in "shopSettingsConfig" but another plugin already defined this field`); - } - - const config = shopSettingsConfigFromPlugin[field]; - configSchema.validate(config); - - shopSettingsConfig[field] = config; - - shopSettingsSchema.extend({ - [field]: { - ...config.simpleSchema, - optional: true - } - }); - }); - } -} diff --git a/src/core-services/settings/xforms/id.js b/src/core-services/settings/xforms/id.js deleted file mode 100644 index a0e52f2dd81..00000000000 --- a/src/core-services/settings/xforms/id.js +++ /dev/null @@ -1,9 +0,0 @@ -import decodeOpaqueIdForNamespace from "@reactioncommerce/api-utils/decodeOpaqueIdForNamespace.js"; -import encodeOpaqueId from "@reactioncommerce/api-utils/encodeOpaqueId.js"; - -const namespaces = { - Shop: "reaction/shop" -}; -export const encodeShopOpaqueId = encodeOpaqueId(namespaces.Shop); - -export const decodeShopOpaqueId = decodeOpaqueIdForNamespace(namespaces.Shop); diff --git a/src/registerPlugins.js b/src/registerPlugins.js index b2e0308e33e..67b0078c397 100644 --- a/src/registerPlugins.js +++ b/src/registerPlugins.js @@ -8,6 +8,7 @@ import registerPluginDiscountCodes from "@reactioncommerce/plugin-discount-codes import registerPluginPaymentsExample from "@reactioncommerce/plugin-payments-example"; import registerPluginI18n from "@reactioncommerce/api-plugin-i18n"; import registerPluginNavigation from "@reactioncommerce/plugin-navigation"; +import registerPluginSettings from "@reactioncommerce/api-plugin-settings"; import registerPluginShops from "@reactioncommerce/api-plugin-shops"; import registerPluginSimpleAuthorization from "@reactioncommerce/plugin-simple-authorization"; import registerPluginSitemapGenerator from "@reactioncommerce/plugin-sitemap-generator"; @@ -21,7 +22,6 @@ import registerPluginDiscounts from "./core-services/discounts/index.js"; import registerPluginEmail from "./core-services/email/index.js"; import registerPluginInventory from "./core-services/inventory/index.js"; import registerPluginProduct from "./core-services/product/index.js"; -import registerPluginSettings from "./core-services/settings/index.js"; import registerPluginOrders from "./core-services/orders/index.js"; import registerPluginPayments from "./core-services/payments/index.js"; import registerPluginShipping from "./core-services/shipping/index.js"; From 1db0933da70a0440b6350878e830f815ce6cbcd6 Mon Sep 17 00:00:00 2001 From: Maria Paktiti Date: Wed, 15 Apr 2020 19:11:23 -0500 Subject: [PATCH 2/3] chore: fix linting errors Signed-off-by: Maria Paktiti --- src/mockTypes.graphql | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/mockTypes.graphql b/src/mockTypes.graphql index 11d0d956bc7..10306ad52ae 100644 --- a/src/mockTypes.graphql +++ b/src/mockTypes.graphql @@ -83,3 +83,29 @@ extend input FakeInput { "Fake field to satisfy linting" emailRecordInput: EmailRecordInput } + +""" +A fake type to satisfy linting +type lives in `api-plugin-settings` +""" +type ShopSettings { + "A fake field to satisfy linting" + fakeField: String +} +extend type FakeData { + "Fake field to satisfy linting" + shopSettings: ShopSettings +} +""" +A fake type to satisfy linting +type lives in `api-plugin-settings` +""" +input ShopSettingsUpdates { + "A fake field to satisfy linting" + fakeField: String +} + +extend input FakeInput { + "Fake field to satisfy linting" + shopSettingsUpdates: ShopSettingsUpdates +} \ No newline at end of file From 76bfec3fffaeb308039cd41f414d9b7e8bf8e9ac Mon Sep 17 00:00:00 2001 From: Maria Paktiti Date: Wed, 15 Apr 2020 19:16:19 -0500 Subject: [PATCH 3/3] chore: update the package version range Signed-off-by: Maria Paktiti --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5a472108db0..a4c2c1bb683 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "@reactioncommerce/api-plugin-address-validation-test": "~1.0.0", "@reactioncommerce/api-plugin-catalogs": "~1.0.0", "@reactioncommerce/api-plugin-i18n": "~1.0.0", - "@reactioncommerce/api-plugin-settings": "^1.0.0", + "@reactioncommerce/api-plugin-settings": "~1.0.0", "@reactioncommerce/api-plugin-shops": "~1.0.0", "@reactioncommerce/api-utils": "~1.10.0", "@reactioncommerce/db-version-check": "~1.0.0",