-
Notifications
You must be signed in to change notification settings - Fork 118
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
17 changed files
with
1,671 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,11 @@ | ||
{ | ||
"imports": { | ||
"@rocket.chat/apps-engine/": "./../src/", | ||
"@rocket.chat/ui-kit": "npm:@rocket.chat/ui-kit@^0.31.22", | ||
"acorn": "npm:acorn@8.10.0", | ||
"acorn-walk": "npm:acorn-walk@8.2.0", | ||
"astring": "npm:astring@1.8.6" | ||
"astring": "npm:astring@1.8.6", | ||
"jsonrpc-lite": "npm:jsonrpc-lite@2.2.0", | ||
"uuid": "npm:uuid@8.3.2", | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
import { v1 as uuid } from 'uuid'; | ||
|
||
import { | ||
BlockType, | ||
IActionsBlock, | ||
IBlock, | ||
IConditionalBlock, | ||
IConditionalBlockFilters, | ||
IContextBlock, | ||
IImageBlock, | ||
IInputBlock, | ||
ISectionBlock, | ||
} from "@rocket.chat/apps-engine/definition/uikit/blocks/Blocks.ts"; | ||
import type { | ||
IBlockElement, | ||
IButtonElement, | ||
IImageElement, | ||
IInputElement, | ||
IInteractiveElement, | ||
IMultiStaticSelectElement, | ||
IOverflowMenuElement, | ||
IPlainTextInputElement, | ||
ISelectElement, | ||
IStaticSelectElement, | ||
} from '@rocket.chat/apps-engine/definition/uikit/blocks/Elements.ts'; | ||
import { BlockElementType } from '@rocket.chat/apps-engine/definition/uikit/blocks/Elements.ts'; | ||
import type { ITextObject } from '@rocket.chat/apps-engine/definition/uikit/blocks/Objects.ts'; | ||
import { TextObjectType } from '@rocket.chat/apps-engine/definition/uikit/blocks/Objects.ts'; | ||
import { AppObjectRegistry } from "../../AppObjectRegistry.ts"; | ||
|
||
type BlockFunctionParameter<T extends IBlock> = Omit<T, 'type'>; | ||
type ElementFunctionParameter<T extends IBlockElement> = T extends IInteractiveElement | ||
? Omit<T, 'type' | 'actionId'> | Partial<Pick<T, 'actionId'>> | ||
: Omit<T, 'type'>; | ||
|
||
type SectionBlockParam = BlockFunctionParameter<ISectionBlock>; | ||
type ImageBlockParam = BlockFunctionParameter<IImageBlock>; | ||
type ActionsBlockParam = BlockFunctionParameter<IActionsBlock>; | ||
type ContextBlockParam = BlockFunctionParameter<IContextBlock>; | ||
type InputBlockParam = BlockFunctionParameter<IInputBlock>; | ||
|
||
type ButtonElementParam = ElementFunctionParameter<IButtonElement>; | ||
type ImageElementParam = ElementFunctionParameter<IImageElement>; | ||
type OverflowMenuElementParam = ElementFunctionParameter<IOverflowMenuElement>; | ||
type PlainTextInputElementParam = ElementFunctionParameter<IPlainTextInputElement>; | ||
type StaticSelectElementParam = ElementFunctionParameter<IStaticSelectElement>; | ||
type MultiStaticSelectElementParam = ElementFunctionParameter<IMultiStaticSelectElement>; | ||
|
||
/** | ||
* @deprecated please prefer the rocket.chat/ui-kit components | ||
*/ | ||
export class BlockBuilder { | ||
private readonly blocks: Array<IBlock>; | ||
private readonly appId: string; | ||
|
||
constructor() { | ||
this.blocks = []; | ||
this.appId = String(AppObjectRegistry.get('appId')); | ||
} | ||
|
||
public addSectionBlock(block: SectionBlockParam): BlockBuilder { | ||
this.addBlock({ type: BlockType.SECTION, ...block } as ISectionBlock); | ||
|
||
return this; | ||
} | ||
|
||
public addImageBlock(block: ImageBlockParam): BlockBuilder { | ||
this.addBlock({ type: BlockType.IMAGE, ...block } as IImageBlock); | ||
|
||
return this; | ||
} | ||
|
||
public addDividerBlock(): BlockBuilder { | ||
this.addBlock({ type: BlockType.DIVIDER }); | ||
|
||
return this; | ||
} | ||
|
||
public addActionsBlock(block: ActionsBlockParam): BlockBuilder { | ||
this.addBlock({ type: BlockType.ACTIONS, ...block } as IActionsBlock); | ||
|
||
return this; | ||
} | ||
|
||
public addContextBlock(block: ContextBlockParam): BlockBuilder { | ||
this.addBlock({ type: BlockType.CONTEXT, ...block } as IContextBlock); | ||
|
||
return this; | ||
} | ||
|
||
public addInputBlock(block: InputBlockParam): BlockBuilder { | ||
this.addBlock({ type: BlockType.INPUT, ...block } as IInputBlock); | ||
|
||
return this; | ||
} | ||
|
||
public addConditionalBlock(innerBlocks: BlockBuilder | Array<IBlock>, condition?: IConditionalBlockFilters): BlockBuilder { | ||
const render = innerBlocks instanceof BlockBuilder ? innerBlocks.getBlocks() : innerBlocks; | ||
|
||
this.addBlock({ type: BlockType.CONDITIONAL, render, when: condition } as IConditionalBlock); | ||
|
||
return this; | ||
} | ||
|
||
public getBlocks() { | ||
return this.blocks; | ||
} | ||
|
||
public newPlainTextObject(text: string, emoji = false): ITextObject { | ||
return { | ||
type: TextObjectType.PLAINTEXT, | ||
text, | ||
emoji, | ||
}; | ||
} | ||
|
||
public newMarkdownTextObject(text: string): ITextObject { | ||
return { | ||
type: TextObjectType.MARKDOWN, | ||
text, | ||
}; | ||
} | ||
|
||
public newButtonElement(info: ButtonElementParam): IButtonElement { | ||
return this.newInteractiveElement({ | ||
type: BlockElementType.BUTTON, | ||
...info, | ||
} as IButtonElement); | ||
} | ||
|
||
public newImageElement(info: ImageElementParam): IImageElement { | ||
return { | ||
type: BlockElementType.IMAGE, | ||
...info, | ||
}; | ||
} | ||
|
||
public newOverflowMenuElement(info: OverflowMenuElementParam): IOverflowMenuElement { | ||
return this.newInteractiveElement({ | ||
type: BlockElementType.OVERFLOW_MENU, | ||
...info, | ||
} as IOverflowMenuElement); | ||
} | ||
|
||
public newPlainTextInputElement(info: PlainTextInputElementParam): IPlainTextInputElement { | ||
return this.newInputElement({ | ||
type: BlockElementType.PLAIN_TEXT_INPUT, | ||
...info, | ||
} as IPlainTextInputElement); | ||
} | ||
|
||
public newStaticSelectElement(info: StaticSelectElementParam): IStaticSelectElement { | ||
return this.newSelectElement({ | ||
type: BlockElementType.STATIC_SELECT, | ||
...info, | ||
} as IStaticSelectElement); | ||
} | ||
|
||
public newMultiStaticElement(info: MultiStaticSelectElementParam): IMultiStaticSelectElement { | ||
return this.newSelectElement({ | ||
type: BlockElementType.MULTI_STATIC_SELECT, | ||
...info, | ||
} as IMultiStaticSelectElement); | ||
} | ||
|
||
private newInteractiveElement<T extends IInteractiveElement>(element: T): T { | ||
if (!element.actionId) { | ||
element.actionId = this.generateActionId(); | ||
} | ||
|
||
return element; | ||
} | ||
|
||
private newInputElement<T extends IInputElement>(element: T): T { | ||
if (!element.actionId) { | ||
element.actionId = this.generateActionId(); | ||
} | ||
|
||
return element; | ||
} | ||
|
||
private newSelectElement<T extends ISelectElement>(element: T): T { | ||
if (!element.actionId) { | ||
element.actionId = this.generateActionId(); | ||
} | ||
|
||
return element; | ||
} | ||
|
||
private addBlock(block: IBlock): void { | ||
if (!block.blockId) { | ||
block.blockId = this.generateBlockId(); | ||
} | ||
|
||
block.appId = this.appId; | ||
|
||
this.blocks.push(block); | ||
} | ||
|
||
private generateBlockId(): string { | ||
return uuid(); | ||
} | ||
|
||
private generateActionId(): string { | ||
return uuid(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import type { IDiscussionBuilder as _IDiscussionBuilder } from "@rocket.chat/apps-engine/definition/accessors/IDiscussionBuilder.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 { RocketChatAssociationModel } from "@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts"; | ||
import { RoomType } from "@rocket.chat/apps-engine/definition/rooms/RoomType.ts"; | ||
|
||
import { RoomBuilder } from "./RoomBuilder.ts"; | ||
import { IRoomBuilder } from "@rocket.chat/apps-engine/definition/accessors/IRoomBuilder.ts"; | ||
|
||
export interface IDiscussionBuilder extends _IDiscussionBuilder, IRoomBuilder {} | ||
|
||
export class DiscussionBuilder extends RoomBuilder implements IDiscussionBuilder { | ||
public kind: RocketChatAssociationModel.DISCUSSION; | ||
|
||
private reply?: string; | ||
|
||
private parentMessage?: IMessage; | ||
|
||
constructor(data?: Partial<IRoom>) { | ||
super(data); | ||
this.kind = RocketChatAssociationModel.DISCUSSION; | ||
this.room.type = RoomType.PRIVATE_GROUP; | ||
} | ||
|
||
public setParentRoom(parentRoom: IRoom): IDiscussionBuilder { | ||
this.room.parentRoom = parentRoom; | ||
return this; | ||
} | ||
|
||
public getParentRoom(): IRoom { | ||
return this.room.parentRoom!; | ||
} | ||
|
||
public setReply(reply: string): IDiscussionBuilder { | ||
this.reply = reply; | ||
return this; | ||
} | ||
|
||
public getReply(): string { | ||
return this.reply!; | ||
} | ||
|
||
public setParentMessage(parentMessage: IMessage): IDiscussionBuilder { | ||
this.parentMessage = parentMessage; | ||
return this; | ||
} | ||
|
||
public getParentMessage(): IMessage { | ||
return this.parentMessage!; | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
import { RocketChatAssociationModel } from "@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts"; | ||
import { RoomType } from "@rocket.chat/apps-engine/definition/rooms/RoomType.ts"; | ||
|
||
import type { ILivechatMessageBuilder } from "@rocket.chat/apps-engine/definition/accessors/ILivechatMessageBuilder.ts"; | ||
import type { IMessage } from '@rocket.chat/apps-engine/definition/messages/IMessage.ts'; | ||
import type { IMessageAttachment } from '@rocket.chat/apps-engine/definition/messages/IMessageAttachment.ts'; | ||
import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom.ts'; | ||
import type { IUser } from '@rocket.chat/apps-engine/definition/users/IUser.ts'; | ||
import type { ILivechatMessage as EngineLivechatMessage } from '@rocket.chat/apps-engine/definition/livechat/ILivechatMessage.ts'; | ||
import type { IVisitor } from "@rocket.chat/apps-engine/definition/livechat/IVisitor.ts"; | ||
import type { IMessageBuilder } from "@rocket.chat/apps-engine/definition/accessors/IMessageBuilder.ts"; | ||
|
||
import { MessageBuilder } from "./MessageBuilder.ts"; | ||
|
||
export interface ILivechatMessage extends EngineLivechatMessage, IMessage {} | ||
|
||
export class LivechatMessageBuilder implements ILivechatMessageBuilder { | ||
public kind: RocketChatAssociationModel.LIVECHAT_MESSAGE; | ||
|
||
private msg: ILivechatMessage; | ||
|
||
constructor(message?: ILivechatMessage) { | ||
this.kind = RocketChatAssociationModel.LIVECHAT_MESSAGE; | ||
this.msg = message || ({} as ILivechatMessage); | ||
} | ||
|
||
public setData(data: ILivechatMessage): ILivechatMessageBuilder { | ||
delete data.id; | ||
this.msg = data; | ||
|
||
return this; | ||
} | ||
|
||
public setRoom(room: IRoom): ILivechatMessageBuilder { | ||
this.msg.room = room; | ||
return this; | ||
} | ||
|
||
public getRoom(): IRoom { | ||
return this.msg.room; | ||
} | ||
|
||
public setSender(sender: IUser): ILivechatMessageBuilder { | ||
this.msg.sender = sender; | ||
delete this.msg.visitor; | ||
|
||
return this; | ||
} | ||
|
||
public getSender(): IUser { | ||
return this.msg.sender; | ||
} | ||
|
||
public setText(text: string): ILivechatMessageBuilder { | ||
this.msg.text = text; | ||
return this; | ||
} | ||
|
||
public getText(): string { | ||
return this.msg.text!; | ||
} | ||
|
||
public setEmojiAvatar(emoji: string): ILivechatMessageBuilder { | ||
this.msg.emoji = emoji; | ||
return this; | ||
} | ||
|
||
public getEmojiAvatar(): string { | ||
return this.msg.emoji!; | ||
} | ||
|
||
public setAvatarUrl(avatarUrl: string): ILivechatMessageBuilder { | ||
this.msg.avatarUrl = avatarUrl; | ||
return this; | ||
} | ||
|
||
public getAvatarUrl(): string { | ||
return this.msg.avatarUrl!; | ||
} | ||
|
||
public setUsernameAlias(alias: string): ILivechatMessageBuilder { | ||
this.msg.alias = alias; | ||
return this; | ||
} | ||
|
||
public getUsernameAlias(): string { | ||
return this.msg.alias!; | ||
} | ||
|
||
public addAttachment(attachment: IMessageAttachment): ILivechatMessageBuilder { | ||
if (!this.msg.attachments) { | ||
this.msg.attachments = []; | ||
} | ||
|
||
this.msg.attachments.push(attachment); | ||
return this; | ||
} | ||
|
||
public setAttachments(attachments: Array<IMessageAttachment>): ILivechatMessageBuilder { | ||
this.msg.attachments = attachments; | ||
return this; | ||
} | ||
|
||
public getAttachments(): Array<IMessageAttachment> { | ||
return this.msg.attachments!; | ||
} | ||
|
||
public replaceAttachment(position: number, attachment: IMessageAttachment): ILivechatMessageBuilder { | ||
if (!this.msg.attachments) { | ||
this.msg.attachments = []; | ||
} | ||
|
||
if (!this.msg.attachments[position]) { | ||
throw new Error(`No attachment found at the index of "${position}" to replace.`); | ||
} | ||
|
||
this.msg.attachments[position] = attachment; | ||
return this; | ||
} | ||
|
||
public removeAttachment(position: number): ILivechatMessageBuilder { | ||
if (!this.msg.attachments) { | ||
this.msg.attachments = []; | ||
} | ||
|
||
if (!this.msg.attachments[position]) { | ||
throw new Error(`No attachment found at the index of "${position}" to remove.`); | ||
} | ||
|
||
this.msg.attachments.splice(position, 1); | ||
|
||
return this; | ||
} | ||
|
||
public setEditor(user: IUser): ILivechatMessageBuilder { | ||
this.msg.editor = user; | ||
return this; | ||
} | ||
|
||
public getEditor(): IUser { | ||
return this.msg.editor; | ||
} | ||
|
||
public setGroupable(groupable: boolean): ILivechatMessageBuilder { | ||
this.msg.groupable = groupable; | ||
return this; | ||
} | ||
|
||
public getGroupable(): boolean { | ||
return this.msg.groupable!; | ||
} | ||
|
||
public setParseUrls(parseUrls: boolean): ILivechatMessageBuilder { | ||
this.msg.parseUrls = parseUrls; | ||
return this; | ||
} | ||
|
||
public getParseUrls(): boolean { | ||
return this.msg.parseUrls!; | ||
} | ||
|
||
public setToken(token: string): ILivechatMessageBuilder { | ||
this.msg.token = token; | ||
return this; | ||
} | ||
|
||
public getToken(): string { | ||
return this.msg.token!; | ||
} | ||
|
||
public setVisitor(visitor: IVisitor): ILivechatMessageBuilder { | ||
this.msg.visitor = visitor; | ||
delete this.msg.sender; | ||
|
||
return this; | ||
} | ||
|
||
public getVisitor(): IVisitor { | ||
return this.msg.visitor; | ||
} | ||
|
||
public getMessage(): ILivechatMessage { | ||
if (!this.msg.room) { | ||
throw new Error('The "room" property is required.'); | ||
} | ||
|
||
if (this.msg.room.type !== RoomType.LIVE_CHAT) { | ||
throw new Error('The room is not a Livechat room'); | ||
} | ||
|
||
return this.msg; | ||
} | ||
|
||
public getMessageBuilder(): IMessageBuilder { | ||
return new MessageBuilder(this.msg as IMessage); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
import { Block } from '@rocket.chat/ui-kit'; | ||
|
||
import { IMessageBuilder } from '@rocket.chat/apps-engine/definition/accessors/IMessageBuilder.ts'; | ||
import { RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts'; | ||
import { IMessage } from '@rocket.chat/apps-engine/definition/messages/IMessage.ts'; | ||
import { IMessageAttachment } from '@rocket.chat/apps-engine/definition/messages/IMessageAttachment.ts'; | ||
import { IUser } from '@rocket.chat/apps-engine/definition/users/IUser.ts'; | ||
import { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom.ts'; | ||
import { IBlock } from '@rocket.chat/apps-engine/definition/uikit/blocks/Blocks.ts'; | ||
import { BlockBuilder } from "./BlockBuilder.ts"; | ||
|
||
export class MessageBuilder implements IMessageBuilder { | ||
public kind: RocketChatAssociationModel.MESSAGE; | ||
|
||
private msg: IMessage; | ||
|
||
constructor(message?: IMessage) { | ||
this.kind = RocketChatAssociationModel.MESSAGE; | ||
this.msg = message || ({} as IMessage); | ||
} | ||
|
||
public setData(data: IMessage): IMessageBuilder { | ||
delete data.id; | ||
this.msg = data; | ||
|
||
return this as IMessageBuilder; | ||
} | ||
|
||
public setUpdateData(data: IMessage, editor: IUser): IMessageBuilder { | ||
this.msg = data; | ||
this.msg.editor = editor; | ||
this.msg.editedAt = new Date(); | ||
|
||
return this as IMessageBuilder; | ||
} | ||
|
||
public setThreadId(threadId: string): IMessageBuilder { | ||
this.msg.threadId = threadId; | ||
|
||
return this as IMessageBuilder; | ||
} | ||
|
||
public getThreadId(): string { | ||
return this.msg.threadId!; | ||
} | ||
|
||
public setRoom(room: IRoom): IMessageBuilder { | ||
this.msg.room = room; | ||
return this as IMessageBuilder; | ||
} | ||
|
||
public getRoom(): IRoom { | ||
return this.msg.room; | ||
} | ||
|
||
public setSender(sender: IUser): IMessageBuilder { | ||
this.msg.sender = sender; | ||
return this as IMessageBuilder; | ||
} | ||
|
||
public getSender(): IUser { | ||
return this.msg.sender; | ||
} | ||
|
||
public setText(text: string): IMessageBuilder { | ||
this.msg.text = text; | ||
return this as IMessageBuilder; | ||
} | ||
|
||
public getText(): string { | ||
return this.msg.text!; | ||
} | ||
|
||
public setEmojiAvatar(emoji: string): IMessageBuilder { | ||
this.msg.emoji = emoji; | ||
return this as IMessageBuilder; | ||
} | ||
|
||
public getEmojiAvatar(): string { | ||
return this.msg.emoji!; | ||
} | ||
|
||
public setAvatarUrl(avatarUrl: string): IMessageBuilder { | ||
this.msg.avatarUrl = avatarUrl; | ||
return this as IMessageBuilder; | ||
} | ||
|
||
public getAvatarUrl(): string { | ||
return this.msg.avatarUrl!; | ||
} | ||
|
||
public setUsernameAlias(alias: string): IMessageBuilder { | ||
this.msg.alias = alias; | ||
return this as IMessageBuilder; | ||
} | ||
|
||
public getUsernameAlias(): string { | ||
return this.msg.alias!; | ||
} | ||
|
||
public addAttachment(attachment: IMessageAttachment): IMessageBuilder { | ||
if (!this.msg.attachments) { | ||
this.msg.attachments = []; | ||
} | ||
|
||
this.msg.attachments.push(attachment); | ||
return this as IMessageBuilder; | ||
} | ||
|
||
public setAttachments(attachments: Array<IMessageAttachment>): IMessageBuilder { | ||
this.msg.attachments = attachments; | ||
return this as IMessageBuilder; | ||
} | ||
|
||
public getAttachments(): Array<IMessageAttachment> { | ||
return this.msg.attachments!; | ||
} | ||
|
||
public replaceAttachment(position: number, attachment: IMessageAttachment): IMessageBuilder { | ||
if (!this.msg.attachments) { | ||
this.msg.attachments = []; | ||
} | ||
|
||
if (!this.msg.attachments[position]) { | ||
throw new Error(`No attachment found at the index of "${position}" to replace.`); | ||
} | ||
|
||
this.msg.attachments[position] = attachment; | ||
return this as IMessageBuilder; | ||
} | ||
|
||
public removeAttachment(position: number): IMessageBuilder { | ||
if (!this.msg.attachments) { | ||
this.msg.attachments = []; | ||
} | ||
|
||
if (!this.msg.attachments[position]) { | ||
throw new Error(`No attachment found at the index of "${position}" to remove.`); | ||
} | ||
|
||
this.msg.attachments.splice(position, 1); | ||
|
||
return this as IMessageBuilder; | ||
} | ||
|
||
public setEditor(user: IUser): IMessageBuilder { | ||
this.msg.editor = user; | ||
return this as IMessageBuilder; | ||
} | ||
|
||
public getEditor(): IUser { | ||
return this.msg.editor; | ||
} | ||
|
||
public setGroupable(groupable: boolean): IMessageBuilder { | ||
this.msg.groupable = groupable; | ||
return this as IMessageBuilder; | ||
} | ||
|
||
public getGroupable(): boolean { | ||
return this.msg.groupable!; | ||
} | ||
|
||
public setParseUrls(parseUrls: boolean): IMessageBuilder { | ||
this.msg.parseUrls = parseUrls; | ||
return this as IMessageBuilder; | ||
} | ||
|
||
public getParseUrls(): boolean { | ||
return this.msg.parseUrls!; | ||
} | ||
|
||
public getMessage(): IMessage { | ||
if (!this.msg.room) { | ||
throw new Error('The "room" property is required.'); | ||
} | ||
|
||
return this.msg; | ||
} | ||
|
||
public addBlocks(blocks: BlockBuilder | Array<IBlock | Block>) { | ||
if (!Array.isArray(this.msg.blocks)) { | ||
this.msg.blocks = []; | ||
} | ||
|
||
if (blocks instanceof BlockBuilder) { | ||
this.msg.blocks.push(...blocks.getBlocks()); | ||
} else { | ||
this.msg.blocks.push(...blocks); | ||
} | ||
|
||
return this as IMessageBuilder; | ||
} | ||
|
||
public setBlocks(blocks: BlockBuilder | Array<IBlock | Block>) { | ||
if (blocks instanceof BlockBuilder) { | ||
this.msg.blocks = blocks.getBlocks(); | ||
} else { | ||
this.msg.blocks = blocks; | ||
} | ||
|
||
return this as IMessageBuilder; | ||
} | ||
|
||
public getBlocks() { | ||
return this.msg.blocks!; | ||
} | ||
|
||
public addCustomField(key: string, value: unknown): IMessageBuilder { | ||
if (!this.msg.customFields) { | ||
this.msg.customFields = {}; | ||
} | ||
|
||
if (this.msg.customFields[key]) { | ||
throw new Error(`The message already contains a custom field by the key: ${key}`); | ||
} | ||
|
||
if (key.includes('.')) { | ||
throw new Error(`The given key contains a period, which is not allowed. Key: ${key}`); | ||
} | ||
|
||
this.msg.customFields[key] = value; | ||
|
||
return this as IMessageBuilder; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import { IRoomBuilder } from "@rocket.chat/apps-engine/definition/accessors/IRoomBuilder.ts"; | ||
import { RocketChatAssociationModel } from "@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts"; | ||
import { IRoom } from "@rocket.chat/apps-engine/definition/rooms/IRoom.ts"; | ||
import { RoomType } from "@rocket.chat/apps-engine/definition/rooms/RoomType.ts"; | ||
import { IUser } from "@rocket.chat/apps-engine/definition/users/IUser.ts"; | ||
|
||
export class RoomBuilder implements IRoomBuilder { | ||
public kind: RocketChatAssociationModel.ROOM | RocketChatAssociationModel.DISCUSSION; | ||
|
||
protected room: IRoom; | ||
|
||
private members: Array<string>; | ||
|
||
constructor(data?: Partial<IRoom>) { | ||
this.kind = RocketChatAssociationModel.ROOM; | ||
this.room = (data || { customFields: {} }) as IRoom; | ||
this.members = []; | ||
} | ||
|
||
public setData(data: Partial<IRoom>): IRoomBuilder { | ||
delete data.id; | ||
this.room = data as IRoom; | ||
|
||
return this; | ||
} | ||
|
||
public setDisplayName(name: string): IRoomBuilder { | ||
this.room.displayName = name; | ||
return this; | ||
} | ||
|
||
public getDisplayName(): string { | ||
return this.room.displayName!; | ||
} | ||
|
||
public setSlugifiedName(name: string): IRoomBuilder { | ||
this.room.slugifiedName = name; | ||
return this; | ||
} | ||
|
||
public getSlugifiedName(): string { | ||
return this.room.slugifiedName; | ||
} | ||
|
||
public setType(type: RoomType): IRoomBuilder { | ||
this.room.type = type; | ||
return this; | ||
} | ||
|
||
public getType(): RoomType { | ||
return this.room.type; | ||
} | ||
|
||
public setCreator(creator: IUser): IRoomBuilder { | ||
this.room.creator = creator; | ||
return this; | ||
} | ||
|
||
public getCreator(): IUser { | ||
return this.room.creator; | ||
} | ||
|
||
/** | ||
* @deprecated | ||
*/ | ||
public addUsername(username: string): IRoomBuilder { | ||
this.addMemberToBeAddedByUsername(username); | ||
return this; | ||
} | ||
|
||
/** | ||
* @deprecated | ||
*/ | ||
public setUsernames(usernames: Array<string>): IRoomBuilder { | ||
this.setMembersToBeAddedByUsernames(usernames); | ||
return this; | ||
} | ||
|
||
/** | ||
* @deprecated | ||
*/ | ||
public getUsernames(): Array<string> { | ||
const usernames = this.getMembersToBeAddedUsernames(); | ||
if (usernames && usernames.length > 0) { | ||
return usernames; | ||
} | ||
return this.room.usernames || []; | ||
} | ||
|
||
public addMemberToBeAddedByUsername(username: string): IRoomBuilder { | ||
this.members.push(username); | ||
return this; | ||
} | ||
|
||
public setMembersToBeAddedByUsernames(usernames: Array<string>): IRoomBuilder { | ||
this.members = usernames; | ||
return this; | ||
} | ||
|
||
public getMembersToBeAddedUsernames(): Array<string> { | ||
return this.members; | ||
} | ||
|
||
public setDefault(isDefault: boolean): IRoomBuilder { | ||
this.room.isDefault = isDefault; | ||
return this; | ||
} | ||
|
||
public getIsDefault(): boolean { | ||
return this.room.isDefault!; | ||
} | ||
|
||
public setReadOnly(isReadOnly: boolean): IRoomBuilder { | ||
this.room.isReadOnly = isReadOnly; | ||
return this; | ||
} | ||
|
||
public getIsReadOnly(): boolean { | ||
return this.room.isReadOnly!; | ||
} | ||
|
||
public setDisplayingOfSystemMessages(displaySystemMessages: boolean): IRoomBuilder { | ||
this.room.displaySystemMessages = displaySystemMessages; | ||
return this; | ||
} | ||
|
||
public getDisplayingOfSystemMessages(): boolean { | ||
return this.room.displaySystemMessages!; | ||
} | ||
|
||
public addCustomField(key: string, value: object): IRoomBuilder { | ||
if (typeof this.room.customFields !== 'object') { | ||
this.room.customFields = {}; | ||
} | ||
|
||
this.room.customFields[key] = value; | ||
return this; | ||
} | ||
|
||
public setCustomFields(fields: { [key: string]: object }): IRoomBuilder { | ||
this.room.customFields = fields; | ||
return this; | ||
} | ||
|
||
public getCustomFields(): { [key: string]: object } { | ||
return this.room.customFields!; | ||
} | ||
|
||
public getUserIds(): Array<string> { | ||
return this.room.userIds!; | ||
} | ||
|
||
public getRoom(): IRoom { | ||
return this.room; | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { IUserBuilder } from '@rocket.chat/apps-engine/definition/accessors/IUserBuilder.ts'; | ||
import { RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts'; | ||
import { IUser } from '@rocket.chat/apps-engine/definition/users/IUser.ts'; | ||
import { IUserSettings } from '@rocket.chat/apps-engine/definition/users/IUserSettings.ts'; | ||
import { IUserEmail } from '@rocket.chat/apps-engine/definition/users/IUserEmail.ts'; | ||
|
||
export class UserBuilder implements IUserBuilder { | ||
public kind: RocketChatAssociationModel.USER; | ||
|
||
private user: Partial<IUser>; | ||
|
||
constructor(user?: Partial<IUser>) { | ||
this.kind = RocketChatAssociationModel.USER; | ||
this.user = user || ({} as Partial<IUser>); | ||
} | ||
|
||
public setData(data: Partial<IUser>): IUserBuilder { | ||
delete data.id; | ||
this.user = data; | ||
|
||
return this; | ||
} | ||
|
||
public setEmails(emails: Array<IUserEmail>): IUserBuilder { | ||
this.user.emails = emails; | ||
return this; | ||
} | ||
|
||
public getEmails(): Array<IUserEmail> { | ||
return this.user.emails!; | ||
} | ||
|
||
public setDisplayName(name: string): IUserBuilder { | ||
this.user.name = name; | ||
return this; | ||
} | ||
|
||
public getDisplayName(): string { | ||
return this.user.name!; | ||
} | ||
|
||
public setUsername(username: string): IUserBuilder { | ||
this.user.username = username; | ||
return this; | ||
} | ||
|
||
public getUsername(): string { | ||
return this.user.username!; | ||
} | ||
|
||
public setRoles(roles: Array<string>): IUserBuilder { | ||
this.user.roles = roles; | ||
return this; | ||
} | ||
|
||
public getRoles(): Array<string> { | ||
return this.user.roles!; | ||
} | ||
|
||
public getSettings(): Partial<IUserSettings> { | ||
return this.user.settings; | ||
} | ||
|
||
public getUser(): Partial<IUser> { | ||
if (!this.user.username) { | ||
throw new Error('The "username" property is required.'); | ||
} | ||
|
||
if (!this.user.name) { | ||
throw new Error('The "name" property is required.'); | ||
} | ||
|
||
return this.user; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import { IVideoConferenceBuilder } from "@rocket.chat/apps-engine/definition/accessors/IVideoConferenceBuilder.ts"; | ||
import { RocketChatAssociationModel } from "@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts"; | ||
import type { IGroupVideoConference } from "@rocket.chat/apps-engine/definition/videoConferences/IVideoConference.ts"; | ||
|
||
export type AppVideoConference = Pick<IGroupVideoConference, 'rid' | 'providerName' | 'providerData' | 'title'> & { | ||
createdBy: IGroupVideoConference['createdBy']['_id']; | ||
}; | ||
|
||
|
||
export class VideoConferenceBuilder implements IVideoConferenceBuilder { | ||
public kind: RocketChatAssociationModel.VIDEO_CONFERENCE = RocketChatAssociationModel.VIDEO_CONFERENCE; | ||
|
||
protected call: AppVideoConference; | ||
|
||
constructor(data?: Partial<AppVideoConference>) { | ||
this.call = (data || {}) as AppVideoConference; | ||
} | ||
|
||
public setData(data: Partial<AppVideoConference>): IVideoConferenceBuilder { | ||
this.call = { | ||
rid: data.rid!, | ||
createdBy: data.createdBy, | ||
providerName: data.providerName!, | ||
title: data.title!, | ||
}; | ||
|
||
return this; | ||
} | ||
|
||
public setRoomId(rid: string): IVideoConferenceBuilder { | ||
this.call.rid = rid; | ||
return this; | ||
} | ||
|
||
public getRoomId(): string { | ||
return this.call.rid; | ||
} | ||
|
||
public setCreatedBy(userId: string): IVideoConferenceBuilder { | ||
this.call.createdBy = userId; | ||
return this; | ||
} | ||
|
||
public getCreatedBy(): string { | ||
return this.call.createdBy; | ||
} | ||
|
||
public setProviderName(userId: string): IVideoConferenceBuilder { | ||
this.call.providerName = userId; | ||
return this; | ||
} | ||
|
||
public getProviderName(): string { | ||
return this.call.providerName; | ||
} | ||
|
||
public setProviderData(data: Record<string, unknown> | undefined): IVideoConferenceBuilder { | ||
this.call.providerData = data; | ||
return this; | ||
} | ||
|
||
public getProviderData(): Record<string, unknown> { | ||
return this.call.providerData!; | ||
} | ||
|
||
public setTitle(userId: string): IVideoConferenceBuilder { | ||
this.call.title = userId; | ||
return this; | ||
} | ||
|
||
public getTitle(): string { | ||
return this.call.title; | ||
} | ||
|
||
public getVideoConference(): AppVideoConference { | ||
return this.call; | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,306 @@ | ||
import { createRequire } from 'node:module'; | ||
|
||
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 { 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 { UserType } from '@rocket.chat/apps-engine/definition/users/UserType.ts'; | ||
import { RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata/RocketChatAssociations.ts'; | ||
import { IMessageBuilder } from '@rocket.chat/apps-engine/definition/accessors/IMessageBuilder.ts'; | ||
import { IRoomBuilder } from '@rocket.chat/apps-engine/definition/accessors/IRoomBuilder.ts'; | ||
import { IUserBuilder } from '@rocket.chat/apps-engine/definition/accessors/IUserBuilder.ts'; | ||
import { IVideoConferenceBuilder } from '@rocket.chat/apps-engine/definition/accessors/IVideoConferenceBuilder.ts'; | ||
import { RoomType } from '@rocket.chat/apps-engine/definition/rooms/RoomType.ts'; | ||
import { ILivechatMessageBuilder } from '@rocket.chat/apps-engine/definition/accessors/ILivechatMessageBuilder.ts'; | ||
|
||
import { BlockBuilder } from '../BlockBuilder.ts'; | ||
import { MessageBuilder } from '../MessageBuilder.ts'; | ||
import { DiscussionBuilder, IDiscussionBuilder } from '../DiscussionBuilder.ts'; | ||
import { ILivechatMessage, LivechatMessageBuilder } from '../LivechatMessageBuilder.ts'; | ||
import { RoomBuilder } from '../RoomBuilder.ts'; | ||
import { UserBuilder } from '../UserBuilder.ts'; | ||
import { AppVideoConference, VideoConferenceBuilder } from '../VideoConferenceBuilder.ts'; | ||
import * as Messenger from '../../messenger.ts'; | ||
import { AppObjectRegistry } from '../../../AppObjectRegistry.ts'; | ||
|
||
const require = createRequire(import.meta.url); | ||
|
||
// @deno-types="../../../../server/misc/UIHelper.d.ts" | ||
const UIHelper = require(import.meta.resolve('@rocket.chat/apps-engine/server/misc/UIHelper.js').replace('file://', '').replace('src/', '')); | ||
|
||
export class ModifyCreator implements IModifyCreator { | ||
constructor(private readonly senderFn: typeof Messenger.sendRequest) {} | ||
|
||
getLivechatCreator(): ILivechatCreator { | ||
return new Proxy( | ||
{ __kind: 'getLivechatCreator' }, | ||
{ | ||
get: (_target: unknown, prop: string) => { | ||
if (prop === 'createToken') { | ||
return () => Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); | ||
} | ||
|
||
return (...params: unknown[]) => | ||
this.senderFn({ | ||
method: `accessor:getModifier:getCreator:getLivechatCreator:${prop}`, | ||
params, | ||
}); | ||
}, | ||
}, | ||
) as ILivechatCreator; | ||
} | ||
|
||
getUploadCreator(): IUploadCreator { | ||
return new Proxy( | ||
{ __kind: 'getUploadCreator' }, | ||
{ | ||
get: | ||
(_target: unknown, prop: string) => | ||
(...params: unknown[]) => | ||
this.senderFn({ | ||
method: `accessor:getModifier:getCreator:getUploadCreator:${prop}`, | ||
params, | ||
}), | ||
}, | ||
) as IUploadCreator; | ||
} | ||
|
||
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'], | ||
}); | ||
|
||
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('appId')); | ||
} | ||
|
||
const response = await this.senderFn({ | ||
method: 'bridges:getMessageBridge:doCreate', | ||
params: [result, AppObjectRegistry.get('appId')], | ||
}); | ||
|
||
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('appId')], | ||
}); | ||
|
||
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('appId')], | ||
}); | ||
|
||
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('appId')], | ||
}); | ||
|
||
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('appId')], | ||
}); | ||
|
||
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('appId')], | ||
}); | ||
|
||
return String(response.result); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// deno-lint-ignore-file no-explicit-any | ||
import { afterAll, beforeEach, describe, it } from 'https://deno.land/std@0.203.0/testing/bdd.ts'; | ||
import { assertSpyCall, spy } from 'https://deno.land/std@0.203.0/testing/mock.ts'; | ||
import { assert, assertEquals, assertNotInstanceOf } from 'https://deno.land/std@0.203.0/assert/mod.ts'; | ||
|
||
import { AppObjectRegistry } from '../../../AppObjectRegistry.ts'; | ||
import { ModifyCreator } from '../modify/ModifyCreator.ts'; | ||
|
||
describe('ModifyCreator', () => { | ||
const senderFn = (r: any) => | ||
Promise.resolve({ | ||
id: Math.random().toString(36).substring(2), | ||
jsonrpc: '2.0', | ||
result: r, | ||
serialize() { | ||
return JSON.stringify(this); | ||
}, | ||
}); | ||
|
||
beforeEach(() => { | ||
AppObjectRegistry.clear(); | ||
AppObjectRegistry.set('appId', 'deno-test'); | ||
}); | ||
|
||
afterAll(() => { | ||
AppObjectRegistry.clear(); | ||
}); | ||
|
||
it('sends the correct payload in the request to create a message', async () => { | ||
const spying = spy(senderFn); | ||
const modifyCreator = new ModifyCreator(spying); | ||
const messageBuilder = modifyCreator.startMessage(); | ||
|
||
// Importing types from the Apps-Engine is problematic, so we'll go with `any` here | ||
messageBuilder | ||
.setRoom({ id: '123' } as any) | ||
.setSender({ id: '456' } as any) | ||
.setText('Hello World') | ||
.setUsernameAlias('alias') | ||
.setAvatarUrl('https://avatars.com/123'); | ||
|
||
// We can't get a legitimate return value here, so we ignore it | ||
// but we need to know that the request sent was well formed | ||
await modifyCreator.finish(messageBuilder); | ||
|
||
assertSpyCall(spying, 0, { | ||
args: [ | ||
{ | ||
method: 'bridges:getMessageBridge:doCreate', | ||
params: [ | ||
{ | ||
room: { id: '123' }, | ||
sender: { id: '456' }, | ||
text: 'Hello World', | ||
alias: 'alias', | ||
avatarUrl: 'https://avatars.com/123', | ||
}, | ||
'deno-test', | ||
], | ||
}, | ||
], | ||
}); | ||
}); | ||
|
||
it('sends the correct payload in the request to upload a buffer', async () => { | ||
const modifyCreator = new ModifyCreator(senderFn); | ||
|
||
const result = await modifyCreator.getUploadCreator().uploadBuffer(new Uint8Array([1, 2, 3, 4]), 'text/plain'); | ||
|
||
assertEquals(result.result, { | ||
method: 'accessor:getModifier:getCreator:getUploadCreator:uploadBuffer', | ||
params: [new Uint8Array([1, 2, 3, 4]), 'text/plain'], | ||
}); | ||
}); | ||
|
||
it('sends the correct payload in the request to create a visitor', async () => { | ||
const modifyCreator = new ModifyCreator(senderFn); | ||
|
||
const result = (await modifyCreator.getLivechatCreator().createVisitor({ | ||
token: 'random token', | ||
username: 'random username for visitor', | ||
name: 'Random Visitor', | ||
})) as any; // We modified the send function so it changed the original return type of the function | ||
|
||
assertEquals(result.result, { | ||
method: 'accessor:getModifier:getCreator:getLivechatCreator:createVisitor', | ||
params: [ | ||
{ | ||
token: 'random token', | ||
username: 'random username for visitor', | ||
name: 'Random Visitor', | ||
}, | ||
], | ||
}); | ||
}); | ||
|
||
// This test is important because if we return a promise we break API compatibility | ||
it('does not return a promise for calls of the createToken() method of the LivechatCreator', () => { | ||
const modifyCreator = new ModifyCreator(senderFn); | ||
|
||
const result = modifyCreator.getLivechatCreator().createToken(); | ||
|
||
assertNotInstanceOf(result, Promise); | ||
assert(typeof result === 'string', `Expected "${result}" to be of type "string", but got "${typeof result}"`); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters