diff --git a/src/definition/exceptions/UserNotAllowedException.ts b/src/definition/exceptions/UserNotAllowedException.ts index 987af7f4b..d81969d8f 100644 --- a/src/definition/exceptions/UserNotAllowedException.ts +++ b/src/definition/exceptions/UserNotAllowedException.ts @@ -9,5 +9,6 @@ import { AppsEngineException } from '.'; * following events: * - IPreRoomCreatePrevent * - IPreRoomUserJoined + * - IPreRoomUserLeave */ export class UserNotAllowedException extends AppsEngineException {} diff --git a/src/definition/metadata/AppInterface.ts b/src/definition/metadata/AppInterface.ts index 90f767ce6..4a1ca0bab 100644 --- a/src/definition/metadata/AppInterface.ts +++ b/src/definition/metadata/AppInterface.ts @@ -19,6 +19,8 @@ export enum AppInterface { IPostRoomDeleted = 'IPostRoomDeleted', IPreRoomUserJoined = 'IPreRoomUserJoined', IPostRoomUserJoined = 'IPostRoomUserJoined', + IPreRoomUserLeave = 'IPreRoomUserLeave', + IPostRoomUserLeave = 'IPostRoomUserLeave', // External Components IPostExternalComponentOpened = 'IPostExternalComponentOpened', IPostExternalComponentClosed = 'IPostExternalComponentClosed', diff --git a/src/definition/metadata/AppMethod.ts b/src/definition/metadata/AppMethod.ts index 9cd1941f2..c3126fb6d 100644 --- a/src/definition/metadata/AppMethod.ts +++ b/src/definition/metadata/AppMethod.ts @@ -46,6 +46,8 @@ export enum AppMethod { EXECUTEPOSTROOMDELETED = 'executePostRoomDeleted', EXECUTE_PRE_ROOM_USER_JOINED = 'executePreRoomUserJoined', EXECUTE_POST_ROOM_USER_JOINED = 'executePostRoomUserJoined', + EXECUTE_PRE_ROOM_USER_LEAVE = 'executePreRoomUserLeave', + EXECUTE_POST_ROOM_USER_LEAVE = 'executePostRoomUserLeave', // External Component handlers EXECUTEPOSTEXTERNALCOMPONENTOPENED = 'executePostExternalComponentOpened', EXECUTEPOSTEXTERNALCOMPONENTCLOSED = 'executePostExternalComponentClosed', diff --git a/src/definition/rooms/IPostRoomUserLeave.ts b/src/definition/rooms/IPostRoomUserLeave.ts new file mode 100644 index 000000000..c3eb41aac --- /dev/null +++ b/src/definition/rooms/IPostRoomUserLeave.ts @@ -0,0 +1,19 @@ +import { IHttp, IModify, IPersistence, IRead } from '../accessors'; +import { IRoomUserLeaveContext } from './IRoomUserLeaveContext'; + +/** + * Event interface that allows an app to + * register as a handler of the `IPostRoomUserLeave` + * event + * + * This event is triggered after an user succcessfully leaves + * a room. + * + * This event does not allow an app to prevent any action from + * happening. For that, see its "pre counterpart(s)": + * + * - IPreRoomUserLeave + */ +export interface IPostRoomUserLeave { + executePostRoomUserLeave(context: IRoomUserLeaveContext, read: IRead, http: IHttp, persistence: IPersistence, modify?: IModify): Promise; +} diff --git a/src/definition/rooms/IPreRoomUserLeave.ts b/src/definition/rooms/IPreRoomUserLeave.ts new file mode 100644 index 000000000..49405cd9b --- /dev/null +++ b/src/definition/rooms/IPreRoomUserLeave.ts @@ -0,0 +1,18 @@ +import { IHttp, IPersistence, IRead } from '../accessors'; +import { IRoomUserLeaveContext } from './IRoomUserLeaveContext'; + +/** + * Event interface that allows an app to + * register as a handler of the `IPreRoomUserLeave` + * event + * + * This event is triggered prior to an user succcessfully + * leaving a room. To prevent the user from executing + * such action, an app should throw the `UserNotAllowedException`. + * + * This event is not triggered before a room has been created. For that, + * check the `IPreRoomCreate` events + */ +export interface IPreRoomUserLeave { + executePreRoomUserLeave(context: IRoomUserLeaveContext, read: IRead, http: IHttp, persistence: IPersistence): Promise; +} diff --git a/src/definition/rooms/IRoomUserLeaveContext.ts b/src/definition/rooms/IRoomUserLeaveContext.ts new file mode 100644 index 000000000..c6aabc582 --- /dev/null +++ b/src/definition/rooms/IRoomUserLeaveContext.ts @@ -0,0 +1,18 @@ +import { IUser } from '../users'; +import { IRoom } from './IRoom'; + +/** + * The context of execution for the following events: + * - IPreRoomUserLeave + * - IPostRoomUserLeave + */ +export interface IRoomUserLeaveContext { + /** + * The user that is leaving the room + */ + leavingUser: IUser; + /** + * The room that the user is leaving + */ + room: IRoom; +} diff --git a/src/definition/rooms/index.ts b/src/definition/rooms/index.ts index 12b88c923..449ae7a2b 100644 --- a/src/definition/rooms/index.ts +++ b/src/definition/rooms/index.ts @@ -21,3 +21,6 @@ export { export * from './IPreRoomUserJoined'; export * from './IPostRoomUserJoined'; export * from './IRoomUserJoinedContext'; +export * from './IPreRoomUserLeave'; +export * from './IPostRoomUserLeave'; +export * from './IRoomUserLeaveContext'; diff --git a/src/server/managers/AppListenerManager.ts b/src/server/managers/AppListenerManager.ts index f91b34ca5..70895b954 100644 --- a/src/server/managers/AppListenerManager.ts +++ b/src/server/managers/AppListenerManager.ts @@ -3,7 +3,7 @@ import { IExternalComponent } from '../../definition/externalComponent'; import { ILivechatEventContext, ILivechatRoom, ILivechatTransferEventContext, IVisitor } from '../../definition/livechat'; import { IMessage } from '../../definition/messages'; import { AppInterface, AppMethod } from '../../definition/metadata'; -import { IRoom, IRoomUserJoinedContext } from '../../definition/rooms'; +import { IRoom, IRoomUserJoinedContext, IRoomUserLeaveContext } from '../../definition/rooms'; import { IUIKitIncomingInteraction, IUIKitResponse, IUIKitView, UIKitIncomingInteractionType } from '../../definition/uikit'; import { IUIKitLivechatIncomingInteraction, UIKitLivechatBlockInteractionContext } from '../../definition/uikit/livechat'; import { IUIKitIncomingInteractionMessageContainer, IUIKitIncomingInteractionModalContainer } from '../../definition/uikit/UIKitIncomingInteractionContainer'; @@ -31,6 +31,7 @@ type EventData = ( IExternalComponent | ILivechatEventContext | IRoomUserJoinedContext | + IRoomUserLeaveContext | ILivechatTransferEventContext | IFileUploadContext ); @@ -185,6 +186,10 @@ export class AppListenerManager { return this.executePreRoomUserJoined(data as IRoomUserJoinedContext); case AppInterface.IPostRoomUserJoined: return this.executePostRoomUserJoined(data as IRoomUserJoinedContext); + case AppInterface.IPreRoomUserLeave: + return this.executePreRoomUserLeave(data as IRoomUserLeaveContext); + case AppInterface.IPostRoomUserLeave: + return this.executePostRoomUserLeave(data as IRoomUserLeaveContext); // External Components case AppInterface.IPostExternalComponentOpened: this.executePostExternalComponentOpened(data as IExternalComponent); @@ -754,6 +759,47 @@ export class AppListenerManager { } } + private async executePreRoomUserLeave(externalData: IRoomUserLeaveContext): Promise { + const data = Utilities.deepClone(externalData); + + data.room = new Room(Utilities.deepFreeze(data.room), this.manager); + Utilities.deepFreeze(data.leavingUser); + + for (const appId of this.listeners.get(AppInterface.IPreRoomUserLeave)) { + const app = this.manager.getOneById(appId); + + if (app.hasMethod(AppMethod.EXECUTE_PRE_ROOM_USER_LEAVE)) { + await app.call(AppMethod.EXECUTE_PRE_ROOM_USER_LEAVE, + data, + this.am.getReader(appId), + this.am.getHttp(appId), + this.am.getPersistence(appId), + ); + } + } + } + + private async executePostRoomUserLeave(externalData: IRoomUserLeaveContext): Promise { + const data = Utilities.deepClone(externalData); + + data.room = new Room(Utilities.deepFreeze(data.room), this.manager); + Utilities.deepFreeze(data.leavingUser); + + for (const appId of this.listeners.get(AppInterface.IPostRoomUserLeave)) { + const app = this.manager.getOneById(appId); + + if (app.hasMethod(AppMethod.EXECUTE_POST_ROOM_USER_LEAVE)) { + await app.call(AppMethod.EXECUTE_POST_ROOM_USER_LEAVE, + data, + this.am.getReader(appId), + this.am.getHttp(appId), + this.am.getPersistence(appId), + this.am.getModifier(appId), + ); + } + } + } + // External Components private async executePostExternalComponentOpened(data: IExternalComponent): Promise { const cfExternalComponent = Utilities.deepCloneAndFreeze(data);