Channel data egress middleware (#118)
* Add util to create channel data egress middleware * Use channel data egress middleware * Rename optional parameters to default * Add tests for createChannelDataEgressMiddleware * Extract tags to constants * Add tests * Refactor * Refactor * Add test * Remove new line * Update CHANGELOG.md
This commit is contained in:
Родитель
6219e16286
Коммит
474110f229
|
@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file.
|
|||
- Add `runtimeId` attribute in `OmnichannelChatSDK` & `ChatSDKRuntimeId` field in telemetry
|
||||
- Add ability to automatically pass locale from chat config on calling `ChatSDK.emailLiveChatTranscript()`
|
||||
- Bubble up `WidgetUseOutsideOperatingHour` exception
|
||||
- Add `acs_webchat-chat-adapter` middleware to add default `channelData.tags` & `channelData.metadata`
|
||||
|
||||
### Fix
|
||||
- Add `acs_webchat-chat-adapter` middlewares to format `channelData.tags`
|
||||
|
|
106
__tests__/external/ACSAdapter/createChannelDataEgressMiddleware.spec.ts
поставляемый
Normal file
106
__tests__/external/ACSAdapter/createChannelDataEgressMiddleware.spec.ts
поставляемый
Normal file
|
@ -0,0 +1,106 @@
|
|||
import { channelIdTag, customerMessageTag } from "../../../src/core/messaging/MessageTags";
|
||||
import { DeliveryMode } from "../../../src/core/messaging/OmnichannelMessage";
|
||||
import createChannelDataEgressMiddleware from "../../../src/external/ACSAdapter/createChannelDataEgressMiddleware";
|
||||
|
||||
describe('createChannelDataEgressMiddleware', () => {
|
||||
it('createChannelDataEgressMiddleware should call next if there\'s no channel data', () => {
|
||||
const channelData = {
|
||||
widgetId: 'widgetId'
|
||||
};
|
||||
const next = jest.fn();
|
||||
const activity = {};
|
||||
|
||||
createChannelDataEgressMiddleware(channelData)()(next)(activity);
|
||||
|
||||
expect(next).toHaveBeenCalledWith(activity);
|
||||
});
|
||||
|
||||
it('createChannelDataEgressMiddleware should add basic tags if not set', () => {
|
||||
const channelData = {
|
||||
widgetId: 'widgetId'
|
||||
};
|
||||
const next = jest.fn();
|
||||
const activity = {
|
||||
channelData: {} as any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
};
|
||||
|
||||
createChannelDataEgressMiddleware(channelData)()(next)(activity);
|
||||
|
||||
expect(activity.channelData).toBeDefined();
|
||||
expect(activity.channelData.tags.includes(channelIdTag)).toBe(true);
|
||||
expect(activity.channelData.tags.includes(customerMessageTag)).toBe(true);
|
||||
expect(next).toHaveBeenCalledWith(activity);
|
||||
});
|
||||
|
||||
it('createChannelDataEgressMiddleware should add \'channelIdTag\' if not set', () => {
|
||||
const channelData = {
|
||||
widgetId: 'widgetId'
|
||||
};
|
||||
const next = jest.fn();
|
||||
const activity = {
|
||||
channelData: {
|
||||
tags: [customerMessageTag]
|
||||
} as any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
};
|
||||
|
||||
createChannelDataEgressMiddleware(channelData)()(next)(activity);
|
||||
|
||||
expect(activity.channelData).toBeDefined();
|
||||
expect(activity.channelData.tags.includes(channelIdTag)).toBe(true);
|
||||
expect(next).toHaveBeenCalledWith(activity);
|
||||
});
|
||||
|
||||
it('createChannelDataEgressMiddleware should add \'customerMessageTag\' if not set', () => {
|
||||
const channelData = {
|
||||
widgetId: 'widgetId'
|
||||
};
|
||||
const next = jest.fn();
|
||||
const activity = {
|
||||
channelData: {
|
||||
tags: [channelIdTag]
|
||||
} as any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
};
|
||||
|
||||
createChannelDataEgressMiddleware(channelData)()(next)(activity);
|
||||
|
||||
expect(activity.channelData).toBeDefined();
|
||||
expect(activity.channelData.tags.includes(customerMessageTag)).toBe(true);
|
||||
expect(next).toHaveBeenCalledWith(activity);
|
||||
});
|
||||
|
||||
it('createChannelDataEgressMiddleware should have deliveryMode as metadata if not set', () => {
|
||||
const channelData = {
|
||||
widgetId: 'widgetId'
|
||||
};
|
||||
const next = jest.fn();
|
||||
const activity = {
|
||||
channelData: {} as any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
};
|
||||
|
||||
createChannelDataEgressMiddleware(channelData)()(next)(activity);
|
||||
|
||||
expect(activity.channelData).toBeDefined();
|
||||
expect(activity.channelData.metadata).toBeDefined();
|
||||
expect(activity.channelData.metadata.deliveryMode).toBeDefined();
|
||||
expect(activity.channelData.metadata.deliveryMode).toBe(DeliveryMode.Bridged);
|
||||
expect(next).toHaveBeenCalledWith(activity);
|
||||
});
|
||||
|
||||
it('createChannelDataEgressMiddleware MUST have widgetId as metadata', () => {
|
||||
const channelData = {
|
||||
widgetId: 'widgetId'
|
||||
};
|
||||
const next = jest.fn();
|
||||
const activity = {
|
||||
channelData: {} as any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
};
|
||||
|
||||
createChannelDataEgressMiddleware(channelData)()(next)(activity);
|
||||
|
||||
expect(activity.channelData).toBeDefined();
|
||||
expect(activity.channelData.metadata).toBeDefined();
|
||||
expect(activity.channelData.metadata.widgetId).toBeDefined();
|
||||
expect(activity.channelData.metadata.widgetId).toBe(channelData.widgetId);
|
||||
expect(next).toHaveBeenCalledWith(activity);
|
||||
});
|
||||
});
|
|
@ -21,6 +21,7 @@ import ChatSDKConfig from "./core/ChatSDKConfig";
|
|||
import ChatSDKMessage from "./core/messaging/ChatSDKMessage";
|
||||
import ChatTranscriptBody from "./core/ChatTranscriptBody";
|
||||
import ConversationMode from "./core/ConversationMode";
|
||||
import createChannelDataEgressMiddleware from "./external/ACSAdapter/createChannelDataEgressMiddleware";
|
||||
import createFormatEgressTagsMiddleware from "./external/ACSAdapter/createFormatEgressTagsMiddleware";
|
||||
import createFormatIngressTagsMiddleware from "./external/ACSAdapter/createFormatIngressTagsMiddleware";
|
||||
import DeliveryMode from "@microsoft/omnichannel-ic3core/lib/model/DeliveryMode";
|
||||
|
@ -1445,15 +1446,19 @@ class OmnichannelChatSDK {
|
|||
if (protocol === ChatAdapterProtocols.ACS || this.liveChatVersion === LiveChatVersion.V2) {
|
||||
return new Promise (async (resolve, reject) => { // eslint-disable-line no-async-promise-executor
|
||||
const options = optionalParams.ACSAdapter? optionalParams.ACSAdapter.options: {};
|
||||
const egressMiddlewares = [createFormatEgressTagsMiddleware()];
|
||||
const ingressMiddlewares = [createFormatIngressTagsMiddleware()];
|
||||
|
||||
// Tags formatting middlewares are required to be the last in the pipeline to ensure tags are converted to the right format
|
||||
const defaultEgressMiddlewares = [createChannelDataEgressMiddleware({widgetId: this.omnichannelConfig.widgetId}), createFormatEgressTagsMiddleware()];
|
||||
const defaultIngressMiddlewares = [createFormatIngressTagsMiddleware()];
|
||||
const egressMiddleware = options?.egressMiddleware? [...options.egressMiddleware, ...defaultEgressMiddlewares]: [...defaultEgressMiddlewares];
|
||||
const ingressMiddleware = options?.ingressMiddleware? [...options.egressMiddleware, ...defaultIngressMiddlewares]: [...defaultIngressMiddlewares];
|
||||
const featuresOption = {
|
||||
enableAdaptiveCards: true, // Whether to enable adaptive card payload in adapter (payload in JSON string)
|
||||
enableThreadMemberUpdateNotification: true, // Whether to enable chat thread member join/leave notification
|
||||
enableLeaveThreadOnWindowClosed: false, // Whether to remove user on browser close event
|
||||
egressMiddleware: egressMiddlewares,
|
||||
ingressMiddleware: ingressMiddlewares,
|
||||
...options // overrides
|
||||
...options, // overrides
|
||||
ingressMiddleware,
|
||||
egressMiddleware
|
||||
};
|
||||
|
||||
const acsAdapterCDNUrl = this.resolveChatAdapterUrl(protocol || ChatAdapterProtocols.ACS);
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
export const defaultMessageTags = ['ChannelId-lcw', 'FromCustomer'];
|
||||
export const channelIdTag = 'ChannelId-lcw'; // Tag for PVA bot to return proper response for live chat channel
|
||||
export const customerMessageTag = 'FromCustomer'; // Tag to support transcript analytics feature
|
||||
export const defaultMessageTags = [channelIdTag, customerMessageTag];
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import { channelIdTag, customerMessageTag } from "../../core/messaging/MessageTags";
|
||||
import { DeliveryMode } from "../../core/messaging/OmnichannelMessage";
|
||||
|
||||
interface ChannelData {
|
||||
widgetId: string;
|
||||
}
|
||||
|
||||
const createChannelDataEgressMiddleware = (channelData: ChannelData): CallableFunction => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const channelDataMiddleware = () => (next: any) => (activity: any) => {
|
||||
const applicable = activity && activity.channelData;
|
||||
|
||||
if (applicable) {
|
||||
if (!activity.channelData.tags) {
|
||||
activity.channelData.tags = [];
|
||||
}
|
||||
|
||||
if (!activity.channelData.tags.includes(channelIdTag)) {
|
||||
activity.channelData.tags.push(channelIdTag);
|
||||
}
|
||||
|
||||
if (!activity.channelData.tags.includes(customerMessageTag)) {
|
||||
activity.channelData.tags.push(customerMessageTag);
|
||||
}
|
||||
|
||||
if (!activity.channelData.metadata) {
|
||||
activity.channelData.metadata = {};
|
||||
}
|
||||
|
||||
if (!activity.channelData.metadata.deliveryMode) {
|
||||
activity.channelData.metadata.deliveryMode = DeliveryMode.Bridged;
|
||||
}
|
||||
|
||||
if (channelData.widgetId) {
|
||||
activity.channelData.metadata.widgetId = channelData.widgetId;
|
||||
}
|
||||
}
|
||||
|
||||
return next(activity);
|
||||
}
|
||||
|
||||
return channelDataMiddleware;
|
||||
}
|
||||
|
||||
export default createChannelDataEgressMiddleware;
|
Загрузка…
Ссылка в новой задаче