Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: WebEngage integration #557

Open
wants to merge 38 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
2a15002
Add. WE integration
Nov 2, 2023
9666929
Add. Logs with Descriptoin
Nov 2, 2023
9d2c997
fix. variations issue
Nov 2, 2023
aee967e
fix. variations issue 2 try
Nov 2, 2023
111cf6e
fix. variations issue 2 try logs
Nov 2, 2023
cac05cd
fix. variations issue- 3 try
Nov 2, 2023
7003745
fix. variations issue- 4 try
Nov 3, 2023
dff1fe0
fix. variations issue- 4 try
Nov 3, 2023
94ecd94
add. conversion api
Nov 3, 2023
c7820f0
add. new project - refactor. licenseKey & api
Nov 3, 2023
6f5afe2
revert api key
Nov 3, 2023
3093c24
disable onesignal
Nov 6, 2023
64f12c5
refactor. layoutId in Variation API
Nov 15, 2023
7c26f4b
refactor. conversion API
Nov 16, 2023
7e79a5e
refactor. remove logs
Nov 16, 2023
b8607ff
refactor. remove logs
Nov 16, 2023
272c6cb
refactor. license key & api
Nov 16, 2023
03d98be
refactor. test pn
Nov 16, 2023
0e2b081
refactor. applyFrequencyCapping
Nov 17, 2023
bc3a02a
refactor. baseUrl and Api Urls
Nov 17, 2023
0e4522a
refactor. apply review comments
Nov 17, 2023
fcf9a85
refactor. apply review comments 2
Nov 17, 2023
9e3c40e
refactor. apply review comments 2
Nov 17, 2023
01c484c
refactor. apply review comments 3
Nov 17, 2023
f311222
refactor. apply review comments 3
Nov 17, 2023
697a4e2
refactor. apply review comments 4
Nov 17, 2023
34cd185
Debug. Add logs - review code
Nov 17, 2023
1130df2
Debug. Add logs - review code
Nov 17, 2023
d15046e
Debug. Add logs - review code
Nov 17, 2023
7013354
Debug. Add logs - review code 2
Nov 17, 2023
1a1a8fe
Debug. Add logs - review code 2
Nov 17, 2023
eb4cc3a
Debug. Add logs - review code 3
Nov 17, 2023
e185fdf
Debug. Add logs - review code 4
Nov 17, 2023
053d94d
Refactor. remove logs
Nov 17, 2023
3a49a60
Refactor. add sw code
Nov 18, 2023
03bd903
Revert. gitignore
Nov 18, 2023
94e7f76
Refactor. apply review change
Nov 20, 2023
958de3f
Refactor. apply review changes
Nov 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions app/client/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import "../../app/assets/stylesheets/app.scss";
const opts = {
enableServiceWorker: process.env.NODE_ENV === "production",
appVersion: require("../isomorphic/app-version"),
preRenderApplication
preRenderApplication,
};

function enableHotReload(store) {
Expand All @@ -20,13 +20,11 @@ function enableHotReload(store) {
});
}
}

if (window.OneSignal) {
Object.assign(opts, {
serviceWorkerLocation: "/OneSignalSDKWorker.js"
serviceWorkerLocation: "/OneSignalSDKWorker.js",
});
}

global.wretch = wretch;

startApp(renderApplication, REDUCERS, opts).then(enableHotReload);
10 changes: 9 additions & 1 deletion app/server/app.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable no-console, no-unused-vars, import/extensions, object-shorthand, global-require */
import bodyParser from "body-parser";
import createApp from "@quintype/framework/server/create-app";
import { getClient, Collection } from "@quintype/framework/server/api-client";
import logger from "@quintype/framework/server/logger";
Expand All @@ -14,6 +15,8 @@ import { renderLayout } from "./handlers/render-layout";
import { loadData, loadErrorData } from "./load-data";
import { pickComponent } from "../isomorphic/pick-component";
import { generateStaticData, generateStructuredData, SEO } from "@quintype/seo";
import { enableWebengage } from "../../config/webengage-config";
import { handleWebEngageNotifications } from "./webengage/webengage-handler";

export const app = createApp();

Expand Down Expand Up @@ -72,7 +75,12 @@ app.get("*", (req, res, next) => {
return next();
}
});
// Begin webengage integration route
if (enableWebengage) {
app.post("/integrations/webengage/trigger-notification", bodyParser.json(), handleWebEngageNotifications);
}

