Commit 88a80338 authored by murtaza98's avatar murtaza98

add support for callback messages in the app

parent 58a70b79
......@@ -13,6 +13,7 @@ import { ILivechatMessage } from '@rocket.chat/apps-engine/definition/livechat';
import { IPostMessageSent } from '@rocket.chat/apps-engine/definition/messages';
import { IAppInfo } from '@rocket.chat/apps-engine/definition/metadata';
import { settings } from './config/Settings';
import { CallbackInputEndpoint } from './endpoints/CallbackInputEndpoint';
import { IncomingEndpoint } from './endpoints/IncomingEndpoint';
import { PostMessageSentHandler } from './handler/PostMessageSentHandler';
......@@ -36,6 +37,7 @@ export class AppsRasaApp extends App implements IPostMessageSent {
security: ApiSecurity.UNSECURE,
endpoints: [
new IncomingEndpoint(this),
new CallbackInputEndpoint(this),
],
});
await Promise.all(settings.map((setting) => configuration.settings.provideSetting(setting)));
......
{
"id": "646b8e7d-f1e1-419e-9478-10d0f5bc74d9",
"version": "0.0.1",
"version": "1.0.0",
"requiredApiVersion": "^1.15.0",
"iconFile": "icon.png",
"author": {
......
......@@ -6,6 +6,7 @@ export enum AppSetting {
RasaServiceUnavailableMessage = 'rasa_service_unavailable_message',
RasaHandoverMessage = 'rasa_handover_message',
RasaCloseChatMessage = 'rasa_close_chat_message',
RasaEnableCallbacks = 'rasa_enable_callbacks',
}
export const settings: Array<ISetting> = [
......@@ -52,4 +53,14 @@ export const settings: Array<ISetting> = [
i18nDescription: 'rasa_handover_message_description',
required: false,
},
{
id: AppSetting.RasaEnableCallbacks,
public: true,
type: SettingType.BOOLEAN,
packageValue: false,
value: false,
i18nLabel: 'rasa_callback_message',
i18nDescription: 'rasa_callback_message_description',
required: false,
},
];
import { HttpStatusCode, IHttp, IModify, IPersistence, IRead } from '@rocket.chat/apps-engine/definition/accessors';
import { ApiEndpoint, IApiEndpointInfo, IApiRequest, IApiResponse } from '@rocket.chat/apps-engine/definition/api';
import { Headers } from '../enum/Http';
import { IRasaMessage } from '../enum/Rasa';
import { createHttpResponse } from '../lib/Http';
import { createRasaMessage } from '../lib/Message';
import { parseSingleRasaMessage } from '../lib/Rasa';
export class CallbackInputEndpoint extends ApiEndpoint {
public path = 'callback';
public async post(request: IApiRequest,
endpoint: IApiEndpointInfo,
read: IRead,
modify: IModify,
http: IHttp,
persis: IPersistence): Promise<IApiResponse> {
this.app.getLogger().info('Endpoint received an request');
try {
await this.processRequest(read, modify, persis, request.content);
return createHttpResponse(HttpStatusCode.OK, { 'Content-Type': Headers.CONTENT_TYPE_JSON }, { result: 'Success' });
} catch (error) {
this.app.getLogger().error('Error occurred while processing the request. Details:- ', error);
return createHttpResponse(HttpStatusCode.INTERNAL_SERVER_ERROR, { 'Content-Type': Headers.CONTENT_TYPE_JSON }, { error: error.message });
}
}
private async processRequest(read: IRead, modify: IModify, persis: IPersistence, endpointContent: any) {
const message: IRasaMessage = parseSingleRasaMessage(endpointContent);
await createRasaMessage(message.sessionId, read, modify, message);
}
}
export interface IRasaMessage {
messages: Array<string | IRasaQuickReplies>;
message: string | IRasaQuickReplies;
sessionId: string;
}
export interface IRasaQuickReplies {
......
......@@ -45,7 +45,7 @@ export class PostMessageSentHandler {
return;
}
let response: IRasaMessage;
let response: Array<IRasaMessage> | null;
try {
response = await sendMessage(this.read, this.http, rid, text);
} catch (error) {
......@@ -57,7 +57,10 @@ export class PostMessageSentHandler {
return;
}
await createRasaMessage(rid, this.read, this.modify, response);
if (response) {
for (const message of response) {
await createRasaMessage(rid, this.read, this.modify, message);
}
}
}
}
......@@ -6,5 +6,7 @@
"rasa_handover_message": "Handover Message",
"rasa_handover_message_description": "The Bot will send this message to Visitor upon handover",
"rasa_close_chat_message": "Close Chat Message",
"rasa_close_chat_message_description": "This message will be sent automatically when a chat is closed"
"rasa_close_chat_message_description": "This message will be sent automatically when a chat is closed",
"rasa_callback_message": "Enable Callbacks",
"rasa_callback_message_description": "Enabling this setting will allow the app to use only callback messages. This feature is useful when you are using Reminder messages in your RASA bot."
}
......@@ -5,26 +5,22 @@ import { IRasaMessage, IRasaQuickReplies, IRasaQuickReply } from '../enum/Rasa';
import { getAppSettingValue } from './Setting';
export const createRasaMessage = async (rid: string, read: IRead, modify: IModify, rasaMessage: IRasaMessage): Promise<any> => {
const { messages = [] } = rasaMessage;
const { text, quickReplies } = rasaMessage.message as IRasaQuickReplies;
for (const message of messages) {
const { text, quickReplies } = message as IRasaQuickReplies;
if (text && quickReplies) {
// message is instanceof IRasaQuickReplies
const actions: Array<IMessageAction> = quickReplies.map((payload: IRasaQuickReply) => ({
type: MessageActionType.BUTTON,
text: payload.title,
msg: payload.payload,
msg_in_chat_window: true,
msg_processing_type: MessageProcessingType.SendMessage,
} as IMessageAction));
const attachment: IMessageAttachment = { actions };
await createMessage(rid, read, modify, { text, attachment });
} else {
// message is instanceof string
await createMessage(rid, read, modify, { text: message });
}
if (text && quickReplies) {
// rasaMessage is instanceof IRasaQuickReplies
const actions: Array<IMessageAction> = quickReplies.map((payload: IRasaQuickReply) => ({
type: MessageActionType.BUTTON,
text: payload.title,
msg: payload.payload,
msg_in_chat_window: true,
msg_processing_type: MessageProcessingType.SendMessage,
} as IMessageAction));
const attachment: IMessageAttachment = { actions };
await createMessage(rid, read, modify, { text, attachment });
} else {
// rasaMessage is instanceof string
await createMessage(rid, read, modify, { text: rasaMessage.message });
}
};
......
......@@ -5,42 +5,54 @@ import { IRasaMessage, IRasaQuickReplies, IRasaQuickReply } from '../enum/Rasa';
import { createHttpRequest } from './Http';
import { getAppSettingValue } from './Setting';
export const sendMessage = async (read: IRead, http: IHttp, sender: string, message: string): Promise<IRasaMessage> => {
export const sendMessage = async (read: IRead, http: IHttp, sender: string, message: string): Promise<Array<IRasaMessage> | null> => {
const rasaServerUrl = await getAppSettingValue(read, AppSetting.RasaServerUrl);
if (!rasaServerUrl) { throw new Error('Error! Rasa server url setting empty'); }
const callbackEnabled: boolean = await getAppSettingValue(read, AppSetting.RasaEnableCallbacks);
const httpRequestContent: IHttpRequest = createHttpRequest(
{ 'Content-Type': Headers.CONTENT_TYPE_JSON },
{ sender, message },
);
const rasaWebhookUrl = `${rasaServerUrl}/webhooks/rest/webhook`;
const rasaWebhookUrl = callbackEnabled ? `${rasaServerUrl}/webhooks/callback/webhook` : `${rasaServerUrl}/webhooks/rest/webhook`;
const response = await http.post(rasaWebhookUrl, httpRequestContent);
if (response.statusCode !== 200) { throw Error(`Error occured while interacting with Rasa Rest API. Details: ${response.content}`); }
if (response.statusCode !== 200) { throw Error(`Error occurred while interacting with Rasa Rest API. Details: ${response.content}`); }
const parsedMessage = parseRasaResponse(response.data);
return parsedMessage;
if (!callbackEnabled) {
const parsedMessage = parseRasaResponse(response.data);
return parsedMessage;
}
return null;
};
export const parseRasaResponse = (response: any): IRasaMessage => {
export const parseRasaResponse = (response: any): Array<IRasaMessage> => {
if (!response) { throw new Error('Error Parsing Rasa\'s Response. Data is undefined'); }
const messages: Array<string | IRasaQuickReplies> = [];
const messages: Array<IRasaMessage> = [];
response.forEach((message) => {
const { text, buttons } = message;
if (buttons) {
const quickReply: IRasaQuickReplies = {
text,
quickReplies: buttons,
};
messages.push(quickReply);
} else {
messages.push(text);
}
messages.push(parseSingleRasaMessage(message));
});
return {
messages,
};
return messages;
};
export const parseSingleRasaMessage = (message: any): IRasaMessage => {
const { recipient_id, text, buttons } = message;
if (buttons) {
const quickReplyMessage: IRasaQuickReplies = {
text,
quickReplies: buttons,
};
return {
message: quickReplyMessage,
sessionId: recipient_id,
};
} else {
return {
message: text,
sessionId: recipient_id,
};
}
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment