You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
383 lines
12 KiB
383 lines
12 KiB
import type { IModifyCreator } from '@rocket.chat/apps-engine/definition/accessors/IModifyCreator.ts';
|
|
import type { IUploadCreator } from '@rocket.chat/apps-engine/definition/accessors/IUploadCreator.ts';
|
|
import type { IEmailCreator } from '@rocket.chat/apps-engine/definition/accessors/IEmailCreator.ts';
|
|
import type { IContactCreator } from '@rocket.chat/apps-engine/definition/accessors/IContactCreator.ts';
|
|
import type { ILivechatCreator } from '@rocket.chat/apps-engine/definition/accessors/ILivechatCreator.ts';
|
|
import type { IMessage } from '@rocket.chat/apps-engine/definition/messages/IMessage.ts';
|
|
import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom.ts';
|
|
import type { IBotUser } from '@rocket.chat/apps-engine/definition/users/IBotUser.ts';
|
|
import type { UserType as _UserType } from '@rocket.chat/apps-engine/definition/users/UserType.ts';
|
|
import type { RocketChatAssociationModel as _RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts';
|
|
import type { IMessageBuilder } from '@rocket.chat/apps-engine/definition/accessors/IMessageBuilder.ts';
|
|
import type { IRoomBuilder } from '@rocket.chat/apps-engine/definition/accessors/IRoomBuilder.ts';
|
|
import type { IUserBuilder } from '@rocket.chat/apps-engine/definition/accessors/IUserBuilder.ts';
|
|
import type { IVideoConferenceBuilder } from '@rocket.chat/apps-engine/definition/accessors/IVideoConferenceBuilder.ts';
|
|
import type { RoomType as _RoomType } from '@rocket.chat/apps-engine/definition/rooms/RoomType.ts';
|
|
import type { ILivechatMessageBuilder } from '@rocket.chat/apps-engine/definition/accessors/ILivechatMessageBuilder.ts';
|
|
import type { UIHelper as _UIHelper } from '@rocket.chat/apps-engine/server/misc/UIHelper.ts';
|
|
|
|
import * as Messenger from '../../messenger.ts';
|
|
import { randomBytes } from 'node:crypto';
|
|
|
|
import { BlockBuilder } from '../builders/BlockBuilder.ts';
|
|
import { MessageBuilder } from '../builders/MessageBuilder.ts';
|
|
import { DiscussionBuilder, IDiscussionBuilder } from '../builders/DiscussionBuilder.ts';
|
|
import { ILivechatMessage, LivechatMessageBuilder } from '../builders/LivechatMessageBuilder.ts';
|
|
import { RoomBuilder } from '../builders/RoomBuilder.ts';
|
|
import { UserBuilder } from '../builders/UserBuilder.ts';
|
|
import { AppVideoConference, VideoConferenceBuilder } from '../builders/VideoConferenceBuilder.ts';
|
|
import { AppObjectRegistry } from '../../../AppObjectRegistry.ts';
|
|
import { require } from '../../../lib/require.ts';
|
|
import { formatErrorResponse } from '../formatResponseErrorHandler.ts';
|
|
|
|
const { UIHelper } = require('@rocket.chat/apps-engine/server/misc/UIHelper.js') as { UIHelper: typeof _UIHelper };
|
|
const { RoomType } = require('@rocket.chat/apps-engine/definition/rooms/RoomType.js') as { RoomType: typeof _RoomType };
|
|
const { UserType } = require('@rocket.chat/apps-engine/definition/users/UserType.js') as { UserType: typeof _UserType };
|
|
const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.js') as {
|
|
RocketChatAssociationModel: typeof _RocketChatAssociationModel;
|
|
};
|
|
|
|
export class ModifyCreator implements IModifyCreator {
|
|
constructor(private readonly senderFn: typeof Messenger.sendRequest) {}
|
|
|
|
getLivechatCreator(): ILivechatCreator {
|
|
return new Proxy(
|
|
{ __kind: 'getLivechatCreator' },
|
|
{
|
|
get: (_target: unknown, prop: string) => {
|
|
// It's not worthwhile to make an asynchronous request for such a simple method
|
|
if (prop === 'createToken') {
|
|
return () => randomBytes(16).toString('hex');
|
|
}
|
|
|
|
if (prop === 'toJSON') {
|
|
return () => ({});
|
|
}
|
|
|
|
return (...params: unknown[]) =>
|
|
this.senderFn({
|
|
method: `accessor:getModifier:getCreator:getLivechatCreator:${prop}`,
|
|
params,
|
|
})
|
|
.then((response) => response.result)
|
|
.catch((err) => {
|
|
throw formatErrorResponse(err);
|
|
});
|
|
},
|
|
},
|
|
) as ILivechatCreator;
|
|
}
|
|
|
|
getUploadCreator(): IUploadCreator {
|
|
return new Proxy(
|
|
{ __kind: 'getUploadCreator' },
|
|
{
|
|
get:
|
|
(_target: unknown, prop: string) =>
|
|
(...params: unknown[]) =>
|
|
prop === 'toJSON'
|
|
? {}
|
|
: this.senderFn({
|
|
method: `accessor:getModifier:getCreator:getUploadCreator:${prop}`,
|
|
params,
|
|
})
|
|
.then((response) => response.result)
|
|
.catch((err) => {
|
|
throw formatErrorResponse(err);
|
|
}),
|
|
},
|
|
) as IUploadCreator;
|
|
}
|
|
|
|
getEmailCreator(): IEmailCreator {
|
|
return new Proxy(
|
|
{ __kind: 'getEmailCreator' },
|
|
{
|
|
get:
|
|
(_target: unknown, prop: string) =>
|
|
(...params: unknown[]) =>
|
|
prop === 'toJSON'
|
|
? {}
|
|
: this.senderFn({
|
|
method: `accessor:getModifier:getCreator:getEmailCreator:${prop}`,
|
|
params,
|
|
})
|
|
.then((response) => response.result)
|
|
.catch((err) => {
|
|
throw formatErrorResponse(err);
|
|
}),
|
|
},
|
|
);
|
|
}
|
|
|
|
getContactCreator(): IContactCreator {
|
|
return new Proxy(
|
|
{ __kind: 'getContactCreator' },
|
|
{
|
|
get:
|
|
(_target: unknown, prop: string) =>
|
|
(...params: unknown[]) =>
|
|
prop === 'toJSON'
|
|
? {}
|
|
: this.senderFn({
|
|
method: `accessor:getModifier:getCreator:getContactCreator:${prop}`,
|
|
params,
|
|
})
|
|
.then((response) => response.result)
|
|
.catch((err) => {
|
|
throw formatErrorResponse(err);
|
|
}),
|
|
},
|
|
);
|
|
}
|
|
|
|
getBlockBuilder() {
|
|
return new BlockBuilder();
|
|
}
|
|
|
|
startMessage(data?: IMessage) {
|
|
if (data) {
|
|
delete data.id;
|
|
}
|
|
|
|
return new MessageBuilder(data);
|
|
}
|
|
|
|
startLivechatMessage(data?: ILivechatMessage) {
|
|
if (data) {
|
|
delete data.id;
|
|
}
|
|
|
|
return new LivechatMessageBuilder(data);
|
|
}
|
|
|
|
startRoom(data?: IRoom) {
|
|
if (data) {
|
|
// @ts-ignore - this has been imported from the Apps-Engine
|
|
delete data.id;
|
|
}
|
|
|
|
return new RoomBuilder(data);
|
|
}
|
|
|
|
startDiscussion(data?: Partial<IRoom>) {
|
|
if (data) {
|
|
delete data.id;
|
|
}
|
|
|
|
return new DiscussionBuilder(data);
|
|
}
|
|
|
|
startVideoConference(data?: Partial<AppVideoConference>) {
|
|
return new VideoConferenceBuilder(data);
|
|
}
|
|
|
|
startBotUser(data?: Partial<IBotUser>) {
|
|
if (data) {
|
|
delete data.id;
|
|
|
|
const { roles } = data;
|
|
|
|
if (roles?.length) {
|
|
const hasRole = roles
|
|
.map((role: string) => role.toLocaleLowerCase())
|
|
.some((role: string) => role === 'admin' || role === 'owner' || role === 'moderator');
|
|
|
|
if (hasRole) {
|
|
throw new Error('Invalid role assigned to the user. Should not be admin, owner or moderator.');
|
|
}
|
|
}
|
|
|
|
if (!data.type) {
|
|
data.type = UserType.BOT;
|
|
}
|
|
}
|
|
|
|
return new UserBuilder(data);
|
|
}
|
|
|
|
public finish(
|
|
builder: IMessageBuilder | ILivechatMessageBuilder | IRoomBuilder | IDiscussionBuilder | IVideoConferenceBuilder | IUserBuilder,
|
|
): Promise<string> {
|
|
switch (builder.kind) {
|
|
case RocketChatAssociationModel.MESSAGE:
|
|
return this._finishMessage(builder as IMessageBuilder);
|
|
case RocketChatAssociationModel.LIVECHAT_MESSAGE:
|
|
return this._finishLivechatMessage(builder as ILivechatMessageBuilder);
|
|
case RocketChatAssociationModel.ROOM:
|
|
return this._finishRoom(builder as IRoomBuilder);
|
|
case RocketChatAssociationModel.DISCUSSION:
|
|
return this._finishDiscussion(builder as IDiscussionBuilder);
|
|
case RocketChatAssociationModel.VIDEO_CONFERENCE:
|
|
return this._finishVideoConference(builder as IVideoConferenceBuilder);
|
|
case RocketChatAssociationModel.USER:
|
|
return this._finishUser(builder as IUserBuilder);
|
|
default:
|
|
throw new Error('Invalid builder passed to the ModifyCreator.finish function.');
|
|
}
|
|
}
|
|
|
|
private async _finishMessage(builder: IMessageBuilder): Promise<string> {
|
|
const result = builder.getMessage();
|
|
delete result.id;
|
|
|
|
if (!result.sender || !result.sender.id) {
|
|
const response = await this.senderFn({
|
|
method: 'bridges:getUserBridge:doGetAppUser',
|
|
params: ['APP_ID'],
|
|
}).catch((err) => {
|
|
throw formatErrorResponse(err);
|
|
});
|
|
|
|
const appUser = response.result;
|
|
|
|
if (!appUser) {
|
|
throw new Error('Invalid sender assigned to the message.');
|
|
}
|
|
|
|
result.sender = appUser;
|
|
}
|
|
|
|
if (result.blocks?.length) {
|
|
// Can we move this elsewhere? This AppObjectRegistry usage doesn't really belong here, but where?
|
|
result.blocks = UIHelper.assignIds(result.blocks, AppObjectRegistry.get('id') || '');
|
|
}
|
|
|
|
const response = await this.senderFn({
|
|
method: 'bridges:getMessageBridge:doCreate',
|
|
params: [result, AppObjectRegistry.get('id')],
|
|
}).catch((err) => {
|
|
throw formatErrorResponse(err);
|
|
});
|
|
|
|
return String(response.result);
|
|
}
|
|
|
|
private async _finishLivechatMessage(builder: ILivechatMessageBuilder): Promise<string> {
|
|
if (builder.getSender() && !builder.getVisitor()) {
|
|
return this._finishMessage(builder.getMessageBuilder());
|
|
}
|
|
|
|
const result = builder.getMessage();
|
|
delete result.id;
|
|
|
|
if (!result.token && (!result.visitor || !result.visitor.token)) {
|
|
throw new Error('Invalid visitor sending the message');
|
|
}
|
|
|
|
result.token = result.visitor ? result.visitor.token : result.token;
|
|
|
|
const response = await this.senderFn({
|
|
method: 'bridges:getLivechatBridge:doCreateMessage',
|
|
params: [result, AppObjectRegistry.get('id')],
|
|
}).catch((err) => {
|
|
throw formatErrorResponse(err);
|
|
});
|
|
|
|
return String(response.result);
|
|
}
|
|
|
|
private async _finishRoom(builder: IRoomBuilder): Promise<string> {
|
|
const result = builder.getRoom();
|
|
delete result.id;
|
|
|
|
if (!result.type) {
|
|
throw new Error('Invalid type assigned to the room.');
|
|
}
|
|
|
|
if (result.type !== RoomType.LIVE_CHAT) {
|
|
if (!result.creator || !result.creator.id) {
|
|
throw new Error('Invalid creator assigned to the room.');
|
|
}
|
|
}
|
|
|
|
if (result.type !== RoomType.DIRECT_MESSAGE) {
|
|
if (result.type !== RoomType.LIVE_CHAT) {
|
|
if (!result.slugifiedName || !result.slugifiedName.trim()) {
|
|
throw new Error('Invalid slugifiedName assigned to the room.');
|
|
}
|
|
}
|
|
|
|
if (!result.displayName || !result.displayName.trim()) {
|
|
throw new Error('Invalid displayName assigned to the room.');
|
|
}
|
|
}
|
|
|
|
const response = await this.senderFn({
|
|
method: 'bridges:getRoomBridge:doCreate',
|
|
params: [result, builder.getMembersToBeAddedUsernames(), AppObjectRegistry.get('id')],
|
|
}).catch((err) => {
|
|
throw formatErrorResponse(err);
|
|
});
|
|
|
|
return String(response.result);
|
|
}
|
|
|
|
private async _finishDiscussion(builder: IDiscussionBuilder): Promise<string> {
|
|
const room = builder.getRoom();
|
|
delete room.id;
|
|
|
|
if (!room.creator || !room.creator.id) {
|
|
throw new Error('Invalid creator assigned to the discussion.');
|
|
}
|
|
|
|
if (!room.slugifiedName || !room.slugifiedName.trim()) {
|
|
throw new Error('Invalid slugifiedName assigned to the discussion.');
|
|
}
|
|
|
|
if (!room.displayName || !room.displayName.trim()) {
|
|
throw new Error('Invalid displayName assigned to the discussion.');
|
|
}
|
|
|
|
if (!room.parentRoom || !room.parentRoom.id) {
|
|
throw new Error('Invalid parentRoom assigned to the discussion.');
|
|
}
|
|
|
|
const response = await this.senderFn({
|
|
method: 'bridges:getRoomBridge:doCreateDiscussion',
|
|
params: [room, builder.getParentMessage(), builder.getReply(), builder.getMembersToBeAddedUsernames(), AppObjectRegistry.get('id')],
|
|
}).catch((err) => {
|
|
throw formatErrorResponse(err);
|
|
});
|
|
|
|
return String(response.result);
|
|
}
|
|
|
|
private async _finishVideoConference(builder: IVideoConferenceBuilder): Promise<string> {
|
|
const videoConference = builder.getVideoConference();
|
|
|
|
if (!videoConference.createdBy) {
|
|
throw new Error('Invalid creator assigned to the video conference.');
|
|
}
|
|
|
|
if (!videoConference.providerName?.trim()) {
|
|
throw new Error('Invalid provider name assigned to the video conference.');
|
|
}
|
|
|
|
if (!videoConference.rid) {
|
|
throw new Error('Invalid roomId assigned to the video conference.');
|
|
}
|
|
|
|
const response = await this.senderFn({
|
|
method: 'bridges:getVideoConferenceBridge:doCreate',
|
|
params: [videoConference, AppObjectRegistry.get('id')],
|
|
}).catch((err) => {
|
|
throw formatErrorResponse(err);
|
|
});
|
|
|
|
return String(response.result);
|
|
}
|
|
|
|
private async _finishUser(builder: IUserBuilder): Promise<string> {
|
|
const user = builder.getUser();
|
|
|
|
const response = await this.senderFn({
|
|
method: 'bridges:getUserBridge:doCreate',
|
|
params: [user, AppObjectRegistry.get('id')],
|
|
}).catch((err) => {
|
|
throw formatErrorResponse(err);
|
|
});
|
|
|
|
return String(response.result);
|
|
}
|
|
}
|
|
|