diff --git a/docker-compose.yml b/docker-compose.yml index 786160f8a..35510e42a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -327,12 +327,12 @@ services: IDENTITYX_APP_ID: ${EXAMPLE_IDENTITYX_APP_ID-5d1b86070ce467bff670a052} IDENTITYX_API_TOKEN: ${EXAMPLE_IDENTITYX_API_TOKEN-} - OMEDA_CLIENT_KEY: ${EXAMPLE_OMEDA_CLIENT_KEY-client_allu} + OMEDA_CLIENT_KEY: ${EXAMPLE_OMEDA_CLIENT_KEY-client_acbm} OMEDA_GRAPHQL_URI: ${EXAMPLE_OMEDA_GRAPHQL_URI-} - OMEDA_BRAND_KEY: ${EXAMPLE_OMEDA_BRAND_KEY-allucd} + OMEDA_BRAND_KEY: ${EXAMPLE_OMEDA_BRAND_KEY-hcl} OMEDA_APP_ID: ${EXAMPLE_OMEDA_APP_ID} OMEDA_INPUT_ID: ${EXAMPLE_OMEDA_INPUT_ID} - OMEDA_RAPID_IDENT_PRODUCT_ID: ${EXAMPLE_OMEDA_RAPID_IDENT_PRODUCT_ID-374} + OMEDA_RAPID_IDENT_PRODUCT_ID: ${EXAMPLE_OMEDA_RAPID_IDENT_PRODUCT_ID-15289} RECAPTCHA_V3_SECRET_KEY: ${EXAMPLE_RECAPTCHA_V3_SECRET_KEY-} RECAPTCHA_V3_SITE_KEY: ${EXAMPLE_RECAPTCHA_V3_SITE_KEY-} SENDGRID_API_KEY: ${EXAMPLE_SENDGRID_API_KEY-} diff --git a/packages/marko-web-omeda-identity-x/README.md b/packages/marko-web-omeda-identity-x/README.md index eb5989e71..c36e60c5c 100644 --- a/packages/marko-web-omeda-identity-x/README.md +++ b/packages/marko-web-omeda-identity-x/README.md @@ -12,20 +12,20 @@ Additional information can be found in the [Omeda](https://training.omeda.com/kn ## Configuration All configuration data must be passed to the middleware when loaded (See [Middleware Setup](#1-middleware-setup) below.) -| Key | Description | Link -| - | - | - | -| `brandKey` | (Required) The Omeda Brand key (such as `orgcd`). -| `clientKey` | (Optional) The Omeda client key (such as `client_orgc`.) *Required if sending deployment optIns via the underlying omeda package!* | [marko-web-omeda docs](../marko-web-omeda) -| `appId` | (Required) The Omeda application API read token -| `inputId` | (Required) The Omeda application API write token -| `rapidIdentProductId` | (Required) The Omeda identifier for a Website product (ProductType=7). -| `idxConfig` | (Required) An instance of the IdentityX configuration class | [marko-web-identity-x#1](../marko-web-identity-x/config.js) -| `idxRouteTemplates` | (Required) An object containing the Marko templates to use for each IdentityX endpoint. | [marko-web-identity-x#2](../marko-web-identity-x/index.js) -| `omedaGraphQLClientProp` | (Optional) Custom path to the Omeda GraphQL client (within app.locals), default value `$omedaGraphQLClient` -| `omedaRapidIdentifyProp` | (Optional) Custom path to the Omeda Rapid Identification handler (within app.locals), default value `$omedaRapidIdentify` -| `idxOmedaRapidIdentifyProp` | (Optional) Custom path to the IdentityX Omeda Rapid Identification handler (within app.locals), default value `$idXOmedaRapidIdentify` -| `omedaPromoCodeCookieName` | (Optional) The Omeda promocode cookie name to detect, default value `omeda_promo_code` -| `omedaPromoCodeDefault` | (Optional) The default promo code to send with rapid identification requests +| Property | Required? | Description | Default value | +| - | - | - | - | +| `brandKey` | **Yes** | The Omeda Brand key (such as `orgcd`). +| `clientKey` | No | The Omeda client key (such as `client_orgc`.) *Required if sending deployment optIns via the underlying omeda package!* [marko-web-omeda docs](../marko-web-omeda) +| `appId` | **Yes** | The Omeda application API read token +| `inputId` | **Yes** | The Omeda application API write token +| `rapidIdentProductId` | **Yes** | The Omeda identifier for a Website product (ProductType=7). +| `idxConfig` | **Yes** | An instance of the IdentityX configuration class (see [marko-web-identity-x#1](../marko-web-identity-x/config.js)) | _n/a_ +| `idxRouteTemplates` | **Yes** | An object containing the Marko templates to use for each IdentityX endpoint. (see [marko-web-identity-x#2](../marko-web-identity-x/index.js)) +| `omedaPromoCodeCookieName` | No | The name of the cookie to look for a persisted/original promo code. | `omeda_promo_code` | +| `omedaPromoCodeDefault` | No | The default promo code to send with all Omeda requests. Falls back to input ID default configured by Omeda. | +| `idxOmedaRapidIdentifyProp` | No | The property (in the express app context) where the O+IdX rapid identification service is located. | `$idxOmedaRapidIdentify` | +| `omedaGraphQLClientProp` | No | The property (in the express app context) where the Omeda GraphQL client is located. | `$omedaGraphQLClient` | +| `omedaRapidIdentifyProp` | No | The property (in the express app context) where the Omeda rapid identification service is located. | `$omedaRapidIdentify` | ## Usage This package: diff --git a/packages/marko-web-omeda-identity-x/add-integration-hooks.js b/packages/marko-web-omeda-identity-x/add-integration-hooks.js index fefe3dc19..d3e42e939 100644 --- a/packages/marko-web-omeda-identity-x/add-integration-hooks.js +++ b/packages/marko-web-omeda-identity-x/add-integration-hooks.js @@ -1,4 +1,7 @@ - +const Joi = require('@parameter1/joi'); +const { validate } = require('@parameter1/joi/utils'); +const { get } = require('@parameter1/base-cms-object-path'); +const IdXConfig = require('@parameter1/base-cms-marko-web-identity-x/config'); const { onAuthenticationSuccess, onLoginLinkSent, @@ -11,32 +14,43 @@ const { * @param {object} params * @param {IdentityXConfiguration} params.idxConfig */ -module.exports = ({ - idxConfig, - brandKey, - omedaGraphQLProp = '$omedaGraphQLClient', - idxOmedaRapidIdentifyProp = '$idxOmedaRapidIdentify', -} = {}) => { - if (!idxConfig) throw new Error('The IdentityX configuration instances is required to add Omeda+IdentityX integration hooks.'); +module.exports = (params = {}) => { + const { + idxConfig, + brandKey, + omedaGraphQLClientProp, + idxOmedaRapidIdentifyProp, + omedaPromoCodeCookieName, + omedaPromoCodeDefault, + } = validate(Joi.object({ + brandKey: Joi.string().required(), + idxConfig: Joi.object().instance(IdXConfig).required(), + idxOmedaRapidIdentifyProp: Joi.string().required(), + omedaGraphQLClientProp: Joi.string().required(), + omedaPromoCodeCookieName: Joi.string().required(), + omedaPromoCodeDefault: Joi.string(), + }), params); + idxConfig.addHook({ name: 'onLoginLinkSent', shouldAwait: false, fn: async args => onLoginLinkSent({ ...args, brandKey, - omedaGraphQLProp, - idxOmedaRapidIdentifyProp, - - req: args.req, - service: args.service, - user: args.user, + idxOmedaRapidIdentify: get(args, `req.${idxOmedaRapidIdentifyProp}`), + omedaGraphQLClient: get(args, `req.${omedaGraphQLClientProp}`), + omedaPromoCodeCookieName, + omedaPromoCodeDefault, }), }); idxConfig.addHook({ name: 'onAuthenticationSuccess', shouldAwait: true, - fn: async ({ user, res }) => onAuthenticationSuccess({ brandKey, user, res }), + fn: async args => onAuthenticationSuccess({ + ...args, + brandKey, + }), }); idxConfig.addHook({ @@ -44,16 +58,18 @@ module.exports = ({ shouldAwait: false, fn: async args => onUserProfileUpdate({ ...args, - idxOmedaRapidIdentifyProp, - req: args.req, - user: args.user, + idxOmedaRapidIdentify: get(args, `req.${idxOmedaRapidIdentifyProp}`), + omedaPromoCodeCookieName, + omedaPromoCodeDefault, }), }); idxConfig.addHook({ name: 'onLogout', shouldAwait: true, - fn: async ({ res }) => onLogout({ res }), + fn: async args => onLogout({ + ...args, + }), }); return idxConfig; diff --git a/packages/marko-web-omeda-identity-x/index.js b/packages/marko-web-omeda-identity-x/index.js index 421f4c056..8fcd07478 100644 --- a/packages/marko-web-omeda-identity-x/index.js +++ b/packages/marko-web-omeda-identity-x/index.js @@ -1,3 +1,6 @@ +const Joi = require('@parameter1/joi'); +const { validate } = require('@parameter1/joi/utils'); +const IdXConfig = require('@parameter1/base-cms-marko-web-identity-x/config'); const omeda = require('@parameter1/base-cms-marko-web-omeda'); const identityX = require('@parameter1/base-cms-marko-web-identity-x'); const addOmedaHooksToIdentityXConfig = require('./add-integration-hooks'); @@ -8,29 +11,34 @@ const setOlyticsCookie = require('./middleware/set-olytics-cookie'); const rapidIdentify = require('./middleware/rapid-identify'); const rapidIdentifyRouter = require('./routes/rapid-identify'); -module.exports = (app, { - brandKey: brand, - clientKey, - appId, - inputId, - - rapidIdentProductId, - omedaGraphQLClientProp = '$omedaGraphQLClient', - omedaRapidIdentifyProp = '$omedaRapidIdentify', - - omedaPromoCodeCookieName = 'omeda_promo_code', - omedaPromoCodeDefault, - - idxConfig, - idxOmedaRapidIdentifyProp = '$idxOmedaRapidIdentify', - idxRouteTemplates = {}, -} = {}) => { - if (!brand) throw new Error('The Omeda `brandKey` is required.'); - if (!appId) throw new Error('The Omeda `appId` is required.'); - if (!rapidIdentProductId) throw new Error('The Omeda `rapidIdentProductId` is required.'); - - // consistently pass brand key - const brandKey = brand.trim().toLowerCase(); +module.exports = (app, params = {}) => { + const { + appId, + brandKey, + clientKey, + idxConfig, + idxOmedaRapidIdentifyProp, + idxRouteTemplates, + inputId, + omedaGraphQLClientProp, + omedaPromoCodeCookieName, + omedaPromoCodeDefault, + omedaRapidIdentifyProp, + rapidIdentProductId, + } = validate(Joi.object({ + appId: Joi.string().required(), + brandKey: Joi.string().required().trim().lowercase(), + clientKey: Joi.string().required().trim().lowercase(), + idxConfig: Joi.object().required().instance(IdXConfig), + idxOmedaRapidIdentifyProp: Joi.string().default('$idxOmedaRapidIdentify'), + idxRouteTemplates: Joi.object().required(), + inputId: Joi.string().required(), + omedaGraphQLClientProp: Joi.string().default('$omedaGraphQLClient'), + omedaPromoCodeCookieName: Joi.string().default('omeda_promo_code'), + omedaPromoCodeDefault: Joi.string(), + omedaRapidIdentifyProp: Joi.string().default('$omedaRapidIdentify'), + rapidIdentProductId: Joi.number().required(), + }), params); // strip `oly_enc_id` when identity-x user is logged-in app.use(stripOlyticsParam()); @@ -53,10 +61,12 @@ module.exports = (app, { // add appropiate identity-x to omeda integration hooks addOmedaHooksToIdentityXConfig({ - idxConfig, brandKey, - productId: rapidIdentProductId, - omedaGraphQLProp: omedaGraphQLClientProp, + idxConfig, + idxOmedaRapidIdentifyProp, + omedaGraphQLClientProp, + omedaPromoCodeCookieName, + omedaPromoCodeDefault, }); // attach the identity-x rapid identification wrapper middleware @@ -75,11 +85,16 @@ module.exports = (app, { app.use(setOlyticsCookie({ brandKey })); // install the Omeda data sync middleware - app.use(resyncCustomerData({ brandKey, omedaGraphQLClientProp })); + app.use(resyncCustomerData({ + brandKey, + omedaGraphQLClientProp, + })); // register the rapid identify AJAX route app.use('/__idx/omeda-rapid-ident', rapidIdentifyRouter({ brandKey, idxOmedaRapidIdentifyProp, + omedaPromoCodeCookieName, + omedaPromoCodeDefault, })); }; diff --git a/packages/marko-web-omeda-identity-x/integration-hooks/on-authentication-success.js b/packages/marko-web-omeda-identity-x/integration-hooks/on-authentication-success.js index e1b78eb70..9a56045f5 100644 --- a/packages/marko-web-omeda-identity-x/integration-hooks/on-authentication-success.js +++ b/packages/marko-web-omeda-identity-x/integration-hooks/on-authentication-success.js @@ -1,7 +1,18 @@ +const Joi = require('@parameter1/joi'); +const { validate } = require('@parameter1/joi/utils'); const olyticsCookie = require('@parameter1/base-cms-marko-web-omeda/olytics/customer-cookie'); const findEncryptedId = require('../external-id/find-encrypted-customer-id'); -module.exports = ({ brandKey, user, res }) => { +module.exports = async (params = {}) => { + const { + brandKey, + user, + res, + } = validate(Joi.object({ + brandKey: Joi.string().required(), + user: Joi.object().required(), + res: Joi.object().required(), + }).unknown(true), params); const encryptedId = findEncryptedId({ externalIds: user.externalIds, brandKey }); if (!encryptedId) return; olyticsCookie.setTo(res, encryptedId); diff --git a/packages/marko-web-omeda-identity-x/integration-hooks/on-login-link-sent.js b/packages/marko-web-omeda-identity-x/integration-hooks/on-login-link-sent.js index 961ec9481..c6df88523 100644 --- a/packages/marko-web-omeda-identity-x/integration-hooks/on-login-link-sent.js +++ b/packages/marko-web-omeda-identity-x/integration-hooks/on-login-link-sent.js @@ -1,3 +1,5 @@ +const Joi = require('@parameter1/joi'); +const { validate } = require('@parameter1/joi/utils'); const extractPromoCode = require('../utils/extract-promo-code'); const { getAnsweredQuestionMap, @@ -6,22 +8,28 @@ const { updateIdentityX, } = require('../omeda-data'); -module.exports = async ({ - brandKey, - omedaGraphQLProp = '$omedaGraphQLClient', - idxOmedaRapidIdentifyProp = '$idxOmedaRapidIdentify', - omedaPromoCodeCookieName = 'omeda_promo_code', - omedaPromoCodeDefault, - promoCode: hookDataPromoCode, - - req, - service: identityX, - user, -}) => { - const omedaGraphQLClient = req[omedaGraphQLProp]; - if (!omedaGraphQLClient) throw new Error(`Unable to load the Omeda GraphQL API from the request using prop ${omedaGraphQLProp}`); - const idxOmedaRapidIdentify = req[idxOmedaRapidIdentifyProp]; - if (!idxOmedaRapidIdentify) throw new Error(`Unable to find the IdentityX+Omeda rapid identifier on the request using ${idxOmedaRapidIdentifyProp}`); +module.exports = async (params = {}) => { + const { + brandKey, + idxOmedaRapidIdentify, + omedaGraphQLClient, + omedaPromoCodeCookieName, + omedaPromoCodeDefault, + promoCode: hookDataPromoCode, + req, + service: identityX, + user, + } = validate(Joi.object({ + brandKey: Joi.string().required(), + idxOmedaRapidIdentify: Joi.function().required(), + omedaGraphQLClient: Joi.object().required(), + omedaPromoCodeCookieName: Joi.string().required(), + omedaPromoCodeDefault: Joi.string(), + promoCode: Joi.string(), + req: Joi.object().required(), + service: Joi.object().required(), + user: Joi.object().required(), + }).unknown(), params); const promoCode = extractPromoCode({ promoCode: hookDataPromoCode, diff --git a/packages/marko-web-omeda-identity-x/integration-hooks/on-logout.js b/packages/marko-web-omeda-identity-x/integration-hooks/on-logout.js index 78b547673..518483949 100644 --- a/packages/marko-web-omeda-identity-x/integration-hooks/on-logout.js +++ b/packages/marko-web-omeda-identity-x/integration-hooks/on-logout.js @@ -1,5 +1,12 @@ +const Joi = require('@parameter1/joi'); +const { validate } = require('@parameter1/joi/utils'); const olyticsCookie = require('@parameter1/base-cms-marko-web-omeda/olytics/customer-cookie'); -module.exports = ({ res }) => { +module.exports = (params = {}) => { + const { + res, + } = validate(Joi.object({ + res: Joi.object().required(), + }).unknown(), params); olyticsCookie.clearFrom(res); }; diff --git a/packages/marko-web-omeda-identity-x/integration-hooks/on-user-profile-update.js b/packages/marko-web-omeda-identity-x/integration-hooks/on-user-profile-update.js index 91f667e41..54d31bbec 100644 --- a/packages/marko-web-omeda-identity-x/integration-hooks/on-user-profile-update.js +++ b/packages/marko-web-omeda-identity-x/integration-hooks/on-user-profile-update.js @@ -1,15 +1,24 @@ +const Joi = require('@parameter1/joi'); +const { validate } = require('@parameter1/joi/utils'); const extractPromoCode = require('../utils/extract-promo-code'); -module.exports = async ({ - idxOmedaRapidIdentifyProp = '$idxOmedaRapidIdentify', - omedaPromoCodeCookieName = 'omeda_promo_code', - omedaPromoCodeDefault, - req, - user, - promoCode: hookDataPromoCode, -}) => { - const idxOmedaRapidIdentify = req[idxOmedaRapidIdentifyProp]; - if (!idxOmedaRapidIdentify) throw new Error(`Unable to find the IdentityX+Omeda rapid identifier on the request using ${idxOmedaRapidIdentifyProp}`); +module.exports = async (params = {}) => { + const { + idxOmedaRapidIdentify, + omedaPromoCodeCookieName, + omedaPromoCodeDefault, + promoCode: hookDataPromoCode, + req, + user, + } = validate(Joi.object({ + idxOmedaRapidIdentify: Joi.function().required(), + omedaPromoCodeCookieName: Joi.string().required(), + omedaPromoCodeDefault: Joi.string(), + promoCode: Joi.string(), + req: Joi.object().required(), + user: Joi.object().required(), + }).unknown(), params); + const promoCode = extractPromoCode({ promoCode: hookDataPromoCode, omedaPromoCodeCookieName, diff --git a/packages/marko-web-omeda-identity-x/middleware/rapid-identify.js b/packages/marko-web-omeda-identity-x/middleware/rapid-identify.js index 508ec09e7..79549a980 100644 --- a/packages/marko-web-omeda-identity-x/middleware/rapid-identify.js +++ b/packages/marko-web-omeda-identity-x/middleware/rapid-identify.js @@ -17,7 +17,10 @@ module.exports = ({ const omedaRapidIdentify = req[omedaRapidIdentifyProp]; if (!omedaRapidIdentify) throw new Error(`Unable to find the Omeda rapid identifier on the request using ${omedaRapidIdentifyProp}`); - const handler = async ({ user, promoCode } = {}) => idxOmedaRapidIdentify({ + const handler = async ({ + user, + promoCode, + } = {}) => idxOmedaRapidIdentify({ brandKey, productId, appUser: user, diff --git a/packages/marko-web-omeda-identity-x/package.json b/packages/marko-web-omeda-identity-x/package.json index f3606be92..759e14049 100644 --- a/packages/marko-web-omeda-identity-x/package.json +++ b/packages/marko-web-omeda-identity-x/package.json @@ -15,6 +15,7 @@ "@parameter1/base-cms-marko-web-omeda": "^2.103.0", "@parameter1/base-cms-object-path": "^2.75.1", "@parameter1/base-cms-utils": "^2.75.1", + "@parameter1/joi": "^1.2.10", "graphql": "^14.7.0", "graphql-tag": "^2.12.5" }, diff --git a/services/example-website/config/omeda-identity-x.js b/services/example-website/config/omeda-identity-x.js new file mode 100644 index 000000000..4f9fcdf7b --- /dev/null +++ b/services/example-website/config/omeda-identity-x.js @@ -0,0 +1,21 @@ +const { get } = require('@parameter1/base-cms-object-path'); +const idxConfig = require('./identity-x'); +const omedaConfig = require('./omeda'); + +module.exports = { + clientKey: omedaConfig.clientKey, + brandKey: omedaConfig.brandKey, + appId: omedaConfig.appId, + inputId: omedaConfig.inputId, + rapidIdentProductId: get(omedaConfig, 'rapidIdentification.productId'), + idxConfig, + + /** + * IdentityX hook customization + * + * If present, the specified behavior, demographic, and/or promo code will be used/appended when + * handling the relevant IdentityX hook event. + */ + + +}; diff --git a/services/example-website/config/omeda.js b/services/example-website/config/omeda.js index a45b7d21d..e61543a53 100644 --- a/services/example-website/config/omeda.js +++ b/services/example-website/config/omeda.js @@ -3,6 +3,5 @@ module.exports = { clientKey: process.env.OMEDA_CLIENT_KEY, appId: process.env.OMEDA_APP_ID, inputId: process.env.OMEDA_INPUT_ID, - graphqlUri: 'https://graphql.omeda.parameter1.com/', rapidIdentification: { productId: process.env.OMEDA_RAPID_IDENT_PRODUCT_ID }, }; diff --git a/services/example-website/config/site.js b/services/example-website/config/site.js index a461c8789..53ddb7aba 100644 --- a/services/example-website/config/site.js +++ b/services/example-website/config/site.js @@ -1,11 +1,13 @@ const identityX = require('./identity-x'); const omeda = require('./omeda'); +const omedaIdentityX = require('./omeda-identity-x'); const nativeX = require('./native-x'); const navigation = require('./navigation'); const newsletter = require('./newsletter'); const search = require('./search'); module.exports = { + omedaIdentityX, identityX, nativeX, navigation, diff --git a/services/example-website/index.js b/services/example-website/index.js index 24465367a..b4b3a620d 100644 --- a/services/example-website/index.js +++ b/services/example-website/index.js @@ -1,6 +1,6 @@ const { startServer } = require('@parameter1/base-cms-marko-web'); const omedaIdentityX = require('@parameter1/base-cms-marko-web-omeda-identity-x'); -const { set, get, getAsObject } = require('@parameter1/base-cms-object-path'); +const { set, getAsObject } = require('@parameter1/base-cms-object-path'); const contactUs = require('@parameter1/base-cms-marko-web-contact-us'); const omedaNewsletters = require('@parameter1/base-cms-marko-web-omeda/routes/omeda-newsletters'); const newsletterState = require('@parameter1/base-cms-marko-web-theme-monorail/middleware/newsletter-state'); @@ -45,16 +45,7 @@ module.exports = startServer({ set(app.locals, 'nativeX', nativeXConfig); // Setup IdentityX + Omeda - const omedaConfig = getAsObject(siteConfig, 'omeda'); - const idxConfig = getAsObject(siteConfig, 'identityX'); - omedaIdentityX(app, { - clientKey: omedaConfig.clientKey, - brandKey: omedaConfig.brandKey, - appId: omedaConfig.appId, - inputId: omedaConfig.inputId, - rapidIdentProductId: get(omedaConfig, 'rapidIdentification.productId'), - idxConfig, - idxRouteTemplates, - }); + const oidxConfig = getAsObject(siteConfig, 'omedaIdentityX'); + omedaIdentityX(app, { ...oidxConfig, idxRouteTemplates }); }, }).then(() => log('Website started!')).catch(e => setImmediate(() => { throw e; }));