Skip to content

Commit

Permalink
Update with alpha files
Browse files Browse the repository at this point in the history
  • Loading branch information
d-gubert committed Aug 1, 2024
1 parent e54f678 commit 8d47e68
Show file tree
Hide file tree
Showing 29 changed files with 282 additions and 13 deletions.
30 changes: 30 additions & 0 deletions packages/apps-engine/deno-runtime/handlers/app/handleOnUpdate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { App } from '@rocket.chat/apps-engine/definition/App.ts';

import { AppObjectRegistry } from '../../AppObjectRegistry.ts';
import { AppAccessorsInstance } from '../../lib/accessors/mod.ts';

export default async function handleOnUpdate(params: unknown): Promise<boolean> {
const app = AppObjectRegistry.get<App>('app');

if (typeof app?.onUpdate !== 'function') {
throw new Error('App must contain an onUpdate function', {
cause: 'invalid_app',
});
}

if (!Array.isArray(params)) {
throw new Error('Invalid params', { cause: 'invalid_param_type' });
}

const [context] = params as [Record<string, unknown>];

await app.onUpdate(
context,
AppAccessorsInstance.getReader(),
AppAccessorsInstance.getHttp(),
AppAccessorsInstance.getPersistence(),
AppAccessorsInstance.getModifier(),
);

return true;
}
4 changes: 4 additions & 0 deletions packages/apps-engine/deno-runtime/handlers/app/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import handleOnSettingUpdated from './handleOnSettingUpdated.ts';
import handleListener from '../listener/handler.ts';
import handleUIKitInteraction, { uikitInteractions } from '../uikit/handler.ts';
import { AppObjectRegistry } from '../../AppObjectRegistry.ts';
import handleOnUpdate from './handleOnUpdate.ts';

