diff --git a/api/src/channel/channel.service.ts b/api/src/channel/channel.service.ts index 62188a05..93802ef3 100644 --- a/api/src/channel/channel.service.ts +++ b/api/src/channel/channel.service.ts @@ -11,7 +11,7 @@ import { Request, Response } from 'express'; import { SubscriberService } from '@/chat/services/subscriber.service'; import { LIVE_CHAT_TEST_CHANNEL_NAME } from '@/extensions/channels/live-chat-tester/settings'; -import { OFFLINE_CHANNEL_NAME } from '@/extensions/channels/offline/settings'; +import { WEB_CHANNEL_NAME } from '@/extensions/channels/web/settings'; import { LoggerService } from '@/logger/logger.service'; import { SocketGet, @@ -72,7 +72,7 @@ export class ChannelService { /** * Retrieves the appropriate channel handler based on the channel name. * - * @param channelName - The name of the channel (messenger, offline, ...). + * @param channelName - The name of the channel (messenger, web, ...). * @returns The handler for the specified channel. */ public getChannelHandler>( @@ -99,19 +99,19 @@ export class ChannelService { } /** - * Handles a websocket request for the offline channel. + * Handles a websocket request for the web channel. * * @param req - The websocket request object. * @param res - The websocket response object. */ - @SocketGet(`/webhook/${OFFLINE_CHANNEL_NAME}/`) - @SocketPost(`/webhook/${OFFLINE_CHANNEL_NAME}/`) - handleWebsocketForOffline( + @SocketGet(`/webhook/${WEB_CHANNEL_NAME}/`) + @SocketPost(`/webhook/${WEB_CHANNEL_NAME}/`) + handleWebsocketForWebChannel( @SocketReq() req: SocketRequest, @SocketRes() res: SocketResponse, ) { - this.logger.log('Channel notification (Offline Socket) : ', req.method); - const handler = this.getChannelHandler(OFFLINE_CHANNEL_NAME); + this.logger.log('Channel notification (Web Socket) : ', req.method); + const handler = this.getChannelHandler(WEB_CHANNEL_NAME); return handler.handle(req, res); } @@ -165,7 +165,7 @@ export class ChannelService { ); // Update session (end user is both a user + subscriber) - req.session.offline = { + req.session.web = { profile: testSubscriber, isSocket: true, messageQueue: [], diff --git a/api/src/channel/lib/__test__/label.mock.ts b/api/src/channel/lib/__test__/label.mock.ts index af706bc5..a2a6082d 100644 --- a/api/src/channel/lib/__test__/label.mock.ts +++ b/api/src/channel/lib/__test__/label.mock.ts @@ -16,7 +16,7 @@ const baseLabel: Label = { name: '', label_id: { messenger: '', - offline: '', + web: '', dimelo: '', twitter: '', }, @@ -30,7 +30,7 @@ export const labelMock: Label = { name: 'label', label_id: { messenger: 'none', - offline: 'none', + web: 'none', dimelo: 'none', twitter: 'none', }, @@ -43,7 +43,7 @@ export const customerLabelsMock: Label[] = [ name: 'client', label_id: { messenger: 'none', - offline: 'none', + web: 'none', dimelo: 'none', twitter: 'none', }, @@ -54,7 +54,7 @@ export const customerLabelsMock: Label[] = [ name: 'profressional', label_id: { messenger: 'none', - offline: 'none', + web: 'none', dimelo: 'none', twitter: 'none', }, diff --git a/api/src/channel/lib/__test__/subscriber.mock.ts b/api/src/channel/lib/__test__/subscriber.mock.ts index e3c17f22..5f2bda7e 100644 --- a/api/src/channel/lib/__test__/subscriber.mock.ts +++ b/api/src/channel/lib/__test__/subscriber.mock.ts @@ -25,7 +25,7 @@ export const subscriberInstance: Subscriber = { lastvisit: new Date(), retainedFrom: new Date(), channel: { - name: 'offline-channel', + name: 'web-channel', }, labels: [], ...modelInstance, diff --git a/api/src/chat/controllers/label.controller.spec.ts b/api/src/chat/controllers/label.controller.spec.ts index f09ca847..7eb51ae0 100644 --- a/api/src/chat/controllers/label.controller.spec.ts +++ b/api/src/chat/controllers/label.controller.spec.ts @@ -173,7 +173,7 @@ describe('LabelController', () => { name: 'LABEL_2', label_id: { messenger: 'messenger', - offline: 'offline', + web: 'web', twitter: 'twitter', dimelo: 'dimelo', }, diff --git a/api/src/chat/services/block.service.spec.ts b/api/src/chat/services/block.service.spec.ts index 20fe0e18..066e6fee 100644 --- a/api/src/chat/services/block.service.spec.ts +++ b/api/src/chat/services/block.service.spec.ts @@ -24,10 +24,10 @@ import { ContentTypeModel } from '@/cms/schemas/content-type.schema'; import { Content, ContentModel } from '@/cms/schemas/content.schema'; import { ContentTypeService } from '@/cms/services/content-type.service'; import { ContentService } from '@/cms/services/content.service'; -import OfflineHandler from '@/extensions/channels/offline/index.channel'; -import { OFFLINE_CHANNEL_NAME } from '@/extensions/channels/offline/settings'; -import { Offline } from '@/extensions/channels/offline/types'; -import OfflineEventWrapper from '@/extensions/channels/offline/wrapper'; +import WebChannelHandler from '@/extensions/channels/web/index.channel'; +import { WEB_CHANNEL_NAME } from '@/extensions/channels/web/settings'; +import { Web } from '@/extensions/channels/web/types'; +import WebEventWrapper from '@/extensions/channels/web/wrapper'; import { LanguageRepository } from '@/i18n/repositories/language.repository'; import { LanguageModel } from '@/i18n/schemas/language.schema'; import { I18nService } from '@/i18n/services/i18n.service'; @@ -222,22 +222,22 @@ describe('BlockService', () => { describe('match', () => { const handlerMock = { - getName: jest.fn(() => OFFLINE_CHANNEL_NAME), - } as any as OfflineHandler; - const offlineEventGreeting = new OfflineEventWrapper( + getName: jest.fn(() => WEB_CHANNEL_NAME), + } as any as WebChannelHandler; + const webEventGreeting = new WebEventWrapper( handlerMock, { - type: Offline.IncomingMessageType.text, + type: Web.IncomingMessageType.text, data: { text: 'Hello', }, }, {}, ); - const offlineEventGetStarted = new OfflineEventWrapper( + const webEventGetStarted = new WebEventWrapper( handlerMock, { - type: Offline.IncomingMessageType.postback, + type: Web.IncomingMessageType.postback, data: { text: 'Get Started', payload: 'GET_STARTED', @@ -247,40 +247,37 @@ describe('BlockService', () => { ); it('should return undefined when no blocks are provided', async () => { - const result = await blockService.match([], offlineEventGreeting); + const result = await blockService.match([], webEventGreeting); expect(result).toBe(undefined); }); it('should return undefined for empty blocks', async () => { - const result = await blockService.match( - [blockEmpty], - offlineEventGreeting, - ); + const result = await blockService.match([blockEmpty], webEventGreeting); expect(result).toEqual(undefined); }); it('should return undefined for no matching labels', async () => { - offlineEventGreeting.setSender(subscriberWithoutLabels); - const result = await blockService.match(blocks, offlineEventGreeting); + webEventGreeting.setSender(subscriberWithoutLabels); + const result = await blockService.match(blocks, webEventGreeting); expect(result).toEqual(undefined); }); it('should match block text and labels', async () => { - offlineEventGreeting.setSender(subscriberWithLabels); - const result = await blockService.match(blocks, offlineEventGreeting); + webEventGreeting.setSender(subscriberWithLabels); + const result = await blockService.match(blocks, webEventGreeting); expect(result).toEqual(blockGetStarted); }); it('should match block with payload', async () => { - offlineEventGetStarted.setSender(subscriberWithLabels); - const result = await blockService.match(blocks, offlineEventGetStarted); + webEventGetStarted.setSender(subscriberWithLabels); + const result = await blockService.match(blocks, webEventGetStarted); expect(result).toEqual(blockGetStarted); }); it('should match block with nlp', async () => { - offlineEventGreeting.setSender(subscriberWithLabels); - offlineEventGreeting.setNLP(nlpEntitiesGreeting); - const result = await blockService.match(blocks, offlineEventGreeting); + webEventGreeting.setSender(subscriberWithLabels); + webEventGreeting.setNLP(nlpEntitiesGreeting); + const result = await blockService.match(blocks, webEventGreeting); expect(result).toEqual(blockGetStarted); }); }); @@ -502,7 +499,7 @@ describe('BlockService', () => { describe('processText', () => { const context: Context = { ...contextGetStartedInstance, - channel: 'offline-channel', + channel: 'web-channel', text: '', payload: undefined, nlp: { entities: [] }, diff --git a/api/src/chat/services/bot.service.spec.ts b/api/src/chat/services/bot.service.spec.ts index 4a864f16..d2acfc85 100644 --- a/api/src/chat/services/bot.service.spec.ts +++ b/api/src/chat/services/bot.service.spec.ts @@ -24,9 +24,9 @@ import { MenuModel } from '@/cms/schemas/menu.schema'; import { ContentTypeService } from '@/cms/services/content-type.service'; import { ContentService } from '@/cms/services/content.service'; import { MenuService } from '@/cms/services/menu.service'; -import { offlineEventText } from '@/extensions/channels/offline/__test__/events.mock'; -import OfflineHandler from '@/extensions/channels/offline/index.channel'; -import OfflineEventWrapper from '@/extensions/channels/offline/wrapper'; +import { webEventText } from '@/extensions/channels/web/__test__/events.mock'; +import WebChannelHandler from '@/extensions/channels/web/index.channel'; +import WebEventWrapper from '@/extensions/channels/web/wrapper'; import { HelperService } from '@/helper/helper.service'; import { LanguageRepository } from '@/i18n/repositories/language.repository'; import { LanguageModel } from '@/i18n/schemas/language.schema'; @@ -75,7 +75,7 @@ describe('BlockService', () => { let blockService: BlockService; let subscriberService: SubscriberService; let botService: BotService; - let handler: OfflineHandler; + let handler: WebChannelHandler; let eventEmitter: EventEmitter2; beforeAll(async () => { @@ -126,7 +126,7 @@ describe('BlockService', () => { ChannelService, MessageService, MenuService, - OfflineHandler, + WebChannelHandler, ContextVarService, ContextVarRepository, LanguageService, @@ -170,7 +170,7 @@ describe('BlockService', () => { botService = module.get(BotService); blockService = module.get(BlockService); eventEmitter = module.get(EventEmitter2); - handler = module.get(OfflineHandler); + handler = module.get(WebChannelHandler); }); afterEach(jest.clearAllMocks); @@ -183,38 +183,38 @@ describe('BlockService', () => { triggeredEvents.push(args); }); - const event = new OfflineEventWrapper(handler, offlineEventText, { + const event = new WebEventWrapper(handler, webEventText, { isSocket: false, ipAddress: '1.1.1.1', }); const [block] = await blockService.findAndPopulate({ patterns: ['Hi'] }); - const offlineSubscriber = await subscriberService.findOne({ - foreign_id: 'foreign-id-offline-1', + const webSubscriber = await subscriberService.findOne({ + foreign_id: 'foreign-id-web-1', }); - event.setSender(offlineSubscriber); + event.setSender(webSubscriber); let hasBotSpoken = false; const clearMock = jest .spyOn(botService, 'findBlockAndSendReply') .mockImplementation( ( - actualEvent: OfflineEventWrapper, + actualEvent: WebEventWrapper, actualConversation: Conversation, actualBlock: BlockFull, isFallback: boolean, ) => { expect(actualConversation).toEqualPayload({ - sender: offlineSubscriber.id, + sender: webSubscriber.id, active: true, next: [], context: { user: { - first_name: offlineSubscriber.first_name, - last_name: offlineSubscriber.last_name, + first_name: webSubscriber.first_name, + last_name: webSubscriber.last_name, language: 'en', - id: offlineSubscriber.id, + id: webSubscriber.id, }, user_location: { lat: 0, @@ -224,8 +224,8 @@ describe('BlockService', () => { nlp: null, payload: null, attempt: 0, - channel: 'offline-channel', - text: offlineEventText.data.text, + channel: 'web-channel', + text: webEventText.data.text, }, }); expect(actualEvent).toEqual(event); @@ -251,40 +251,40 @@ describe('BlockService', () => { triggeredEvents.push(args); }); - const event = new OfflineEventWrapper(handler, offlineEventText, { + const event = new WebEventWrapper(handler, webEventText, { isSocket: false, ipAddress: '1.1.1.1', }); - const offlineSubscriber = await subscriberService.findOne({ - foreign_id: 'foreign-id-offline-1', + const webSubscriber = await subscriberService.findOne({ + foreign_id: 'foreign-id-web-1', }); - event.setSender(offlineSubscriber); + event.setSender(webSubscriber); const clearMock = jest .spyOn(botService, 'handleIncomingMessage') .mockImplementation( async ( actualConversation: ConversationFull, - event: OfflineEventWrapper, + event: WebEventWrapper, ) => { expect(actualConversation).toEqualPayload({ next: [], - sender: offlineSubscriber, + sender: webSubscriber, active: true, context: { user: { - first_name: offlineSubscriber.first_name, - last_name: offlineSubscriber.last_name, + first_name: webSubscriber.first_name, + last_name: webSubscriber.last_name, language: 'en', - id: offlineSubscriber.id, + id: webSubscriber.id, }, user_location: { lat: 0, lon: 0 }, vars: {}, nlp: null, payload: null, attempt: 0, - channel: 'offline-channel', - text: offlineEventText.data.text, + channel: 'web-channel', + text: webEventText.data.text, }, }); expect(event).toEqual(event); @@ -304,14 +304,14 @@ describe('BlockService', () => { eventEmitter.on('hook:stats:entry', (...args) => { triggeredEvents.push(args); }); - const event = new OfflineEventWrapper(handler, offlineEventText, { + const event = new WebEventWrapper(handler, webEventText, { isSocket: false, ipAddress: '1.1.1.1', }); - const offlineSubscriber = await subscriberService.findOne({ - foreign_id: 'foreign-id-offline-2', + const webSubscriber = await subscriberService.findOne({ + foreign_id: 'foreign-id-web-2', }); - event.setSender(offlineSubscriber); + event.setSender(webSubscriber); const captured = await botService.processConversationMessage(event); expect(captured).toBe(false); diff --git a/api/src/extensions/channels/live-chat-tester/index.channel.ts b/api/src/extensions/channels/live-chat-tester/index.channel.ts index 6a47a317..ae62962a 100644 --- a/api/src/extensions/channels/live-chat-tester/index.channel.ts +++ b/api/src/extensions/channels/live-chat-tester/index.channel.ts @@ -19,7 +19,7 @@ import { LoggerService } from '@/logger/logger.service'; import { SettingService } from '@/setting/services/setting.service'; import { WebsocketGateway } from '@/websocket/websocket.gateway'; -import BaseWebChannelHandler from '../offline/base-web-channel'; +import BaseWebChannelHandler from '../web/base-web-channel'; import { LIVE_CHAT_TEST_CHANNEL_NAME } from './settings'; diff --git a/api/src/extensions/channels/live-chat-tester/settings.ts b/api/src/extensions/channels/live-chat-tester/settings.ts index b455ca5f..19f80b21 100644 --- a/api/src/extensions/channels/live-chat-tester/settings.ts +++ b/api/src/extensions/channels/live-chat-tester/settings.ts @@ -10,7 +10,7 @@ import { ChannelSetting } from '@/channel/types'; import { config } from '@/config'; import { SettingType } from '@/setting/schemas/types'; -import { Offline } from '../offline/types'; +import { Web } from '../web/types'; export const LIVE_CHAT_TEST_CHANNEL_NAME = 'live-chat-tester-channel'; @@ -19,74 +19,74 @@ export const LIVE_CHAT_TEST_CHANNEL_NAMESPACE = 'live_chat_tester_channel'; export default [ { group: LIVE_CHAT_TEST_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.verification_token, + label: Web.SettingLabel.verification_token, value: 'test', type: SettingType.text, }, { group: LIVE_CHAT_TEST_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.allowed_domains, + label: Web.SettingLabel.allowed_domains, value: config.frontendPath, type: SettingType.text, }, { group: LIVE_CHAT_TEST_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.start_button, + label: Web.SettingLabel.start_button, value: true, type: SettingType.checkbox, }, { group: LIVE_CHAT_TEST_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.input_disabled, + label: Web.SettingLabel.input_disabled, value: false, type: SettingType.checkbox, }, { group: LIVE_CHAT_TEST_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.persistent_menu, + label: Web.SettingLabel.persistent_menu, value: true, type: SettingType.checkbox, }, { group: LIVE_CHAT_TEST_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.greeting_message, + label: Web.SettingLabel.greeting_message, value: 'Welcome! Ready to start a conversation with our chatbot?', type: SettingType.textarea, }, { group: LIVE_CHAT_TEST_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.theme_color, + label: Web.SettingLabel.theme_color, value: 'teal', type: SettingType.select, options: ['teal', 'orange', 'red', 'green', 'blue', 'dark'], }, { group: LIVE_CHAT_TEST_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.show_emoji, + label: Web.SettingLabel.show_emoji, value: true, type: SettingType.checkbox, }, { group: LIVE_CHAT_TEST_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.show_file, + label: Web.SettingLabel.show_file, value: true, type: SettingType.checkbox, }, { group: LIVE_CHAT_TEST_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.show_location, + label: Web.SettingLabel.show_location, value: true, type: SettingType.checkbox, }, { group: LIVE_CHAT_TEST_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.allowed_upload_size, + label: Web.SettingLabel.allowed_upload_size, value: 2500000, type: SettingType.number, }, { group: LIVE_CHAT_TEST_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.allowed_upload_types, + label: Web.SettingLabel.allowed_upload_types, value: 'audio/mpeg,audio/x-ms-wma,audio/vnd.rn-realaudio,audio/x-wav,image/gif,image/jpeg,image/png,image/tiff,image/vnd.microsoft.icon,image/vnd.djvu,image/svg+xml,text/css,text/csv,text/html,text/plain,text/xml,video/mpeg,video/mp4,video/quicktime,video/x-ms-wmv,video/x-msvideo,video/x-flv,video/web,application/msword,application/vnd.ms-powerpoint,application/pdf,application/vnd.ms-excel,application/vnd.oasis.opendocument.presentation,application/vnd.oasis.opendocument.tex,application/vnd.oasis.opendocument.spreadsheet,application/vnd.oasis.opendocument.graphics,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/vnd.openxmlformats-officedocument.wordprocessingml.document', type: SettingType.textarea, diff --git a/api/src/extensions/channels/offline/i18n/en/title.json b/api/src/extensions/channels/offline/i18n/en/title.json deleted file mode 100644 index d6bda3c9..00000000 --- a/api/src/extensions/channels/offline/i18n/en/title.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "offline_channel": "Web Channel" -} diff --git a/api/src/extensions/channels/offline/i18n/fr/title.json b/api/src/extensions/channels/offline/i18n/fr/title.json deleted file mode 100644 index d9815c96..00000000 --- a/api/src/extensions/channels/offline/i18n/fr/title.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "offline_channel": "Canal Web" -} diff --git a/api/src/extensions/channels/offline/index.d.ts b/api/src/extensions/channels/offline/index.d.ts deleted file mode 100644 index 512aa6d4..00000000 --- a/api/src/extensions/channels/offline/index.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import DEFAULT_OFFLINE_SETTINGS, { - OFFLINE_CHANNEL_NAMESPACE, -} from './settings'; - -declare global { - interface Settings extends SettingTree {} -} - -declare module '@nestjs/event-emitter' { - interface IHookExtensionsOperationMap { - [OFFLINE_CHANNEL_NAMESPACE]: TDefinition< - object, - SettingMapByType - >; - } -} diff --git a/api/src/extensions/channels/offline/__test__/data.mock.ts b/api/src/extensions/channels/web/__test__/data.mock.ts similarity index 83% rename from api/src/extensions/channels/offline/__test__/data.mock.ts rename to api/src/extensions/channels/web/__test__/data.mock.ts index c136112f..ae5fcd29 100644 --- a/api/src/extensions/channels/offline/__test__/data.mock.ts +++ b/api/src/extensions/channels/web/__test__/data.mock.ts @@ -12,14 +12,14 @@ import { ButtonType } from '@/chat/schemas/types/button'; import { FileType } from '@/chat/schemas/types/message'; import { QuickReplyType } from '@/chat/schemas/types/quick-reply'; -import { Offline } from '../types'; +import { Web } from '../types'; -export const offlineText: Offline.OutgoingMessageBase = { - type: Offline.OutgoingMessageType.text, +export const webText: Web.OutgoingMessageBase = { + type: Web.OutgoingMessageType.text, data: textMessage, }; -export const offlineQuickReplies: Offline.OutgoingMessageBase = { +export const webQuickReplies: Web.OutgoingMessageBase = { data: { quick_replies: [ { @@ -35,10 +35,10 @@ export const offlineQuickReplies: Offline.OutgoingMessageBase = { ], text: 'Choose one option', }, - type: Offline.OutgoingMessageType.quick_replies, + type: Web.OutgoingMessageType.quick_replies, }; -export const offlineButtons: Offline.OutgoingMessageBase = { +export const webButtons: Web.OutgoingMessageBase = { data: { buttons: [ { @@ -56,10 +56,10 @@ export const offlineButtons: Offline.OutgoingMessageBase = { ], text: 'Hit one of these buttons :', }, - type: Offline.OutgoingMessageType.buttons, + type: Web.OutgoingMessageType.buttons, }; -export const offlineList: Offline.OutgoingMessageBase = { +export const webList: Web.OutgoingMessageBase = { data: { buttons: [ { @@ -95,10 +95,10 @@ export const offlineList: Offline.OutgoingMessageBase = { }, ], }, - type: Offline.OutgoingMessageType.list, + type: Web.OutgoingMessageType.list, }; -export const offlineCarousel: Offline.OutgoingMessageBase = { +export const webCarousel: Web.OutgoingMessageBase = { data: { elements: [ { @@ -127,10 +127,10 @@ export const offlineCarousel: Offline.OutgoingMessageBase = { }, ], }, - type: Offline.OutgoingMessageType.carousel, + type: Web.OutgoingMessageType.carousel, }; -export const offlineAttachment: Offline.OutgoingMessageBase = { +export const webAttachment: Web.OutgoingMessageBase = { data: { quick_replies: [ { @@ -142,5 +142,5 @@ export const offlineAttachment: Offline.OutgoingMessageBase = { type: FileType.image, url: 'http://localhost:4000/attachment/download/1/attachment.jpg', }, - type: Offline.OutgoingMessageType.file, + type: Web.OutgoingMessageType.file, }; diff --git a/api/src/extensions/channels/offline/__test__/events.mock.ts b/api/src/extensions/channels/web/__test__/events.mock.ts similarity index 60% rename from api/src/extensions/channels/offline/__test__/events.mock.ts rename to api/src/extensions/channels/web/__test__/events.mock.ts index 4ce0db10..334482be 100644 --- a/api/src/extensions/channels/offline/__test__/events.mock.ts +++ b/api/src/extensions/channels/web/__test__/events.mock.ts @@ -12,56 +12,55 @@ import { StdEventType, } from '@/chat/schemas/types/message'; -import { Offline } from '../types'; +import { Web } from '../types'; const img_url = 'http://demo.hexabot.ai/attachment/download/5c334078e2c41d11206bd152/myimage.png'; -// Offline events -const offlineEventPayload: Offline.Event = { - type: Offline.IncomingMessageType.postback, +// Web events +const webEventPayload: Web.Event = { + type: Web.IncomingMessageType.postback, data: { text: 'Get Started', payload: 'GET_STARTED', }, - author: 'offline-9be7aq09-b45a-452q-bcs0-f145b9qce1cad', - mid: 'offline-event-payload', + author: 'web-9be7aq09-b45a-452q-bcs0-f145b9qce1cad', + mid: 'web-event-payload', read: true, }; -export const offlineEventText: Offline.IncomingMessage = - { - type: Offline.IncomingMessageType.text, - data: { - text: 'Hello', - }, - author: 'offline-9qsdfgqxac09-f83a-452d-bca0-f1qsdqg457c1ad', - mid: 'offline-event-text', - read: true, - }; +export const webEventText: Web.IncomingMessage = { + type: Web.IncomingMessageType.text, + data: { + text: 'Hello', + }, + author: 'web-9qsdfgqxac09-f83a-452d-bca0-f1qsdqg457c1ad', + mid: 'web-event-text', + read: true, +}; -const offlineEventLocation: Offline.IncomingMessage = { - type: Offline.IncomingMessageType.location, +const webEventLocation: Web.IncomingMessage = { + type: Web.IncomingMessageType.location, data: { coordinates: { lat: 2.0545, lng: 12.2558, }, }, - author: 'offline-9beqsdqa09-b489a-438c-bqd0-f11buykkhl851ad', - mid: 'offline-event-location', + author: 'web-9beqsdqa09-b489a-438c-bqd0-f11buykkhl851ad', + mid: 'web-event-location', read: true, }; -const offlineEventFile: Offline.Event = { - type: Offline.IncomingMessageType.file, +const webEventFile: Web.Event = { + type: Web.IncomingMessageType.file, data: { type: FileType.image, url: img_url, size: 500, }, - author: 'offline-9be8ac09-b43a-432d-bca0-f11b98cec1ad', - mid: 'offline-event-file', + author: 'web-9be8ac09-b43a-432d-bca0-f11b98cec1ad', + mid: 'web-event-file', read: true, }; @@ -85,66 +84,66 @@ const fileChannelData = { ipAddress: '3.3.3.3', }; -export const offlineEvents: [string, Offline.IncomingMessage, any][] = [ +export const webEvents: [string, Web.IncomingMessage, any][] = [ [ 'Payload Event', - offlineEventPayload, + webEventPayload, { channelData: payloadChannelData, - id: offlineEventPayload.mid, + id: webEventPayload.mid, eventType: StdEventType.message, messageType: IncomingMessageType.postback, - payload: offlineEventPayload.data.payload, + payload: webEventPayload.data.payload, message: { - postback: offlineEventPayload.data.payload, - text: offlineEventPayload.data.text, + postback: webEventPayload.data.payload, + text: webEventPayload.data.text, }, }, ], [ 'Text Event', - offlineEventText, + webEventText, { channelData: textChannelData, - id: offlineEventText.mid, + id: webEventText.mid, eventType: StdEventType.message, messageType: IncomingMessageType.message, payload: undefined, message: { - text: offlineEventText.data.text, + text: webEventText.data.text, }, }, ], [ 'Location Event', - offlineEventLocation, + webEventLocation, { channelData: locationChannelData, - id: offlineEventLocation.mid, + id: webEventLocation.mid, eventType: StdEventType.message, messageType: IncomingMessageType.location, payload: { - type: Offline.IncomingMessageType.location, + type: Web.IncomingMessageType.location, coordinates: { - lat: offlineEventLocation.data.coordinates.lat, - lon: offlineEventLocation.data.coordinates.lng, + lat: webEventLocation.data.coordinates.lat, + lon: webEventLocation.data.coordinates.lng, }, }, message: { - type: Offline.IncomingMessageType.location, + type: Web.IncomingMessageType.location, coordinates: { - lat: offlineEventLocation.data.coordinates.lat, - lon: offlineEventLocation.data.coordinates.lng, + lat: webEventLocation.data.coordinates.lat, + lon: webEventLocation.data.coordinates.lng, }, }, }, ], [ 'File Event', - offlineEventFile, + webEventFile, { channelData: fileChannelData, - id: offlineEventFile.mid, + id: webEventFile.mid, eventType: StdEventType.message, messageType: IncomingMessageType.attachments, payload: { diff --git a/api/src/extensions/channels/offline/__test__/index.spec.ts b/api/src/extensions/channels/web/__test__/index.spec.ts similarity index 89% rename from api/src/extensions/channels/offline/__test__/index.spec.ts rename to api/src/extensions/channels/web/__test__/index.spec.ts index a25ed05d..4ad78dbe 100644 --- a/api/src/extensions/channels/offline/__test__/index.spec.ts +++ b/api/src/extensions/channels/web/__test__/index.spec.ts @@ -48,21 +48,21 @@ import { SocketRequest } from '@/websocket/utils/socket-request'; import { SocketResponse } from '@/websocket/utils/socket-response'; import { WebsocketGateway } from '@/websocket/websocket.gateway'; -import OfflineHandler from '../index.channel'; +import WebChannelHandler from '../index.channel'; import { - offlineAttachment, - offlineButtons, - offlineCarousel, - offlineList, - offlineQuickReplies, - offlineText, + webAttachment, + webButtons, + webCarousel, + webList, + webQuickReplies, + webText, } from './data.mock'; -describe('Offline Handler', () => { +describe('WebChannelHandler', () => { let subscriberService: SubscriberService; - let handler: OfflineHandler; - const offlineSettings = {}; + let handler: WebChannelHandler; + const webSettings = {}; beforeAll(async () => { const module: TestingModule = await Test.createTestingModule({ @@ -87,7 +87,7 @@ describe('Offline Handler', () => { chatbot: { lang: { default: 'fr' } }, })), getSettings: jest.fn(() => ({ - offline: offlineSettings, + web: webSettings, })), }, }, @@ -102,7 +102,7 @@ describe('Offline Handler', () => { MessageRepository, MenuService, MenuRepository, - OfflineHandler, + WebChannelHandler, EventEmitter2, LoggerService, { @@ -122,7 +122,7 @@ describe('Offline Handler', () => { ], }).compile(); subscriberService = module.get(SubscriberService); - handler = module.get(OfflineHandler); + handler = module.get(WebChannelHandler); }); afterAll(async () => { @@ -131,29 +131,29 @@ describe('Offline Handler', () => { it('should have correct name', () => { expect(handler).toBeDefined(); - expect(handler.getName()).toEqual('offline-channel'); + expect(handler.getName()).toEqual('web-channel'); }); it('should format text properly', () => { const formatted = handler._textFormat(textMessage, {}); - expect(formatted).toEqual(offlineText); + expect(formatted).toEqual(webText); }); it('should format quick replies properly', () => { const formatted = handler._quickRepliesFormat(quickRepliesMessage, {}); - expect(formatted).toEqual(offlineQuickReplies); + expect(formatted).toEqual(webQuickReplies); }); it('should format buttons properly', () => { const formatted = handler._buttonsFormat(buttonsMessage, {}); - expect(formatted).toEqual(offlineButtons); + expect(formatted).toEqual(webButtons); }); it('should format list properly', () => { const formatted = handler._listFormat(contentMessage, { content: contentMessage.options, }); - expect(formatted).toEqual(offlineList); + expect(formatted).toEqual(webList); }); it('should format carousel properly', () => { @@ -163,12 +163,12 @@ describe('Offline Handler', () => { display: OutgoingMessageFormat.carousel, }, }); - expect(formatted).toEqual(offlineCarousel); + expect(formatted).toEqual(webCarousel); }); it('should format attachment properly', () => { const formatted = handler._attachmentFormat(attachmentMessage, {}); - expect(formatted).toEqual(offlineAttachment); + expect(formatted).toEqual(webAttachment); }); it('creates a new subscriber if needed + set a new session', async () => { @@ -180,7 +180,7 @@ describe('Offline Handler', () => { user: {}, } as any as Request; - const generatedId = 'offline-test'; + const generatedId = 'web-test'; const clearMock = jest .spyOn(handler, 'generateId') .mockImplementation(() => generatedId); @@ -192,7 +192,7 @@ describe('Offline Handler', () => { agent: req.headers['user-agent'], ipAddress: '0.0.0.0', isSocket: false, - name: 'offline-channel', + name: 'web-channel', }, country: '', first_name: req.query.first_name, @@ -209,7 +209,7 @@ describe('Offline Handler', () => { }, {}); expect(subscriberAttrs).toEqual(expectedAttrs); expect(req.session).toEqual({ - offline: { + web: { isSocket: false, messageQueue: [], polling: false, @@ -222,7 +222,7 @@ describe('Offline Handler', () => { const subscriber2nd = await handler['getOrCreateSession'](req); expect(subscriber2nd.id).toBe(subscriber.id); expect(req.session).toEqual({ - offline: { + web: { isSocket: false, messageQueue: [], polling: false, @@ -232,9 +232,8 @@ describe('Offline Handler', () => { }); it('subscribes and returns the message history', async () => { - const subscriber = await subscriberService.findOneByForeignIdAndPopulate( - 'foreign-id-offline-1', - ); + const subscriber = + await subscriberService.findOneByForeignIdAndPopulate('foreign-id-web-1'); const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); const req = { @@ -257,7 +256,7 @@ describe('Offline Handler', () => { } as any as SocketResponse; req.session = { cookie: { originalMaxAge: 0 }, - offline: { + web: { isSocket: true, messageQueue: [], polling: false, diff --git a/api/src/extensions/channels/offline/__test__/wrapper.spec.ts b/api/src/extensions/channels/web/__test__/wrapper.spec.ts similarity index 78% rename from api/src/extensions/channels/offline/__test__/wrapper.spec.ts rename to api/src/extensions/channels/web/__test__/wrapper.spec.ts index 4abfc6b2..c206a6c0 100644 --- a/api/src/extensions/channels/offline/__test__/wrapper.spec.ts +++ b/api/src/extensions/channels/web/__test__/wrapper.spec.ts @@ -36,14 +36,14 @@ import { import { SocketEventDispatcherService } from '@/websocket/services/socket-event-dispatcher.service'; import { WebsocketGateway } from '@/websocket/websocket.gateway'; -import OfflineHandler from '../index.channel'; -import OfflineEventWrapper from '../wrapper'; +import WebChannelHandler from '../index.channel'; +import WebEventWrapper from '../wrapper'; -import { offlineEvents } from './events.mock'; +import { webEvents } from './events.mock'; -describe(`Offline event wrapper`, () => { - let handler: OfflineHandler; - const offlineSettings = {}; +describe(`Web event wrapper`, () => { + let handler: WebChannelHandler; + const webSettings = {}; beforeAll(async () => { const module: TestingModule = await Test.createTestingModule({ imports: [ @@ -65,7 +65,7 @@ describe(`Offline event wrapper`, () => { chatbot: { lang: { default: 'fr' } }, })), getSettings: jest.fn(() => ({ - offline: offlineSettings, + web: webSettings, })), }, }, @@ -86,7 +86,7 @@ describe(`Offline event wrapper`, () => { MessageRepository, MenuService, MenuRepository, - OfflineHandler, + WebChannelHandler, EventEmitter2, LoggerService, { @@ -105,7 +105,7 @@ describe(`Offline event wrapper`, () => { }, ], }).compile(); - handler = module.get(OfflineHandler); + handler = module.get(WebChannelHandler); }); afterAll(async () => { @@ -113,21 +113,18 @@ describe(`Offline event wrapper`, () => { await closeInMongodConnection(); }); - test.each(offlineEvents)( - 'should wrap event : %s', - (_testCase, e, expected) => { - const event = new OfflineEventWrapper( - handler as unknown as OfflineHandler, - e, - expected.channelData, - ); - expect(event.getChannelData()).toEqual(expected.channelData); - expect(event.getId()).toEqual(expected.id); - expect(event.getEventType()).toEqual(expected.eventType); - expect(event.getMessageType()).toEqual(expected.messageType); - expect(event.getPayload()).toEqual(expected.payload); - expect(event.getMessage()).toEqual(expected.message); - expect(event.getDeliveredMessages()).toEqual([]); - }, - ); + test.each(webEvents)('should wrap event : %s', (_testCase, e, expected) => { + const event = new WebEventWrapper( + handler as unknown as WebChannelHandler, + e, + expected.channelData, + ); + expect(event.getChannelData()).toEqual(expected.channelData); + expect(event.getId()).toEqual(expected.id); + expect(event.getEventType()).toEqual(expected.eventType); + expect(event.getMessageType()).toEqual(expected.messageType); + expect(event.getPayload()).toEqual(expected.payload); + expect(event.getMessage()).toEqual(expected.message); + expect(event.getDeliveredMessages()).toEqual([]); + }); }); diff --git a/api/src/extensions/channels/offline/base-web-channel.ts b/api/src/extensions/channels/web/base-web-channel.ts similarity index 90% rename from api/src/extensions/channels/offline/base-web-channel.ts rename to api/src/extensions/channels/web/base-web-channel.ts index 3b02c519..59e70f07 100644 --- a/api/src/extensions/channels/offline/base-web-channel.ts +++ b/api/src/extensions/channels/web/base-web-channel.ts @@ -58,9 +58,9 @@ import { SocketRequest } from '@/websocket/utils/socket-request'; import { SocketResponse } from '@/websocket/utils/socket-response'; import { WebsocketGateway } from '@/websocket/websocket.gateway'; -import { OFFLINE_CHANNEL_NAMESPACE } from './settings'; -import { Offline } from './types'; -import OfflineEventWrapper from './wrapper'; +import { WEB_CHANNEL_NAMESPACE } from './settings'; +import { Web } from './types'; +import WebEventWrapper from './wrapper'; @Injectable() export default abstract class BaseWebChannelHandler< @@ -92,7 +92,7 @@ export default abstract class BaseWebChannelHandler< } /** - * Verify offline websocket connection and return settings + * Verify web websocket connection and return settings * * @param client - The socket client */ @@ -138,20 +138,20 @@ export default abstract class BaseWebChannelHandler< } /** - * Adapt incoming message structure for offline channel + * Adapt incoming message structure for web channel * * @param incoming - Incoming message - * @returns Formatted offline message + * @returns Formatted web message */ private formatIncomingHistoryMessage( incoming: IncomingMessage, - ): Offline.IncomingMessageBase { + ): Web.IncomingMessageBase { // Format incoming message if ('type' in incoming.message) { if (incoming.message.type === PayloadType.location) { const coordinates = incoming.message.coordinates; return { - type: Offline.IncomingMessageType.location, + type: Web.IncomingMessageType.location, data: { coordinates: { lat: coordinates.lat, @@ -165,7 +165,7 @@ export default abstract class BaseWebChannelHandler< ? incoming.message.attachment[0] : incoming.message.attachment; return { - type: Offline.IncomingMessageType.file, + type: Web.IncomingMessageType.file, data: { type: attachment.type, url: attachment.payload.url, @@ -174,21 +174,21 @@ export default abstract class BaseWebChannelHandler< } } else { return { - type: Offline.IncomingMessageType.text, + type: Web.IncomingMessageType.text, data: incoming.message, }; } } /** - * Adapt the outgoing message structure for offline channel + * Adapt the outgoing message structure for web channel * * @param outgoing - The outgoing message - * @returns Formatted offline message + * @returns Formatted web message */ private formatOutgoingHistoryMessage( outgoing: OutgoingMessage, - ): Offline.OutgoingMessageBase { + ): Web.OutgoingMessageBase { // Format outgoing message if ('buttons' in outgoing.message) { return this._buttonsFormat(outgoing.message); @@ -212,13 +212,13 @@ export default abstract class BaseWebChannelHandler< } /** - * Adapt the message structure for offline channel + * Adapt the message structure for web channel * * @param messages - The messages to be formatted * * @returns Formatted message */ - private formatHistoryMessages(messages: AnyMessage[]): Offline.Message[] { + private formatHistoryMessages(messages: AnyMessage[]): Web.Message[] { return messages.map((anyMessage: AnyMessage) => { if ('sender' in anyMessage && anyMessage.sender) { return { @@ -227,7 +227,7 @@ export default abstract class BaseWebChannelHandler< read: true, // Temporary fix as read is false in the bd mid: anyMessage.mid, createdAt: anyMessage.createdAt, - } as Offline.IncomingMessage; + } as Web.IncomingMessage; } else { const outgoingMessage = anyMessage as OutgoingMessage; return { @@ -237,7 +237,7 @@ export default abstract class BaseWebChannelHandler< mid: outgoingMessage.mid, handover: !!outgoingMessage.handover, createdAt: outgoingMessage.createdAt, - } as Offline.OutgoingMessage; + } as Web.OutgoingMessage; } }); } @@ -254,8 +254,8 @@ export default abstract class BaseWebChannelHandler< req: Request | SocketRequest, until: Date = new Date(), n: number = 30, - ): Promise { - const profile = req.session?.offline?.profile; + ): Promise { + const profile = req.session?.web?.profile; if (profile) { const messages = await this.messageService.findHistoryUntilDate( profile, @@ -279,8 +279,8 @@ export default abstract class BaseWebChannelHandler< req: Request, since: Date = new Date(10e14), n: number = 30, - ): Promise { - const profile = req.session?.offline?.profile; + ): Promise { + const profile = req.session?.web?.profile; if (profile) { const messages = await this.messageService.findHistorySinceDate( profile, @@ -299,7 +299,7 @@ export default abstract class BaseWebChannelHandler< */ private async verifyToken(verificationToken: string) { const settings = - (await this.getSettings()) as Settings[typeof OFFLINE_CHANNEL_NAMESPACE]; + (await this.getSettings()) as Settings[typeof WEB_CHANNEL_NAMESPACE]; const verifyToken = settings.verification_token; if (!verifyToken) { @@ -326,7 +326,7 @@ export default abstract class BaseWebChannelHandler< req: Request | SocketRequest, res: Response | SocketResponse, ) { - const settings = await this.getSettings(); + const settings = await this.getSettings(); // If we have an origin header... if (req.headers && req.headers.origin) { // Get the allowed origins @@ -376,7 +376,7 @@ export default abstract class BaseWebChannelHandler< res: Response | SocketResponse, next: (profile: Subscriber) => void, ) { - if (!req.session?.offline?.profile?.id) { + if (!req.session?.web?.profile?.id) { this.logger.warn( 'Web Channel Handler : No session ID to be found!', req.session, @@ -385,8 +385,8 @@ export default abstract class BaseWebChannelHandler< .status(403) .json({ err: 'Web Channel Handler : Unauthorized!' }); } else if ( - ('isSocket' in req && !!req.isSocket !== req.session.offline.isSocket) || - !Array.isArray(req.session.offline.messageQueue) + ('isSocket' in req && !!req.isSocket !== req.session.web.isSocket) || + !Array.isArray(req.session.web.messageQueue) ) { this.logger.warn( 'Web Channel Handler : Mixed channel request or invalid session data!', @@ -396,7 +396,7 @@ export default abstract class BaseWebChannelHandler< .status(403) .json({ err: 'Web Channel Handler : Unauthorized!' }); } - next(req.session?.offline?.profile); + next(req.session?.web?.profile); } /** @@ -440,15 +440,15 @@ export default abstract class BaseWebChannelHandler< ): Promise { const data = req.query; // Subscriber has already a session - const sessionProfile = req.session?.offline?.profile; + const sessionProfile = req.session?.web?.profile; if (sessionProfile) { const subscriber = await this.subscriberService.findOneAndPopulate( sessionProfile.id, ); - if (!subscriber || !req.session.offline) { + if (!subscriber || !req.session.web) { throw new Error('Subscriber session was not persisted in DB'); } - req.session.offline.profile = subscriber; + req.session.web.profile = subscriber; return subscriber; } @@ -456,7 +456,7 @@ export default abstract class BaseWebChannelHandler< const newProfile: SubscriberCreateDto = { foreign_id: this.generateId(), first_name: data.first_name ? data.first_name.toString() : 'Anon.', - last_name: data.last_name ? data.last_name.toString() : 'Offline User', + last_name: data.last_name ? data.last_name.toString() : 'Web User', assignedTo: null, assignedAt: null, lastvisit: new Date(), @@ -481,7 +481,7 @@ export default abstract class BaseWebChannelHandler< avatar: null, }; - req.session.offline = { + req.session.web = { profile, isSocket: 'isSocket' in req && !!req.isSocket, messageQueue: [], @@ -507,9 +507,7 @@ export default abstract class BaseWebChannelHandler< .json({ err: 'Polling not authorized when using websockets' }); } // Session must be active - if ( - !(req.session && req.session.offline && req.session.offline.profile.id) - ) { + if (!(req.session && req.session.web && req.session.web.profile.id)) { this.logger.warn( 'Web Channel Handler : Must be connected to poll messages', ); @@ -519,7 +517,7 @@ export default abstract class BaseWebChannelHandler< } // Can only request polling once at a time - if (req.session && req.session.offline && req.session.offline.polling) { + if (req.session && req.session.web && req.session.web.polling) { this.logger.warn( 'Web Channel Handler : Poll rejected ... already requested', ); @@ -528,7 +526,7 @@ export default abstract class BaseWebChannelHandler< .json({ err: 'Poll rejected ... already requested' }); } - req.session.offline.polling = true; + req.session.web.polling = true; const fetchMessages = async (req: Request, res: Response, retrials = 1) => { try { @@ -539,8 +537,8 @@ export default abstract class BaseWebChannelHandler< setTimeout(async () => { await fetchMessages(req, res, retrials * 2); }, retrials * 1000); - } else if (req.session.offline) { - req.session.offline.polling = false; + } else if (req.session.web) { + req.session.web.polling = false; return res.status(200).json(messages.map((msg) => ['message', msg])); } else { this.logger.error( @@ -549,8 +547,8 @@ export default abstract class BaseWebChannelHandler< return res.status(500).json({ err: 'No session data' }); } } catch (err) { - if (req.session.offline) { - req.session.offline.polling = false; + if (req.session.web) { + req.session.web.polling = false; } this.logger.error('Web Channel Handler : Polling failed', err); return res.status(500).json({ err: 'Polling failed' }); @@ -560,7 +558,7 @@ export default abstract class BaseWebChannelHandler< } /** - * Allow the subscription to a offline's webhook after verification + * Allow the subscription to a web's webhook after verification * * @param req * @param res @@ -608,7 +606,7 @@ export default abstract class BaseWebChannelHandler< * @param filename */ private async storeAttachment( - upload: Omit, + upload: Omit, filename: string, next: ( err: Error | null, @@ -623,7 +621,7 @@ export default abstract class BaseWebChannelHandler< type: upload.type || 'text/txt', size: upload.size || 0, location: filename, - channel: { offline: {} }, + channel: { web: {} }, }); this.logger.debug( @@ -657,9 +655,9 @@ export default abstract class BaseWebChannelHandler< result: { type: string; url: string } | false, ) => void, ): Promise { - const data: Offline.IncomingMessage = req.body; + const data: Web.IncomingMessage = req.body; // Check if any file is provided - if (!req.session.offline) { + if (!req.session.web) { this.logger.debug('Web Channel Handler : No session provided'); return next(null, false); } @@ -682,7 +680,7 @@ export default abstract class BaseWebChannelHandler< // Store file as attachment const dirPath = path.join(config.parameters.uploadDir); const sanitizedFilename = sanitize( - `${req.session.offline.profile.id}_${+new Date()}_${upload.name}`, + `${req.session.web.profile.id}_${+new Date()}_${upload.name}`, ); const filePath = path.resolve(dirPath, sanitizedFilename); @@ -763,7 +761,7 @@ export default abstract class BaseWebChannelHandler< * * @returns The channel's data */ - protected getChannelData(req: Request | SocketRequest): Offline.ChannelData { + protected getChannelData(req: Request | SocketRequest): Web.ChannelData { return { isSocket: 'isSocket' in req && !!req.isSocket, ipAddress: this.getIpAddress(req), @@ -781,13 +779,13 @@ export default abstract class BaseWebChannelHandler< req: Request | SocketRequest, res: Response | SocketResponse, ): void { - const data: Offline.IncomingMessage = req.body; + const data: Web.IncomingMessage = req.body; this.validateSession(req, res, (profile) => { this.handleFilesUpload( req, res, // @ts-expect-error @TODO : This needs to be fixed at a later point @TODO - (err: Error, upload: Offline.IncomingMessageData) => { + (err: Error, upload: Web.IncomingMessageData) => { if (err) { this.logger.warn( 'Web Channel Handler : Unable to upload file ', @@ -802,7 +800,7 @@ export default abstract class BaseWebChannelHandler< data.data = upload; } const channelData = this.getChannelData(req); - const event: OfflineEventWrapper = new OfflineEventWrapper( + const event: WebEventWrapper = new WebEventWrapper( this, data, channelData, @@ -844,14 +842,14 @@ export default abstract class BaseWebChannelHandler< } /** - * Process incoming Offline data (finding out its type and assigning it to its proper handler) + * Process incoming Web Channel data (finding out its type and assigning it to its proper handler) * * @param req * @param res */ async handle(req: Request | SocketRequest, res: Response | SocketResponse) { const settings = await this.getSettings(); - // Offline messaging can be done through websockets or long-polling + // Web Channel messaging can be done through websockets or long-polling try { await this.checkRequest(req, res); if (req.method === 'GET') { @@ -887,7 +885,7 @@ export default abstract class BaseWebChannelHandler< .json({ err: 'Webhook received unknown command' }); } } else if (req.query._disconnect) { - req.session.offline = undefined; + req.session.web = undefined; return res.status(200).json({ _disconnect: true }); } else { // Handle webhook subscribe requests @@ -911,7 +909,7 @@ export default abstract class BaseWebChannelHandler< * @returns UUID */ generateId(): string { - return 'offline-' + uuidv4(); + return 'web-' + uuidv4(); } /** @@ -925,9 +923,9 @@ export default abstract class BaseWebChannelHandler< _textFormat( message: StdOutgoingTextMessage, _options?: BlockOptions, - ): Offline.OutgoingMessageBase { + ): Web.OutgoingMessageBase { return { - type: Offline.OutgoingMessageType.text, + type: Web.OutgoingMessageType.text, data: message, }; } @@ -943,9 +941,9 @@ export default abstract class BaseWebChannelHandler< _quickRepliesFormat( message: StdOutgoingQuickRepliesMessage, _options?: BlockOptions, - ): Offline.OutgoingMessageBase { + ): Web.OutgoingMessageBase { return { - type: Offline.OutgoingMessageType.quick_replies, + type: Web.OutgoingMessageType.quick_replies, data: { text: message.text, quick_replies: message.quickReplies, @@ -964,9 +962,9 @@ export default abstract class BaseWebChannelHandler< _buttonsFormat( message: StdOutgoingButtonsMessage, _options?: BlockOptions, - ): Offline.OutgoingMessageBase { + ): Web.OutgoingMessageBase { return { - type: Offline.OutgoingMessageType.buttons, + type: Web.OutgoingMessageType.buttons, data: { text: message.text, buttons: message.buttons, @@ -985,9 +983,9 @@ export default abstract class BaseWebChannelHandler< _attachmentFormat( message: StdOutgoingAttachmentMessage>, _options?: BlockOptions, - ): Offline.OutgoingMessageBase { - const payload: Offline.OutgoingMessageBase = { - type: Offline.OutgoingMessageType.file, + ): Web.OutgoingMessageBase { + const payload: Web.OutgoingMessageBase = { + type: Web.OutgoingMessageType.file, data: { type: message.attachment.type, url: message.attachment.payload.url, @@ -1007,10 +1005,7 @@ export default abstract class BaseWebChannelHandler< * * @returns An array of elements object */ - _formatElements( - data: any[], - options: BlockOptions, - ): Offline.MessageElement[] { + _formatElements(data: any[], options: BlockOptions): Web.MessageElement[] { if (!options.content || !options.content.fields) { throw new Error('Content options are missing the fields'); } @@ -1018,7 +1013,7 @@ export default abstract class BaseWebChannelHandler< const fields = options.content.fields; const buttons: Button[] = options.content.buttons; return data.map((item) => { - const element: Offline.MessageElement = { + const element: Web.MessageElement = { title: item[fields.title], buttons: item.buttons || [], }; @@ -1031,7 +1026,7 @@ export default abstract class BaseWebChannelHandler< if (!attachmentPayload.id) { // @deprecated this.logger.warn( - 'Offline Channel Handler: Attachment remote url has been deprecated', + 'Web Channel Handler: Attachment remote url has been deprecated', item, ); } @@ -1090,11 +1085,11 @@ export default abstract class BaseWebChannelHandler< _listFormat( message: StdOutgoingListMessage, options: BlockOptions, - ): Offline.OutgoingMessageBase { + ): Web.OutgoingMessageBase { const data = message.elements || []; const pagination = message.pagination; let buttons: Button[] = [], - elements: Offline.MessageElement[] = []; + elements: Web.MessageElement[] = []; // Items count min check if (!data.length) { @@ -1123,7 +1118,7 @@ export default abstract class BaseWebChannelHandler< } : {}; return { - type: Offline.OutgoingMessageType.list, + type: Web.OutgoingMessageType.list, data: { elements, buttons, @@ -1143,7 +1138,7 @@ export default abstract class BaseWebChannelHandler< _carouselFormat( message: StdOutgoingListMessage, options: BlockOptions, - ): Offline.OutgoingMessageBase { + ): Web.OutgoingMessageBase { const data = message.elements || []; // Items count min check if (data.length === 0) { @@ -1156,7 +1151,7 @@ export default abstract class BaseWebChannelHandler< // Populate items (elements/cards) with content const elements = this._formatElements(data, options); return { - type: Offline.OutgoingMessageType.carousel, + type: Web.OutgoingMessageType.carousel, data: { elements, }, @@ -1174,7 +1169,7 @@ export default abstract class BaseWebChannelHandler< _formatMessage( envelope: StdOutgoingEnvelope, options: BlockOptions, - ): Offline.OutgoingMessageBase { + ): Web.OutgoingMessageBase { switch (envelope.format) { case OutgoingMessageFormat.attachment: return this._attachmentFormat(envelope.message, options); @@ -1214,14 +1209,14 @@ export default abstract class BaseWebChannelHandler< } /** - * Send a Offline Message to the end-user + * Send a Web Channel Message to the end-user * * @param event - Incoming event/message being responded to * @param envelope - The message to be sent {format, message} * @param options - Might contain additional settings * @param _context - Contextual data * - * @returns The offline's response, otherwise an error + * @returns The web's response, otherwise an error */ async sendMessage( event: EventWrapper, @@ -1229,13 +1224,13 @@ export default abstract class BaseWebChannelHandler< options: BlockOptions, _context?: any, ): Promise<{ mid: string }> { - const messageBase: Offline.OutgoingMessageBase = this._formatMessage( + const messageBase: Web.OutgoingMessageBase = this._formatMessage( envelope, options, ); const subscriber = event.getSender(); - const message: Offline.OutgoingMessage = { + const message: Web.OutgoingMessage = { ...messageBase, mid: this.generateId(), author: 'chatbot', @@ -1296,9 +1291,9 @@ export default abstract class BaseWebChannelHandler< * * @param event - The message event received * - * @returns The offline's response, otherwise an error + * @returns The web's response, otherwise an error */ - async getUserData(event: OfflineEventWrapper): Promise { + async getUserData(event: WebEventWrapper): Promise { return event.getSender() as SubscriberCreateDto; } } diff --git a/api/src/extensions/channels/offline/i18n/en/label.json b/api/src/extensions/channels/web/i18n/en/label.json similarity index 100% rename from api/src/extensions/channels/offline/i18n/en/label.json rename to api/src/extensions/channels/web/i18n/en/label.json diff --git a/api/src/extensions/channels/web/i18n/en/title.json b/api/src/extensions/channels/web/i18n/en/title.json new file mode 100644 index 00000000..abf9d834 --- /dev/null +++ b/api/src/extensions/channels/web/i18n/en/title.json @@ -0,0 +1,3 @@ +{ + "web_channel": "Web Channel" +} diff --git a/api/src/extensions/channels/offline/i18n/fr/label.json b/api/src/extensions/channels/web/i18n/fr/label.json similarity index 100% rename from api/src/extensions/channels/offline/i18n/fr/label.json rename to api/src/extensions/channels/web/i18n/fr/label.json diff --git a/api/src/extensions/channels/web/i18n/fr/title.json b/api/src/extensions/channels/web/i18n/fr/title.json new file mode 100644 index 00000000..80a293ea --- /dev/null +++ b/api/src/extensions/channels/web/i18n/fr/title.json @@ -0,0 +1,3 @@ +{ + "web_channel": "Canal Web" +} diff --git a/api/src/extensions/channels/offline/index.channel.ts b/api/src/extensions/channels/web/index.channel.ts similarity index 91% rename from api/src/extensions/channels/offline/index.channel.ts rename to api/src/extensions/channels/web/index.channel.ts index db1073f1..8432892c 100644 --- a/api/src/extensions/channels/offline/index.channel.ts +++ b/api/src/extensions/channels/web/index.channel.ts @@ -20,11 +20,11 @@ import { SettingService } from '@/setting/services/setting.service'; import { WebsocketGateway } from '@/websocket/websocket.gateway'; import BaseWebChannelHandler from './base-web-channel'; -import { OFFLINE_CHANNEL_NAME } from './settings'; +import { WEB_CHANNEL_NAME } from './settings'; @Injectable() -export default class OfflineHandler extends BaseWebChannelHandler< - typeof OFFLINE_CHANNEL_NAME +export default class WebChannelHandler extends BaseWebChannelHandler< + typeof WEB_CHANNEL_NAME > { constructor( settingService: SettingService, @@ -39,7 +39,7 @@ export default class OfflineHandler extends BaseWebChannelHandler< websocketGateway: WebsocketGateway, ) { super( - OFFLINE_CHANNEL_NAME, + WEB_CHANNEL_NAME, settingService, channelService, logger, diff --git a/api/src/extensions/channels/web/index.d.ts b/api/src/extensions/channels/web/index.d.ts new file mode 100644 index 00000000..7ae6b00b --- /dev/null +++ b/api/src/extensions/channels/web/index.d.ts @@ -0,0 +1,16 @@ +import DEFAULT_WEB_CHANNEL_SETTINGS, { + WEB_CHANNEL_NAMESPACE, +} from './settings'; + +declare global { + interface Settings extends SettingTree {} +} + +declare module '@nestjs/event-emitter' { + interface IHookExtensionsOperationMap { + [WEB_CHANNEL_NAMESPACE]: TDefinition< + object, + SettingMapByType + >; + } +} diff --git a/api/src/extensions/channels/offline/package.json b/api/src/extensions/channels/web/package.json similarity index 82% rename from api/src/extensions/channels/offline/package.json rename to api/src/extensions/channels/web/package.json index 7c33567d..0da6429a 100644 --- a/api/src/extensions/channels/offline/package.json +++ b/api/src/extensions/channels/web/package.json @@ -1,7 +1,7 @@ { - "name": "hexabot-channel-offline", + "name": "hexabot-channel-web", "version": "2.0.0", "description": "The Web Channel Extension for Hexabot Chatbot / Agent Builder for website integration", "author": "Hexastack", "license": "AGPL-3.0-only" -} +} \ No newline at end of file diff --git a/api/src/extensions/channels/offline/settings.ts b/api/src/extensions/channels/web/settings.ts similarity index 63% rename from api/src/extensions/channels/offline/settings.ts rename to api/src/extensions/channels/web/settings.ts index d0189d3a..1011774c 100644 --- a/api/src/extensions/channels/offline/settings.ts +++ b/api/src/extensions/channels/web/settings.ts @@ -9,97 +9,97 @@ import { ChannelSetting } from '@/channel/types'; import { SettingType } from '@/setting/schemas/types'; -import { Offline } from './types'; +import { Web } from './types'; -export const OFFLINE_CHANNEL_NAME = 'offline-channel' as const; +export const WEB_CHANNEL_NAME = 'web-channel' as const; -export const OFFLINE_CHANNEL_NAMESPACE = 'offline_channel'; +export const WEB_CHANNEL_NAMESPACE = 'web_channel'; export default [ { - group: OFFLINE_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.verification_token, + group: WEB_CHANNEL_NAMESPACE, + label: Web.SettingLabel.verification_token, value: 'token123', type: SettingType.secret, }, { - group: OFFLINE_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.allowed_domains, + group: WEB_CHANNEL_NAMESPACE, + label: Web.SettingLabel.allowed_domains, value: 'http://localhost:8080,http://localhost:4000', type: SettingType.text, }, { - group: OFFLINE_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.start_button, + group: WEB_CHANNEL_NAMESPACE, + label: Web.SettingLabel.start_button, value: true, type: SettingType.checkbox, }, { - group: OFFLINE_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.input_disabled, + group: WEB_CHANNEL_NAMESPACE, + label: Web.SettingLabel.input_disabled, value: false, type: SettingType.checkbox, }, { - group: OFFLINE_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.persistent_menu, + group: WEB_CHANNEL_NAMESPACE, + label: Web.SettingLabel.persistent_menu, value: true, type: SettingType.checkbox, }, { - group: OFFLINE_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.greeting_message, + group: WEB_CHANNEL_NAMESPACE, + label: Web.SettingLabel.greeting_message, value: 'Welcome! Ready to start a conversation with our chatbot?', type: SettingType.textarea, }, { - group: OFFLINE_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.theme_color, + group: WEB_CHANNEL_NAMESPACE, + label: Web.SettingLabel.theme_color, value: 'teal', type: SettingType.select, options: ['teal', 'orange', 'red', 'green', 'blue', 'dark'], }, { - group: OFFLINE_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.window_title, + group: WEB_CHANNEL_NAMESPACE, + label: Web.SettingLabel.window_title, value: 'Widget Title', type: SettingType.text, }, { - group: OFFLINE_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.avatar_url, + group: WEB_CHANNEL_NAMESPACE, + label: Web.SettingLabel.avatar_url, value: 'https://eu.ui-avatars.com/api/?name=Hexa+Bot&size=64', type: SettingType.text, }, { - group: OFFLINE_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.show_emoji, + group: WEB_CHANNEL_NAMESPACE, + label: Web.SettingLabel.show_emoji, value: true, type: SettingType.checkbox, }, { - group: OFFLINE_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.show_file, + group: WEB_CHANNEL_NAMESPACE, + label: Web.SettingLabel.show_file, value: true, type: SettingType.checkbox, }, { - group: OFFLINE_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.show_location, + group: WEB_CHANNEL_NAMESPACE, + label: Web.SettingLabel.show_location, value: true, type: SettingType.checkbox, }, { - group: OFFLINE_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.allowed_upload_size, + group: WEB_CHANNEL_NAMESPACE, + label: Web.SettingLabel.allowed_upload_size, value: 2500000, type: SettingType.number, }, { - group: OFFLINE_CHANNEL_NAMESPACE, - label: Offline.SettingLabel.allowed_upload_types, + group: WEB_CHANNEL_NAMESPACE, + label: Web.SettingLabel.allowed_upload_types, value: 'audio/mpeg,audio/x-ms-wma,audio/vnd.rn-realaudio,audio/x-wav,image/gif,image/jpeg,image/png,image/tiff,image/vnd.microsoft.icon,image/vnd.djvu,image/svg+xml,text/css,text/csv,text/html,text/plain,text/xml,video/mpeg,video/mp4,video/quicktime,video/x-ms-wmv,video/x-msvideo,video/x-flv,video/web,application/msword,application/vnd.ms-powerpoint,application/pdf,application/vnd.ms-excel,application/vnd.oasis.opendocument.presentation,application/vnd.oasis.opendocument.tex,application/vnd.oasis.opendocument.spreadsheet,application/vnd.oasis.opendocument.graphics,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/vnd.openxmlformats-officedocument.wordprocessingml.document', type: SettingType.textarea, }, -] as const satisfies ChannelSetting[]; +] as const satisfies ChannelSetting[]; diff --git a/api/src/extensions/channels/offline/types.ts b/api/src/extensions/channels/web/types.ts similarity index 98% rename from api/src/extensions/channels/offline/types.ts rename to api/src/extensions/channels/web/types.ts index c202bdf3..7442f837 100644 --- a/api/src/extensions/channels/offline/types.ts +++ b/api/src/extensions/channels/web/types.ts @@ -11,7 +11,7 @@ import { Button, WebUrlButton } from '@/chat/schemas/types/button'; import { FileType } from '@/chat/schemas/types/message'; import { StdQuickReply } from '@/chat/schemas/types/quick-reply'; -export namespace Offline { +export namespace Web { export enum SettingLabel { secret = 'secret', verification_token = 'verification_token', @@ -39,7 +39,7 @@ export namespace Offline { }; export type RequestSession = { - offline?: { + web?: { profile: SubscriberFull; isSocket: boolean; messageQueue: any[]; @@ -61,7 +61,7 @@ export namespace Offline { file = 'file', } - export type EventType = Offline.StatusEventType | Offline.IncomingMessageType; + export type EventType = Web.StatusEventType | Web.IncomingMessageType; export enum OutgoingMessageType { text = 'text', diff --git a/api/src/extensions/channels/offline/wrapper.ts b/api/src/extensions/channels/web/wrapper.ts similarity index 88% rename from api/src/extensions/channels/offline/wrapper.ts rename to api/src/extensions/channels/web/wrapper.ts index 0331f5a7..e36ff5d9 100644 --- a/api/src/extensions/channels/offline/wrapper.ts +++ b/api/src/extensions/channels/web/wrapper.ts @@ -21,56 +21,56 @@ import { import { Payload } from '@/chat/schemas/types/quick-reply'; import BaseWebChannelHandler from './base-web-channel'; -import { Offline } from './types'; +import { Web } from './types'; -type OfflineEventAdapter = +type WebEventAdapter = | { eventType: StdEventType.unknown; messageType: never; - raw: Offline.Event; + raw: Web.Event; } | { eventType: StdEventType.read; messageType: never; - raw: Offline.StatusReadEvent; + raw: Web.StatusReadEvent; } | { eventType: StdEventType.delivery; messageType: never; - raw: Offline.StatusDeliveryEvent; + raw: Web.StatusDeliveryEvent; } | { eventType: StdEventType.typing; messageType: never; - raw: Offline.StatusTypingEvent; + raw: Web.StatusTypingEvent; } | { eventType: StdEventType.message; messageType: IncomingMessageType.message; - raw: Offline.IncomingMessage; + raw: Web.IncomingMessage; } | { eventType: StdEventType.message; messageType: | IncomingMessageType.postback | IncomingMessageType.quick_reply; - raw: Offline.IncomingMessage; + raw: Web.IncomingMessage; } | { eventType: StdEventType.message; messageType: IncomingMessageType.location; - raw: Offline.IncomingMessage; + raw: Web.IncomingMessage; } | { eventType: StdEventType.message; messageType: IncomingMessageType.attachments; - raw: Offline.IncomingMessage; + raw: Web.IncomingMessage; }; -export default class OfflineEventWrapper< +export default class WebEventWrapper< T extends BaseWebChannelHandler = BaseWebChannelHandler, -> extends EventWrapper { +> extends EventWrapper { /** * Constructor : channel's event wrapper * @@ -78,7 +78,7 @@ export default class OfflineEventWrapper< * @param event - The message event received * @param channelData - Channel's specific extra data {isSocket, ipAddress} */ - constructor(handler: T, event: Offline.Event, channelData: any) { + constructor(handler: T, event: Web.Event, channelData: any) { super(handler, event, channelData); } @@ -90,34 +90,34 @@ export default class OfflineEventWrapper< * * @param event - The message event received */ - _init(event: Offline.Event) { + _init(event: Web.Event) { switch (event.type) { - case Offline.StatusEventType.delivery: + case Web.StatusEventType.delivery: this._adapter.eventType = StdEventType.delivery; break; - case Offline.StatusEventType.read: + case Web.StatusEventType.read: this._adapter.eventType = StdEventType.read; break; - case Offline.StatusEventType.typing: + case Web.StatusEventType.typing: this._adapter.eventType = StdEventType.typing; break; - case Offline.IncomingMessageType.text: + case Web.IncomingMessageType.text: this._adapter.eventType = StdEventType.message; this._adapter.messageType = IncomingMessageType.message; break; - case Offline.IncomingMessageType.quick_reply: + case Web.IncomingMessageType.quick_reply: this._adapter.eventType = StdEventType.message; this._adapter.messageType = IncomingMessageType.quick_reply; break; - case Offline.IncomingMessageType.postback: + case Web.IncomingMessageType.postback: this._adapter.eventType = StdEventType.message; this._adapter.messageType = IncomingMessageType.postback; break; - case Offline.IncomingMessageType.location: + case Web.IncomingMessageType.location: this._adapter.eventType = StdEventType.message; this._adapter.messageType = IncomingMessageType.location; break; - case Offline.IncomingMessageType.file: + case Web.IncomingMessageType.file: this._adapter.eventType = StdEventType.message; this._adapter.messageType = IncomingMessageType.attachments; break; diff --git a/api/src/index.d.ts b/api/src/index.d.ts index b6c3f103..f0ec76e8 100644 --- a/api/src/index.d.ts +++ b/api/src/index.d.ts @@ -27,7 +27,7 @@ declare module 'express-session' { passport?: { user?: SessionUser; }; - offline?: { + web?: { profile?: T; isSocket: boolean; messageQueue: any[]; @@ -40,7 +40,7 @@ declare module 'express-session' { passport?: { user?: SessionUser; }; - offline?: { + web?: { profile?: SubscriberStub; isSocket: boolean; messageQueue: any[]; diff --git a/api/src/utils/test/fixtures/conversation.ts b/api/src/utils/test/fixtures/conversation.ts index b1770cf0..548a84b2 100644 --- a/api/src/utils/test/fixtures/conversation.ts +++ b/api/src/utils/test/fixtures/conversation.ts @@ -71,7 +71,7 @@ const conversations: ConversationCreateDto[] = [ { sender: '1', context: { - channel: 'offline-channel', + channel: 'web-channel', text: 'Hello', payload: '', nlp: { @@ -106,7 +106,7 @@ const conversations: ConversationCreateDto[] = [ foreign_id: '', labels: [], assignedTo: null, - channel: { name: 'offline-channel' }, + channel: { name: 'web-channel' }, }, skip: {}, attempt: 0, diff --git a/api/src/utils/test/fixtures/label.ts b/api/src/utils/test/fixtures/label.ts index b32be697..c38f5215 100644 --- a/api/src/utils/test/fixtures/label.ts +++ b/api/src/utils/test/fixtures/label.ts @@ -9,7 +9,7 @@ import mongoose from 'mongoose'; import { LabelCreateDto } from '@/chat/dto/label.dto'; -import { LabelModel, Label } from '@/chat/schemas/label.schema'; +import { Label, LabelModel } from '@/chat/schemas/label.schema'; import { getFixturesWithDefaultValues } from '../defaultValues'; import { TFixturesDefaultValues } from '../types'; @@ -19,7 +19,7 @@ export const labels: LabelCreateDto[] = [ description: 'test description 1', label_id: { messenger: 'messenger', - offline: 'offline', + web: 'web', twitter: 'twitter', dimelo: 'dimelo', }, @@ -30,7 +30,7 @@ export const labels: LabelCreateDto[] = [ description: 'test description 2', label_id: { messenger: 'messenger', - offline: 'offline', + web: 'web', twitter: 'twitter', dimelo: 'dimelo', }, diff --git a/api/src/utils/test/fixtures/subscriber.ts b/api/src/utils/test/fixtures/subscriber.ts index 62b890ca..605d7560 100644 --- a/api/src/utils/test/fixtures/subscriber.ts +++ b/api/src/utils/test/fixtures/subscriber.ts @@ -35,7 +35,7 @@ const subscribers: SubscriberCreateDto[] = [ retainedFrom: new Date('2020-01-01T20:40:03.249Z'), }, { - foreign_id: 'foreign-id-offline-1', + foreign_id: 'foreign-id-web-1', first_name: 'Maynard', last_name: 'James Keenan', language: 'en', @@ -43,7 +43,7 @@ const subscribers: SubscriberCreateDto[] = [ gender: 'male', country: 'US', channel: { - name: 'offline-channel', + name: 'web-channel', }, labels: [], assignedAt: null, @@ -51,7 +51,7 @@ const subscribers: SubscriberCreateDto[] = [ retainedFrom: new Date('2021-01-02T20:40:03.249Z'), }, { - foreign_id: 'foreign-id-offline-2', + foreign_id: 'foreign-id-web-2', first_name: 'Queen', last_name: 'Elisabeth', language: 'en', @@ -59,7 +59,7 @@ const subscribers: SubscriberCreateDto[] = [ gender: 'male', country: 'US', channel: { - name: 'offline-channel', + name: 'web-channel', }, labels: [], assignedAt: null, @@ -75,7 +75,7 @@ const subscribers: SubscriberCreateDto[] = [ gender: 'male', country: 'US', channel: { - name: 'offline-channel', + name: 'web-channel', }, labels: [], assignedAt: null, diff --git a/api/src/utils/test/mocks/conversation.ts b/api/src/utils/test/mocks/conversation.ts index ab90d76e..115b9d2f 100644 --- a/api/src/utils/test/mocks/conversation.ts +++ b/api/src/utils/test/mocks/conversation.ts @@ -16,7 +16,7 @@ import { modelInstance } from './misc'; import { subscriberInstance } from './subscriber'; export const contextBlankInstance: Context = { - channel: 'offline-channel', + channel: 'web-channel', text: '', payload: undefined, nlp: { entities: [] }, @@ -42,7 +42,7 @@ export const contextEmailVarInstance: Context = { }; export const contextGetStartedInstance: Context = { - channel: 'offline-channel', + channel: 'web-channel', text: 'Get Started', payload: 'GET_STARTED', nlp: { entities: [] }, diff --git a/api/src/utils/test/mocks/subscriber.ts b/api/src/utils/test/mocks/subscriber.ts index 54aa955d..8ec8ee83 100644 --- a/api/src/utils/test/mocks/subscriber.ts +++ b/api/src/utils/test/mocks/subscriber.ts @@ -25,7 +25,7 @@ export const subscriberInstance: Subscriber = { lastvisit: new Date(), retainedFrom: new Date(), channel: { - name: 'offline-channel', + name: 'web-channel', }, labels: [], ...modelInstance, diff --git a/api/src/websocket/websocket.gateway.spec.ts b/api/src/websocket/websocket.gateway.spec.ts index 690b3efe..6f7956b2 100644 --- a/api/src/websocket/websocket.gateway.spec.ts +++ b/api/src/websocket/websocket.gateway.spec.ts @@ -49,8 +49,8 @@ describe('WebsocketGateway', () => { ioClient = io('http://localhost:3000', { autoConnect: false, transports: ['websocket', 'polling'], - // path: '/socket.io/?EIO=4&transport=websocket&channel=offline', - query: { EIO: '4', transport: 'websocket', channel: 'offline' }, + // path: '/socket.io/?EIO=4&transport=websocket&channel=web', + query: { EIO: '4', transport: 'websocket', channel: 'web' }, }); app.listen(3000); diff --git a/api/src/websocket/websocket.gateway.ts b/api/src/websocket/websocket.gateway.ts index 371b0f90..d401fc2b 100644 --- a/api/src/websocket/websocket.gateway.ts +++ b/api/src/websocket/websocket.gateway.ts @@ -223,7 +223,7 @@ export class WebsocketGateway 'Unable to load session, creating a new one ...', err, ); - if (searchParams.get('channel') === 'offline') { + if (searchParams.get('channel') === 'web') { return this.createAndStoreSession(client, next); } else { return next(new Error('Unauthorized: Unknown session ID')); @@ -237,7 +237,7 @@ export class WebsocketGateway return next(new Error('Unable to parse session ID from cookie')); } } - } else if (searchParams.get('channel') === 'offline') { + } else if (searchParams.get('channel') === 'web') { return this.createAndStoreSession(client, next); } else { return next(new Error('Unauthorized to connect to WS')); diff --git a/docker/.env.example b/docker/.env.example index 71a3effb..3691d0ed 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -57,5 +57,5 @@ NEXT_PUBLIC_SSO_ENABLED=false # Widget APP_WIDGET_PORT=5173 REACT_APP_WIDGET_API_URL=http://${APP_DOMAIN}:${API_PORT} -REACT_APP_WIDGET_CHANNEL=offline +REACT_APP_WIDGET_CHANNEL=web REACT_APP_WIDGET_TOKEN=token123 diff --git a/frontend/public/locales/en/translation.json b/frontend/public/locales/en/translation.json index 5e55364e..1b902f60 100644 --- a/frontend/public/locales/en/translation.json +++ b/frontend/public/locales/en/translation.json @@ -216,12 +216,6 @@ "handled_by_me": "Assigned to me", "handled_by_chatbot": "Others", "settings": "Settings", - "facebook_settings": "Facebook", - "messenger": "Facebook Messenger", - "msbot": "Microsoft Bot Connector", - "offline": "Web Channel", - "twitter": "Twitter", - "dimelo": "Dimelo", "event_log": "Events Log", "log_entry": "Log entry", "dashboard": "Dashboard", @@ -304,11 +298,6 @@ "user_location_zipcode": "Zipcode", "user_location_streetName": "Street Name", "from_channels": "Target channels", - "messenger": "Facebook/Messenger", - "msbot": "Microsoft Bot Connector", - "offline": "Canal Web", - "twitter": "Twitter", - "dimelo": "Dimelo", "simple_text": "Simple Text", "quick_replies": "Quick Replies", "buttons": "Buttons", diff --git a/frontend/public/locales/fr/translation.json b/frontend/public/locales/fr/translation.json index e44ac4c0..19f67cf5 100644 --- a/frontend/public/locales/fr/translation.json +++ b/frontend/public/locales/fr/translation.json @@ -216,12 +216,6 @@ "handled_by_me": "Assignés à moi", "handled_by_chatbot": "Autres", "settings": "Paramètres", - "facebook_settings": "Paramètres Facebook", - "messenger": "Facebook Messenger", - "msbot": "Microsoft Bot Connector", - "offline": "Canal Web", - "twitter": "Twitter", - "dimelo": "Dimelo", "event_log": "Journal des événements", "log_entry": "Journal des entrées", "dashboard": "Tableau de bord", @@ -304,11 +298,6 @@ "user_location_zipcode": "Code postal", "user_location_streetName": "Adresse", "from_channels": "Cibler les canaux", - "messenger": "Facebook/Messenger", - "msbot": "Microsoft Bot Connector", - "offline": "Canal Web", - "twitter": "Twitter", - "dimelo": "Dimelo", "simple_text": "Texte simple", "quick_replies": "Réponses rapides", "buttons": "Boutons", diff --git a/widget/README.md b/widget/README.md index 041b9400..a25250ae 100644 --- a/widget/README.md +++ b/widget/README.md @@ -61,7 +61,7 @@ Once the widget is built, you can easily embed it into any webpage. Here's an ex ReactDOM.render( el(HexabotWidget, { apiUrl: 'https://api.yourdomain.com', - channel: 'offline-channel', + channel: 'web-channel', token: 'token123', }), domContainer, @@ -96,7 +96,7 @@ To prevent the website css from conflicting with the chat widget css, we can lev ReactDOM.render( React.createElement(HexabotWidget, { apiUrl: 'https://api.yourdomain.com', - channel: 'offline-channel', + channel: 'web-channel', token: 'token123', }), shadowContainer, diff --git a/widget/public/index.html b/widget/public/index.html index 00863784..b4e3f015 100644 --- a/widget/public/index.html +++ b/widget/public/index.html @@ -34,7 +34,7 @@ ReactDOM.render( React.createElement(HexabotWidget, { apiUrl: 'http://localhost:4000', - channel: 'offline-channel', + channel: 'web-channel', token: 'token123', }), shadowContainer, diff --git a/widget/src/main.tsx b/widget/src/main.tsx index f07a3165..82c9e53a 100644 --- a/widget/src/main.tsx +++ b/widget/src/main.tsx @@ -18,7 +18,7 @@ ReactDOM.createRoot(document.getElementById('root')!).render(