Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions app.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"id": "21b7d3ba-031b-41d9-8ff2-fbbfa081ae90",
"version": "1.2.2",
"version": "1.2.3",
"requiredApiVersion": "^1.17.0",
"iconFile": "icon.png",
"author": {
Expand All @@ -16,4 +16,4 @@
"IPostMessageSent",
"IUIKitLivechatInteractionHandler"
]
}
}
10 changes: 10 additions & 0 deletions config/Settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export enum AppSetting {
FallbackTargetDepartment = 'fallback_target_department',
DialogflowHandoverMessage = 'dialogflow_handover_message',
DialogflowServiceUnavailableMessage = 'dialogflow_service_unavailable_message',
DialogflowHandoverFailedMessage = 'dialogflow_no_agents_online_for_handover',
DialogflowCloseChatMessage = 'dialogflow_close_chat_message',
DialogflowHideQuickReplies = 'dialogflow_hide_quick_replies',
}
Expand Down Expand Up @@ -81,6 +82,15 @@ export const settings: Array<ISetting> = [
i18nDescription: 'dialogflow_handover_message_description',
required: false,
},
{
id: AppSetting.DialogflowHandoverFailedMessage,
public: true,
type: SettingType.STRING,
packageValue: '',
i18nLabel: 'dialogflow_handover_failed_message',
i18nDescription: 'dialogflow_handover_failed_message_description',
required: false,
},
{
id: AppSetting.DialogflowServiceUnavailableMessage,
public: true,
Expand Down
20 changes: 14 additions & 6 deletions endpoints/IncomingEndpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,19 @@ export class IncomingEndpoint extends ApiEndpoint {
this.app.getLogger().info(Logs.ENDPOINT_RECEIVED_REQUEST);

try {
await this.processRequest(read, modify, http, request.content);
return createHttpResponse(HttpStatusCode.OK, { 'Content-Type': Headers.CONTENT_TYPE_JSON }, { result: Response.SUCCESS });
const { statusCode = HttpStatusCode.OK, data = null } = await this.processRequest(read, modify, http, request.content);
return createHttpResponse(statusCode, { 'Content-Type': Headers.CONTENT_TYPE_JSON }, { ...data ? { ...data } : { result: Response.SUCCESS } });
} catch (error) {
this.app.getLogger().error(Logs.ENDPOINT_REQUEST_PROCESSING_ERROR, error);
return createHttpResponse(HttpStatusCode.INTERNAL_SERVER_ERROR, { 'Content-Type': Headers.CONTENT_TYPE_JSON }, { error: error.message });
}
}

private async processRequest(read: IRead, modify: IModify, http: IHttp, endpointContent: IActionsEndpointContent) {

private async processRequest(read: IRead,
modify: IModify,
http: IHttp,
endpointContent: IActionsEndpointContent,
): Promise<{ statusCode: HttpStatusCode, data?: { result?: string; error?: string } }> {
const { action, sessionId } = endpointContent;
if (!sessionId) { throw new Error(Logs.INVALID_SESSION_ID); }
switch (action) {
Expand All @@ -41,9 +44,12 @@ export class IncomingEndpoint extends ApiEndpoint {
case EndpointActionNames.HANDOVER:
const { actionData: { targetDepartment = '' } = {} } = endpointContent;
const room = await read.getRoomReader().getById(sessionId) as ILivechatRoom;
if (!room) { throw new Error(); }
if (!room || !room.isOpen) { throw new Error('Error! Invalid session Id. No active room found with the given session id'); }
const { visitor: { token: visitorToken } } = room;
await performHandover(this.app, modify, read, sessionId, visitorToken, targetDepartment);
const result = await performHandover(this.app, modify, read, sessionId, visitorToken, targetDepartment);
if (!result) {
return { statusCode: HttpStatusCode.CONFLICT, data: { error: Response.NO_AGENTS_ONLINE }};
}
break;
case EndpointActionNames.TRIGGER_EVENT:
const { actionData: { event = null } = {} } = endpointContent;
Expand All @@ -65,5 +71,7 @@ export class IncomingEndpoint extends ApiEndpoint {
default:
throw new Error(Logs.INVALID_ENDPOINT_ACTION);
}

return { statusCode: HttpStatusCode.OK, data: { result: Response.SUCCESS }};
}
}
1 change: 1 addition & 0 deletions enum/Http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export enum Headers {

export enum Response {
SUCCESS = 'Your request was processed successfully',
NO_AGENTS_ONLINE = 'Handover failed! No agents online',
}
1 change: 1 addition & 0 deletions enum/Logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ export enum Logs {
HTTP_REQUEST_ERROR = 'Error occurred while sending a HTTP Request',
CLOSE_CHAT_REQUEST_FAILED_ERROR = 'Error: Internal Server Error. Could not close the chat',
HANDOVER_REQUEST_FAILED_ERROR = 'Error occurred while processing handover. Details',
NO_AGENTS_ONLINE = 'Handover failed! No agents online',
}
4 changes: 3 additions & 1 deletion i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@
"dialogflow_close_chat_message": "Close Chat Message",
"dialogflow_close_chat_message_description": "This message will be sent automatically when a chat is closed",
"dialogflow_hide_quick_replies": "Hide Quick Replies",
"dialogflow_hide_quick_replies_description": "If enabled, then all quick-replies will hide when a visitor clicks on any one of them"
"dialogflow_hide_quick_replies_description": "If enabled, then all quick-replies will hide when a visitor clicks on any one of them",
"dialogflow_handover_failed_message": "Handover Failed Message",
"dialogflow_handover_failed_message_description": "The Bot will send this message to Visitor if the handover failed because no agents were online"
}
27 changes: 20 additions & 7 deletions lib/Room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,7 @@ export const closeChat = async (modify: IModify, read: IRead, rid: string) => {
if (!result) { throw new Error(Logs.CLOSE_CHAT_REQUEST_FAILED_ERROR); }
};

export const performHandover = async (app: IApp, modify: IModify, read: IRead, rid: string, visitorToken: string, targetDepartmentName?: string) => {

const handoverMessage: string = await getAppSettingValue(read, AppSetting.DialogflowHandoverMessage);
await createMessage(app, rid, read, modify, { text: handoverMessage ? handoverMessage : DefaultMessage.DEFAULT_DialogflowHandoverMessage });

export const performHandover = async (app: IApp, modify: IModify, read: IRead, rid: string, visitorToken: string, targetDepartmentName?: string): Promise<boolean> => {
const room: ILivechatRoom = (await read.getRoomReader().getById(rid)) as ILivechatRoom;
if (!room) { throw new Error(Logs.INVALID_ROOM_ID); }

Expand All @@ -65,13 +61,30 @@ export const performHandover = async (app: IApp, modify: IModify, read: IRead, r
livechatTransferData.targetDepartment = targetDepartment.id;
}

// check if any agent is online in the department where we're transferring this chat
const serviceOnline = await read.getLivechatReader().isOnlineAsync(livechatTransferData.targetDepartment);
if (!serviceOnline) {
const offlineMessage: string = await getAppSettingValue(read, AppSetting.DialogflowHandoverFailedMessage);
if (offlineMessage && offlineMessage.trim()) {
await createMessage(app, rid, read, modify, { text: offlineMessage });
}
return false;
}

const handoverMessage: string = await getAppSettingValue(read, AppSetting.DialogflowHandoverMessage);
await createMessage(app, rid, read, modify, { text: handoverMessage ? handoverMessage : DefaultMessage.DEFAULT_DialogflowHandoverMessage });

const result = await modify.getUpdater().getLivechatUpdater().transferVisitor(visitor, livechatTransferData)
.catch((error) => {
throw new Error(`${Logs.HANDOVER_REQUEST_FAILED_ERROR} ${error}`);
});
if (!result) {
const offlineMessage: string = await getAppSettingValue(read, AppSetting.DialogflowServiceUnavailableMessage);
const offlineMessage: string = await getAppSettingValue(read, AppSetting.DialogflowHandoverFailedMessage);
if (offlineMessage && offlineMessage.trim()) {
await createMessage(app, rid, read, modify, { text: offlineMessage });
}

await createMessage(app, rid, read, modify, { text: offlineMessage ? offlineMessage : DefaultMessage.DEFAULT_DialogflowServiceUnavailableMessage });
return false;
}
return true;
};