export default async function handleApp(method: string, params: unknown): Promise<Defined | JsonRpcError> {
const [, appMethod] = method.split(':');
Expand Down Expand Up @@ -83,6 +84,9 @@ export default async function handleApp(method: string, params: unknown): Promis
case 'onSettingUpdated':
result = await handleOnSettingUpdated(params);
break;
case 'onUpdate':
result = await handleOnUpdate(params);
break;
default:
throw new JsonRpcError('Method not found', -32601);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const { RocketChatAssociationModel } = require('@rocket.chat/apps-engine/definit
RocketChatAssociationModel: typeof _RocketChatAssociationModel;
};

export type AppVideoConference = Pick<IGroupVideoConference, 'rid' | 'providerName' | 'providerData' | 'title'> & {
export type AppVideoConference = Pick<IGroupVideoConference, 'rid' | 'providerName' | 'providerData' | 'title' | 'discussionRid'> & {
createdBy: IGroupVideoConference['createdBy']['_id'];
};

Expand All @@ -28,6 +28,7 @@ export class VideoConferenceBuilder implements IVideoConferenceBuilder {
createdBy: data.createdBy,
providerName: data.providerName!,
title: data.title!,
discussionRid: data.discussionRid,
};

return this;
Expand Down Expand Up @@ -78,6 +79,15 @@ export class VideoConferenceBuilder implements IVideoConferenceBuilder {
return this.call.title;
}

public setDiscussionRid(rid: AppVideoConference['discussionRid']): IVideoConferenceBuilder {
this.call.discussionRid = rid;
return this;
}

public getDiscussionRid(): AppVideoConference['discussionRid'] {
return this.call.discussionRid;
}

public getVideoConference(): AppVideoConference {
return this.call;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ export class VideoConferenceExtender implements IVideoConferenceExtender {
return this;
}

public setDiscussionRid(rid: VideoConference['discussionRid']): IVideoConferenceExtender {
this.videoConference.discussionRid = rid;

return this;
}

public getVideoConference(): VideoConference {
return structuredClone(this.videoConference);
}
Expand Down
8 changes: 8 additions & 0 deletions packages/apps-engine/src/definition/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
IModify,
IPersistence,
IRead,
IAppUpdateContext,
} from './accessors';
import { AppStatus } from './AppStatus';
import type { IApp } from './IApp';
Expand Down Expand Up @@ -181,6 +182,13 @@ export abstract class App implements IApp {
*/
public async onInstall(context: IAppInstallationContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify): Promise<void> {}

/**
* Method which is called when the App is updated and it is called one single time.
*
* This method is NOT called when the App is installed.
*/
public async onUpdate(context: IAppUpdateContext, read: IRead, http: IHttp, persistence: IPersistence, modify: IModify): Promise<void> {}

/**
* Method which is called whenever a setting which belongs to this App has been updated
* by an external system and not this App itself. The setting passed is the newly updated one.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { IUser } from '../users';

export interface IAppUpdateContext {
user?: IUser;
oldAppVersion: string;
}
12 changes: 12 additions & 0 deletions packages/apps-engine/src/definition/accessors/ILivechatCreator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import type { IUser } from '../users';

export interface IExtraRoomParams {
source?: ILivechatRoom['source'];
customFields?: {
[key: string]: unknown;
};
}

export interface ILivechatCreator {
Expand All @@ -16,13 +19,22 @@ export interface ILivechatCreator {
* @param agent The agent responsible for the room
*/
createRoom(visitor: IVisitor, agent: IUser, extraParams?: IExtraRoomParams): Promise<ILivechatRoom>;

/**
* @deprecated Use `createAndReturnVisitor` instead.
* Creates a Livechat visitor
*
* @param visitor Data of the visitor to be created
*/
createVisitor(visitor: IVisitor): Promise<string>;

/**
* Creates a Livechat visitor
*
* @param visitor Data of the visitor to be created
*/
createAndReturnVisitor(visitor: IVisitor): Promise<IVisitor | undefined>;

/**
* Creates a token to be used when
* creating a new livechat visitor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ export interface IModifyDeleter {
deleteUsers(appId: Exclude<IUser['appId'], undefined>, userType: UserType.APP | UserType.BOT): Promise<boolean>;

deleteMessage(message: IMessage, user: IUser): Promise<void>;

removeUsersFromRoom(roomId: string, usernames: Array<string>): Promise<void>;
}
15 changes: 10 additions & 5 deletions packages/apps-engine/src/definition/accessors/IRoomRead.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { IMessage } from '../messages/index';
import type { GetMessagesOptions } from '../../server/bridges/RoomBridge';
import type { IMessageRaw } from '../messages/index';
import type { IRoom } from '../rooms/index';
import type { IUser } from '../users/index';

Expand Down Expand Up @@ -40,12 +41,16 @@ export interface IRoomRead {
getCreatorUserByName(name: string): Promise<IUser | undefined>;

/**
* Gets an iterator for all of the messages in the provided room.
* Retrieves an array of messages from the specified room.
*
* @param roomId the room's id
* @returns an iterator for messages
* @param roomId The unique identifier of the room from which to retrieve messages.
* @param options Optional parameters for retrieving messages:
* - limit: The maximum number of messages to retrieve. Maximum 100
* - skip: The number of messages to skip (for pagination).
* - sort: An object defining the sorting order of the messages. Each key is a field to sort by, and the value is either "asc" for ascending order or "desc" for descending order.
* @returns A Promise that resolves to an array of IMessage objects representing the messages in the room.
*/
getMessages(roomId: string): Promise<IterableIterator<IMessage>>;
getMessages(roomId: string, options?: Partial<GetMessagesOptions>): Promise<Array<IMessageRaw>>;

/**
* Gets an iterator for all of the users in the provided room.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,9 @@ export interface IVideoConferenceBuilder {

getTitle(): string;

setDiscussionRid(rid: string | undefined): IVideoConferenceBuilder;

getDiscussionRid(): string | undefined;

getVideoConference(): AppVideoConference;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ export interface IVideoConferenceExtender {

addUser(userId: VideoConferenceMember['_id'], ts?: VideoConferenceMember['ts']): IVideoConferenceExtender;

setDiscussionRid(rid: VideoConference['discussionRid']): IVideoConferenceExtender;

getVideoConference(): VideoConference;
}
1 change: 1 addition & 0 deletions packages/apps-engine/src/definition/accessors/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './IApiExtend';
export * from './IAppAccessors';
export * from './IAppInstallationContext';
export * from './IAppUpdateContext';
export * from './IAppUninstallationContext';
export * from './ICloudWorkspaceRead';
export * from './IConfigurationExtend';
Expand Down
40 changes: 40 additions & 0 deletions packages/apps-engine/src/definition/messages/IMessageRaw.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { IBlock, Block } from '@rocket.chat/ui-kit';

import type { IRoom } from '../rooms';
import type { IUserLookup } from '../users';
import type { IMessageAttachment } from './IMessageAttachment';
import type { IMessageFile } from './IMessageFile';
import type { IMessageReactions } from './IMessageReaction';

/**
* The raw version of a message, without resolved information for relationship fields, i.e.
* `room`, `sender` and `editor` are not the complete entity like they are in `IMessage`
*
* This is used in methods that fetch multiple messages at the same time, as resolving the relationship
* fields require additional queries to the database and would hit the system's performance significantly.
*/
export interface IMessageRaw {
id: string;
roomId: IRoom['id'];
sender: IUserLookup;
createdAt: Date;
threadId?: string;
text?: string;
updatedAt?: Date;
editor?: IUserLookup;
editedAt?: Date;
emoji?: string;
avatarUrl?: string;
alias?: string;
file?: IMessageFile;
attachments?: Array<IMessageAttachment>;
reactions?: IMessageReactions;
groupable?: boolean;
parseUrls?: boolean;
customFields?: { [key: string]: any };
blocks?: Array<IBlock | Block>;
starred?: Array<{ _id: string }>;
pinned?: boolean;
pinnedAt?: Date;
pinnedBy?: IUserLookup;
}
2 changes: 2 additions & 0 deletions packages/apps-engine/src/definition/messages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { IMessageDeleteContext } from './IMessageDeleteContext';
import { IMessageFile } from './IMessageFile';
import { IMessageFollowContext } from './IMessageFollowContext';
import { IMessagePinContext } from './IMessagePinContext';
import { IMessageRaw } from './IMessageRaw';
import { IMessageReaction, IMessageReactions } from './IMessageReaction';
import { IMessageReactionContext } from './IMessageReactionContext';
import { IMessageReportContext } from './IMessageReportContext';
Expand Down Expand Up @@ -39,6 +40,7 @@ export {
IMessageAttachmentField,
IMessageAction,
IMessageFile,
IMessageRaw,
IMessageReactions,
IMessageReaction,
IPostMessageDeleted,
Expand Down
1 change: 1 addition & 0 deletions packages/apps-engine/src/definition/metadata/AppMethod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export enum AppMethod {
ONDISABLE = 'onDisable',
ONINSTALL = 'onInstall',
ONUNINSTALL = 'onUninstall',
ONUPDATE = 'onUpdate',
ON_PRE_SETTING_UPDATE = 'onPreSettingUpdate',
ONSETTINGUPDATED = 'onSettingUpdated',
SETSTATUS = 'setStatus',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,9 @@ export interface IRoomUserLeaveContext {
* The room that the user is leaving
*/
room: IRoom;

/**
* The user that removed the room member
*/
removedBy?: IUser;
}
1 change: 1 addition & 0 deletions packages/apps-engine/src/definition/users/IUserLookup.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface IUserLookup {
_id: string;
username: string;
name?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export interface IVideoConfProvider {
cam?: boolean;
// Indicates if Rocket.Chat can send a custom title for the video conferences
title?: boolean;
// Indicates if the provider supports Rocket.Chat's Persistent Chat feature on its conferences.
persistentChat?: boolean;
};

// Optional function that can be used to determine if the provider is ready to use or still needs to be configured
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { IGroupVideoConference, IVideoConference } from '../videoConferences/IVideoConference';

export type VideoConfData = Pick<IVideoConference, '_id' | 'type' | 'rid' | 'createdBy' | 'providerData'> & { title?: IGroupVideoConference['title'] };
export type VideoConfData = Pick<IVideoConference, '_id' | 'type' | 'rid' | 'createdBy' | 'providerData' | 'discussionRid'> & {
title?: IGroupVideoConference['title'];
};

export type VideoConfDataExtended = VideoConfData & Required<Pick<IVideoConference, 'url'>>;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { IGroupVideoConference } from './IVideoConference';

// Type for video conferences being created by an app
export type AppVideoConference = Pick<IGroupVideoConference, 'rid' | 'providerName' | 'providerData' | 'title'> & {
export type AppVideoConference = Pick<IGroupVideoConference, 'rid' | 'providerName' | 'providerData' | 'title' | 'discussionRid'> & {
createdBy: IGroupVideoConference['createdBy']['_id'];
};
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export interface IVideoConference {
providerData?: Record<string, any>;

ringing?: boolean;
discussionRid?: string;
}

export interface IDirectVideoConference extends IVideoConference {
Expand Down
26 changes: 25 additions & 1 deletion packages/apps-engine/src/server/AppManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,11 @@ export class AppManager {
this.apps.delete(app.getID());
}

public async update(appPackage: Buffer, permissionsGranted: Array<IPermission>, updateOptions = { loadApp: true }): Promise<AppFabricationFulfillment> {
public async update(
appPackage: Buffer,
permissionsGranted: Array<IPermission>,
updateOptions: { loadApp?: boolean; user?: IUser } = { loadApp: true },
): Promise<AppFabricationFulfillment> {
const aff = new AppFabricationFulfillment();
const result = await this.getParser().unpackageApp(appPackage);

Expand Down Expand Up @@ -724,6 +728,8 @@ export class AppManager {
.catch(() => {});
}

await this.updateApp(app, updateOptions.user, old.info.version);

return aff;
}

Expand Down Expand Up @@ -934,6 +940,24 @@ export class AppManager {
return result;
}

private async updateApp(app: ProxiedApp, user: IUser | null, oldAppVersion: string): Promise<boolean> {
let result: boolean;

try {
await app.call(AppMethod.ONUPDATE, { oldAppVersion, user });

result = true;
} catch (e) {
const status = AppStatus.ERROR_DISABLED;

result = false;

await app.setStatus(status);
}

return result;
}

private async initializeApp(storageItem: IAppStorageItem, app: ProxiedApp, saveToDb = true, silenceStatus = false): Promise<boolean> {
let result: boolean;

Expand Down
7 changes: 7 additions & 0 deletions packages/apps-engine/src/server/accessors/LivechatCreator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,17 @@ export class LivechatCreator implements ILivechatCreator {
return this.bridges.getLivechatBridge().doCreateRoom(visitor, agent, this.appId, extraParams);
}

/**
* @deprecated Use `createAndReturnVisitor` instead.
*/
public createVisitor(visitor: IVisitor): Promise<string> {
return this.bridges.getLivechatBridge().doCreateVisitor(visitor, this.appId);
}

public createAndReturnVisitor(visitor: IVisitor): Promise<IVisitor | undefined> {
return this.bridges.getLivechatBridge().doCreateAndReturnVisitor(visitor, this.appId);
}

public createToken(): string {
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
}
Expand Down
Loading

0 comments on commit 8d47e68

Please sign in to comment.