// End webengage integration route
function generateSeo(config, pageType) {
return new SEO({
staticTags: Object.assign(generateStaticData(config)),
Expand Down Expand Up @@ -133,6 +141,6 @@ isomorphicRoutes(app, {
staticRoutes: STATIC_ROUTES,
seo: generateSeo,
preloadJs: true,
oneSignalServiceWorkers: true,
oneSignalServiceWorkers: false,
prerenderServiceUrl: "https://prerender.quintype.io",
});
12 changes: 6 additions & 6 deletions app/server/handlers/render-layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const fontJsContent = assetPath("font.js") ? readAsset("font.js") : "";
const allChunks = getAllChunks("list", "story", "home");

export async function renderLayout(res, params) {
const storeState = params.store.getState();
const {
gtmId,
gaId,
Expand All @@ -28,17 +29,15 @@ export async function renderLayout(res, params) {
loadAdsSynchronously,
pageType,
enableMetype,
} = getConfig(params.store.getState());
} = getConfig(storeState);
const chunk = params.shell ? null : allChunks[getChunkName(params.pageType)];
const criticalCss = await getCriticalCss();
const styleTags = await getStyleTags();
const arrowCss = await getArrowCss(params.store.getState());
const arrowCss = await getArrowCss(storeState);
const isProduction = process.env.NODE_ENV === "production";

const placeholderDelay = parseInt(
get(params.store.getState(), ["qt", "config", "publisher-attributes", "placeholder_delay"])
);

const placeholderDelay = parseInt(get(storeState, ["qt", "config", "publisher-attributes", "placeholder_delay"]));
const webengageLicenseCode = get(storeState, ["qt", "config", "webengage-config", "licenseCode"], "");
// Need to change this condition after static page api is fixed
const metadataHeader =
(pageType === "static-page" && params.metadata?.header && params.metadata?.header === true) ||
Expand All @@ -51,6 +50,7 @@ export async function renderLayout(res, params) {
"pages/layout",
Object.assign(
{
webengageLicenseCode,
isProduction,
assetPath: assetPath,
metadata: params.metadata,
Expand Down
21 changes: 12 additions & 9 deletions app/server/load-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { getNavigationMenuArray } from "./data-loaders/menu-data";
import { loadCollectionPageData } from "./data-loaders/collection-page-data";
import { loadAuthorPageData } from "./data-loaders/author-page-data";
import { PAGE_TYPE } from "../isomorphic/constants";
import webengageConfig from "../../config/webengage-config";

const { ads } = require("@quintype/framework/server/static-configuration");

Expand All @@ -27,10 +28,10 @@ const WHITELIST_CONFIG_KEYS = [
"publisher-name",
"public-integrations",
"sketches-host",
"publisher-settings"
"publisher-settings",
];

const svgSpritePath = Array.from(getAssetFiles()).find(asset => asset.includes("sprite"));
const svgSpritePath = Array.from(getAssetFiles()).find((asset) => asset.includes("sprite"));

export function getPublisherAttributes(publisherYml = publisher) {
const publisherAttributes = get(publisherYml, ["publisher"], {});
Expand All @@ -42,15 +43,16 @@ export function loadErrorData(error, config) {
const errorComponents = { 404: "not-found" };
return Promise.resolve({
data: {
navigationMenu: getNavigationMenuArray(config.layout.menu, config.sections)
navigationMenu: getNavigationMenuArray(config.layout.menu, config.sections),
},
config: Object.assign(pick(config.asJson(), WHITELIST_CONFIG_KEYS), {
"publisher-attributes": publisherAttributes,
"ads-config": ads,
svgSpritePath
svgSpritePath,
"webengage-config": webengageConfig,
}),
pageType: errorComponents[error.httpStatusCode],
httpStatusCode: error.httpStatusCode || 500
httpStatusCode: error.httpStatusCode || 500,
});
}

Expand Down Expand Up @@ -89,22 +91,23 @@ export function loadData(pageType, params, config, client, { host, next, domainS
}
}

return _loadData().then(data => {
return _loadData().then((data) => {
return {
httpStatusCode: data.httpStatusCode || 200,
pageType: data.pageType || pageType,
data: Object.assign({}, data, {
navigationMenu: getNavigationMenuArray(config.layout.menu, config.sections),
timezone: publisherAttributes.timezone || null
timezone: publisherAttributes.timezone || null,
}),
config: Object.assign(pick(config.asJson(), WHITELIST_CONFIG_KEYS), {
"publisher-attributes": publisherAttributes,
"image-cdn-format": "gumlet",
"ads-config": ads,
svgSpritePath,
domainSlug,
showPlaceholder: publisherAttributes.enable_placeholder
})
showPlaceholder: publisherAttributes.enable_placeholder,
"webengage-config": webengageConfig,
}),
};
});
}
39 changes: 39 additions & 0 deletions app/server/webengage/createCampaign.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import get from "lodash/get";
import fetch from "node-fetch";

async function createCampaign({ res, webhookContent, platform, url, webengageHeaders, logger }) {
const headline = get(webhookContent, ["headline"], "");
const title = get(webhookContent, ["title"], headline);
const TAGS = ["storypublish"];

const webRequestPayload = {
title,
sdks: null,
container: "ONETIME",
tags: TAGS,
experimentMetaData: { applyUCG: true },
applyUCG: true,
};

const appRequestPayload = {
title,
sdks: [2, 3],
container: "ONETIME",
tags: TAGS,
appIds: {},
};
const requestPayload = platform === "push-notifications" ? appRequestPayload : webRequestPayload;
try {
const apiResponse = await fetch(url, {
method: "POST",
body: JSON.stringify(requestPayload),
headers: webengageHeaders,
});
const audienceCreationResponse = await apiResponse.json();
return get(audienceCreationResponse, ["response", "data", "id"]);
} catch (e) {
logger.error("Error handling Audience/Campaign Creation : " + e);
res.status(503).send({ error: { message: "Audience/Campaign creation failure" } });
}
}
export default createCampaign;
46 changes: 46 additions & 0 deletions app/server/webengage/createConversion.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import fetch from "node-fetch";
import get from "lodash/get";
import { licenseCode } from "../../../config/webengage-config";

async function createConversion({ res, webhookContent, url, campaignId, webengageHeaders, logger }) {
const headline = get(webhookContent, ["headline"], "");
const title = get(webhookContent, ["title"], headline);
const requestPayload = {
deadline: "+7d",
experiment: `${campaignId}`,
licenseCode: `${licenseCode}`,
controlGroup: 0,
name: title,
triggerSet: {
triggers: [
{
name: "Trigger ",
category: "application",
type: "EVENT",
timeDifference: "",
timeAttribute: {
name: "event_time",
category: "system",
},
filters: null,
},
],
},
version: 2,
status: "ACTIVE",
};

try {
const response = await fetch(url, {
method: "POST",
body: JSON.stringify(requestPayload),
headers: webengageHeaders,
});
await response.json();
} catch (e) {
logger.error("Error handling createConversion Creation : " + e);
res.status(503).send({ error: { message: "Conversion creation failure" } });
}
}

export default createConversion;
90 changes: 90 additions & 0 deletions app/server/webengage/createVariation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import get from "lodash/get";
import {
webPushTextLayoutId,
appPushTextLayoutId,
appPushBannerLayoutId,
icon,
} from "../../../config/webengage-config";
import fetch from "node-fetch";

async function createVariation({
res,
webhookContent,
platform,
url,
sketchesHost,
eventType,
cdnName,
webengageHeaders,
logger,
}) {
const headline = get(webhookContent, ["headline"], "");
const title = get(webhookContent, ["title"], headline);
const message = get(webhookContent, ["message"], "");
const subheadline = get(webhookContent, ["subheadline"], "");
const storyUrl = get(webhookContent, ["story-url"], "");
const slug = `${sketchesHost}/${get(webhookContent, ["slug"], "")}`;
const STORY_PUBLISH_EVENT = "story-publish";
const heroImage =
eventType === STORY_PUBLISH_EVENT
? `${cdnName}${get(webhookContent, ["v1", "data", "hero-image-s3-key"])}`
: get(webhookContent, ["hero-image-url"], "");

const webRequestPayload = [
{
layoutEId: webPushTextLayoutId,
title,
description: message || subheadline,
sampling: 100,
icon,
requireInteraction: true,
cta: { actionText: "NA", actionLink: storyUrl || slug, type: "EXTERNAL_URL", isPrime: true },
},
];
const appPushRequestPayload = [
{
sampling: 50,
layoutEId: appPushTextLayoutId,
title,
message: message || subheadline,
androidDetails: {
expandableDetails: {},
},
iosDetails: {
expandableDetails: {},
},
},
{
sampling: 50,
layoutEId: appPushBannerLayoutId,
experimentVariationStatus: "ACTIVE",
title,
message: message || subheadline,
androidDetails: {
expandableDetails: {
image: heroImage,
},
},
iosDetails: {
expandableDetails: {
image: heroImage,
},
},
},
];
const requestPayload = platform === "push-notifications" ? appPushRequestPayload : webRequestPayload;

try {
const response = await fetch(url, {
method: "PUT",
body: JSON.stringify(requestPayload),
headers: webengageHeaders,
});
await response.json();
} catch (e) {
logger.error("Error handling Variation Creation : " + e);
res.status(503).send({ error: { message: "Variation creation failure" } });
}
}

export default createVariation;
12 changes: 12 additions & 0 deletions app/server/webengage/launchCampaign.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import fetch from "node-fetch";
async function launchCampaign({ res, url, webengageHeaders, logger }) {
try {
const response = await fetch(url, { method: "PUT", headers: webengageHeaders });
await response.json();
} catch (e) {
logger.error("Error handling launch Campaign:", +e);
res.status(503).send({ error: { message: "Campaign activation failure" } });
}
}

export default launchCampaign;
35 changes: 35 additions & 0 deletions app/server/webengage/scheduleCampaign.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import fetch from "node-fetch";
async function scheduleCampaign({ res, url, webengageHeaders, logger }) {
const requestPayload = {
trafficSegmentDto: {},
scheduler: {
sendNow: true,
sendInTz: "ACCOUNT",
sendIntelligently: false,
time: null,
},
triggerSet: null,
oneTime: true,
queueMessage: true,
ttl: 86400,
applyFrequencyCapping: true,
incrementFrequencyCappingCount: true,
applyDnd: true,
startDate: null,
endDate: null,
};

try {
const response = await fetch(url, {
method: "POST",
body: JSON.stringify(requestPayload),
headers: webengageHeaders,
});
await response.json();
} catch (e) {
logger.error("Error handling ScheduleCampaign : " + e);
res.status(503).send({ error: { message: "ScheduleCampaign failure" } });
}
}

export default scheduleCampaign;
Loading