diff --git a/docs/proposals/apps-accessor-consolidation/README.md b/docs/proposals/apps-accessor-consolidation/README.md index 269f6bc4ea6b4..65357a40b3a18 100644 --- a/docs/proposals/apps-accessor-consolidation/README.md +++ b/docs/proposals/apps-accessor-consolidation/README.md @@ -485,9 +485,16 @@ since consolidating more logic into the runtime makes the assumption more load-b dropping. 3. **`messenger.sendRequest` timeout** — the runtime-side TODO becomes more prominent once all accessor traffic flows through it. -4. **Drop the legacy `_accessors` threading** through `AppApi.runExecutor`, - `AppSlashCommand.runTheCode`, `AppVideoConfProvider.runTheCode`, - `AppOutboundCommunicationProvider.runTheCode` signatures. +4. ✅ **Drop the legacy `_accessors` threading + delete the dead host accessor layer.** — **landed as + Phase 5** (§8). Un-threaded the ignored `accessors: AppAccessorManager` parameter from + `AppApi.runExecutor`, `AppSlashCommand`/`AppVideoConfProvider`/`AppOutboundCommunicationProvider` + `run*`/`runTheCode` and their managers; deleted `AppAccessorManager` (+ its `getAccessorManager()` + on `AppManager` and the `purifyApp` call), the entire `src/server/accessors/` directory (unreachable + from the subprocess after Phase 4), the host `src/server/misc/UIHelper.ts` copy (its only importers + were those deleted accessors), and the `managers/index.ts` export. Behavior-neutral cleanup; kept + separate from the Phase 4 message-path teardown because it touches the sandbox-execution core. + (The parity harness is **not** removed — it became a permanent test utility the base-runtime + accessor tests depend on.) 5. **Consolidated host↔subprocess protocol/SDK** — a single typed manifest of every host-bound method and its accepted params (the §5.2 explicit method/exception list is the seed), replacing today's hand-rolled message strings and per-param normalization judgment with a declared contract. A @@ -672,21 +679,79 @@ returning the bridge value, matching the interface. **RPC-boundary note:** `SettingRead.getValueById` treats `null` and `undefined` alike as "does not exist" (undefined serializes to null across the boundary), same adaptation as `ServerSettingRead`. -### Phase 4 — Teardown - -1. Replace `AppListenerManager.executePostMessageSent`'s `getReader(...).getAppUser()` with - `bridges.getUserBridge().doGetAppUser(appId)`. -2. Delete `handleAccessorMessage`, `ALLOWED_ACCESSOR_METHODS`, `isValidOrigin`, - `getAccessorForOrigin`, and the `accessor:` branch in `handleIncomingMessage`. -3. Delete `src/server/accessors/` entirely (including dead `AppAccessors`, `Http`), delete - `AppAccessorManager` (and its `purifyApp` call in `AppManager`), remove `proxify` from `mod.ts`, - and drop the now-unused `getAccessorManager()` threading in managers (follow-up #4 can ride - along). -4. Delete the `src/server/misc/UIHelper.ts` copy (its last importers are gone with the host - accessors), leaving the base-runtime copy as the single source of truth; remove the transitional - parity harness (§6). -5. CHANGELOG entry; update any architecture docs referencing the accessor message category. - -**End state:** `BaseRuntimeSubprocessController` handles exactly one app-originated RPC category — -`bridges:*` — with a single dispatcher, a single permission model, and a single accessor -implementation living in `packages/apps/base-runtime`. +### Phase 4 — Teardown — ✅ landed (message-path teardown; dead-class deletion moved to follow-up #4) + +1. ✅ Replaced `AppListenerManager.executePostMessageSent`'s `getReader(appId).getUserReader().getAppUser()` + with `this.manager.getBridges().getUserBridge().doGetAppUser(appId)` — the only load-bearing + host-side accessor consumer outside the RPC path. `AppListenerManager` no longer references + `AppAccessorManager`. +2. ✅ Deleted `handleAccessorMessage`, `ALLOWED_ACCESSOR_METHODS`, `isValidOrigin`, + `getAccessorForOrigin`, the `accessor:` branch in `handleIncomingMessage`, and the controller's + now-unused `accessors`/`api` fields (and their `manager.getAccessorManager()`/`getApiManager()` + reads). `proxify` and `WithProxy` were already removed from `mod.ts` in Phase 3. **The + `accessor:*` message category no longer exists — the controller dispatches only `bridges:*`, + `ready`, `log`, and the error notifications.** `JSONRPC_METHOD_NOT_FOUND` is kept (it is imported by + `ProxiedApp`, `AppListenerManager`, `AppVideoConfProvider`). +3. ✅ Adapted `tests/server/runtime/DenoRuntimeSubprocessController.test.ts`: removed the four + `handleAccessorMessage` cases (HTTP accessor, IRead, IEnvironmentReader-via-IRead, LivechatCreator + visitor) that exercised the now-deleted `accessor:*` dispatch path. Their host-side resolution no + longer exists (the subprocess resolves accessors locally via `bridges:*`), and the equivalent + behavior is covered by the surviving `handleBridgeMessage` "message bridge" case here plus the + base-runtime accessor/RemoteBridges suites. The unused `UserStatusConnection`/`UserType` import was + dropped with them. + +**Scoping decision — physical deletion of the dead accessor classes is folded into follow-up #4.** +Deleting `src/server/accessors/` + `AppAccessorManager` requires first un-threading the (ignored) +`accessors: AppAccessorManager` parameter from the sandbox-execution core (`AppApi.runExecutor`, +`AppSlashCommand`/`AppVideoConfProvider`/`AppOutboundCommunicationProvider` `run*`/`runTheCode`, and +their managers). That is exactly follow-up #4 ("drop the legacy `_accessors` threading"), which the +plan already carved out as a separate, behavior-neutral change. Rather than refactor the execution +core at the tail of this work for zero behavior benefit, the now-**unreachable** host accessor +classes + `AppAccessorManager` are left in place (dead code — nothing on the subprocess path reaches +them) and their removal is done in follow-up #4 together with the threading cleanup. The host +`src/server/misc/UIHelper.ts` copy and the parity harness stay for the same reason (the harness has +also become a genuine, permanent test utility that the Phase 1–3 tests depend on, so it is retained +rather than removed). + +**End state (primary objectives met):** `BaseRuntimeSubprocessController` handles exactly one +app-originated RPC category — `bridges:*` — with a single dispatcher and a single permission model, +and accessor *behavior* lives in exactly one place, `packages/apps/base-runtime`. `handleAccessorMessage` +and the entire `accessor:*` category are gone. What remains is dead-code removal (Phase 5 / follow-up #4). + +### Phase 5 — Dead host accessor layer removal (follow-up #4) — ✅ landed + +Physical removal of the now-unreachable host accessor code. Behavior-neutral: nothing on the +subprocess path reached any of it after Phase 4. + +1. ✅ **Un-threaded the vestigial `accessors` parameter** from the sandbox-execution core. The + `run*`/`runTheCode` methods already ignored it (`_accessors`) — the app executes in the subprocess + via `getRuntimeController().sendRequest`, so the host-side accessor manager was never consulted. + Dropped the parameter from `AppApi.runExecutor`, `AppSlashCommand.runExecutorOrPreviewer`/ + `runPreviewExecutor`/`runTheCode`, all `AppVideoConfProvider.run*`/`runTheCode`, and + `AppOutboundCommunicationProvider.runGetProviderMetadata`/`runSendOutboundMessage`/`runTheCode`, and + updated the four managers' call sites. Removed the now-unused `private readonly accessors` field + (and its `this.manager.getAccessorManager()` assignment) from `AppApiManager`, + `AppSlashCommandManager`, `AppVideoConfProviderManager`, and `AppOutboundCommunicationProviderManager`. +2. ✅ **Deleted `AppAccessorManager`** (`src/server/managers/AppAccessorManager.ts`), removed its + `managers/index.ts` export, and removed `AppManager`'s `accessorManager` field, its + `new AppAccessorManager(this)` construction, the `getAccessorManager()` accessor, and the + `accessorManager.purifyApp(...)` call in `removeLocal` (a no-op — the caches it cleared were never + populated once no host code called `getReader`/`getModifier`/etc.). +3. ✅ **Deleted the entire `src/server/accessors/` directory** (64 files — the host copies of the + readers, modifiers, builders, environment accessors, and the configuration/registration accessors) + and the host `src/server/misc/UIHelper.ts` (only ever imported by those deleted accessors). The + base-runtime holds the single source of truth for all of this. +4. ✅ **Adapted tests:** deleted `tests/server/accessors/` (35 host-accessor unit tests — the + base-runtime suites cover the equivalent behavior) and `tests/server/managers/AppAccessorManager.test.ts`; + removed the `AppAccessorManager`/`getAccessorManager()`/`(x as any).accessors` setup and assertions + from the four manager tests, `AppSettingsManager.test.ts`, `AppManager.test.ts`, the two Deno-runtime + integration tests, and `AppListenerManager.test.ts`. + +**Verification:** host `tsc` error-set unchanged vs the environmental-only baseline (no new errors); +`test:node` host suites green (excluding the two `deno`-spawn integration suites, which require the +`deno` binary unavailable in this environment); base-runtime suite unaffected (untouched by this phase). + +**End state:** the `@rocket.chat/apps` host no longer contains any accessor implementation or accessor +manager. The only accessor-shaped code left on the host is the bridge layer (`AppBridges`/`do*`) and +`AppResourceBridge`; every accessor an app actually uses is built and resolved inside +`packages/apps/base-runtime`. diff --git a/packages/apps/src/server/AppManager.ts b/packages/apps/src/server/AppManager.ts index ce5656a3b62f8..fe60b52603d03 100644 --- a/packages/apps/src/server/AppManager.ts +++ b/packages/apps/src/server/AppManager.ts @@ -17,7 +17,6 @@ import { AppCompiler, AppFabricationFulfillment, AppPackageParser } from './comp import { InvalidLicenseError } from './errors'; import { InvalidInstallationError } from './errors/InvalidInstallationError'; import { - AppAccessorManager, AppApiManager, AppExternalComponentManager, AppLicenseManager, @@ -87,8 +86,6 @@ export class AppManager { private readonly compiler: AppCompiler; - private readonly accessorManager: AppAccessorManager; - private readonly listenerManager: AppListenerManager; private readonly commandManager: AppSlashCommandManager; @@ -153,7 +150,6 @@ export class AppManager { this.parser = new AppPackageParser(); this.compiler = new AppCompiler(); - this.accessorManager = new AppAccessorManager(this); this.listenerManager = new AppListenerManager(this); this.commandManager = new AppSlashCommandManager(this); this.apiManager = new AppApiManager(this); @@ -200,11 +196,6 @@ export class AppManager { return this.compiler; } - /** Gets the accessor manager instance. */ - public getAccessorManager(): AppAccessorManager { - return this.accessorManager; - } - /** Gets the instance of the Bridge manager. */ public getBridges(): AppBridges { return this.bridges; @@ -1096,7 +1087,6 @@ export class AppManager { this.listenerManager.lockEssentialEvents(app); this.externalComponentManager.unregisterExternalComponents(app.getID()); await this.apiManager.unregisterApis(app.getID()); - this.accessorManager.purifyApp(app.getID()); this.uiActionButtonManager.clearAppActionButtons(app.getID()); await this.videoConfProviderManager.unregisterProviders(app.getID()); await this.outboundCommunicationProviderManager.unregisterProviders(app.getID(), { diff --git a/packages/apps/src/server/accessors/ApiExtend.ts b/packages/apps/src/server/accessors/ApiExtend.ts deleted file mode 100644 index 46e9eeab782bc..0000000000000 --- a/packages/apps/src/server/accessors/ApiExtend.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { IApiExtend } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IApi } from '@rocket.chat/apps-engine/definition/api'; - -import type { AppApiManager } from '../managers/AppApiManager'; - -export class ApiExtend implements IApiExtend { - constructor( - private readonly manager: AppApiManager, - private readonly appId: string, - ) {} - - public provideApi(api: IApi): Promise { - return Promise.resolve(this.manager.addApi(this.appId, api)); - } -} diff --git a/packages/apps/src/server/accessors/AppAccessors.ts b/packages/apps/src/server/accessors/AppAccessors.ts deleted file mode 100644 index 0959de4db4fea..0000000000000 --- a/packages/apps/src/server/accessors/AppAccessors.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { IAppAccessors, IEnvironmentRead, IEnvironmentWrite, IHttp, IRead } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IApiEndpointMetadata } from '@rocket.chat/apps-engine/definition/api'; - -import type { AppManager } from '../AppManager'; -import type { AppAccessorManager } from '../managers/AppAccessorManager'; -import type { AppApiManager } from '../managers/AppApiManager'; - -export class AppAccessors implements IAppAccessors { - private accessorManager: AppAccessorManager; - - private apiManager: AppApiManager; - - constructor( - manager: AppManager, - private readonly appId: string, - ) { - this.accessorManager = manager.getAccessorManager(); - this.apiManager = manager.getApiManager(); - } - - public get environmentReader(): IEnvironmentRead { - return this.accessorManager.getEnvironmentRead(this.appId); - } - - public get environmentWriter(): IEnvironmentWrite { - return this.accessorManager.getEnvironmentWrite(this.appId); - } - - public get reader(): IRead { - return this.accessorManager.getReader(this.appId); - } - - public get http(): IHttp { - return this.accessorManager.getHttp(this.appId); - } - - public get providedApiEndpoints(): Array { - return this.apiManager.listApis(this.appId); - } -} diff --git a/packages/apps/src/server/accessors/CloudWorkspaceRead.ts b/packages/apps/src/server/accessors/CloudWorkspaceRead.ts deleted file mode 100644 index 999ec62a9110a..0000000000000 --- a/packages/apps/src/server/accessors/CloudWorkspaceRead.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { ICloudWorkspaceRead } from '@rocket.chat/apps-engine/definition/accessors/ICloudWorkspaceRead'; -import type { IWorkspaceToken } from '@rocket.chat/apps-engine/definition/cloud/IWorkspaceToken'; - -import type { CloudWorkspaceBridge } from '../bridges/CloudWorkspaceBridge'; - -export class CloudWorkspaceRead implements ICloudWorkspaceRead { - constructor( - private readonly cloudBridge: CloudWorkspaceBridge, - private readonly appId: string, - ) {} - - public async getWorkspaceToken(scope: string): Promise { - return this.cloudBridge.doGetWorkspaceToken(scope, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/ConfigurationExtend.ts b/packages/apps/src/server/accessors/ConfigurationExtend.ts deleted file mode 100644 index a1629114efd20..0000000000000 --- a/packages/apps/src/server/accessors/ConfigurationExtend.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { - IApiExtend, - IConfigurationExtend, - IExternalComponentsExtend, - IHttpExtend, - ISchedulerExtend, - ISettingsExtend, - ISlashCommandsExtend, - IUIExtend, - IVideoConfProvidersExtend, - IOutboundCommunicationProviderExtend, -} from '@rocket.chat/apps-engine/definition/accessors'; - -export class ConfigurationExtend implements IConfigurationExtend { - constructor( - public readonly http: IHttpExtend, - public readonly settings: ISettingsExtend, - public readonly slashCommands: ISlashCommandsExtend, - public readonly api: IApiExtend, - public readonly externalComponents: IExternalComponentsExtend, - public readonly scheduler: ISchedulerExtend, - public readonly ui: IUIExtend, - public readonly videoConfProviders: IVideoConfProvidersExtend, - public readonly outboundCommunication: IOutboundCommunicationProviderExtend, - ) {} -} diff --git a/packages/apps/src/server/accessors/ConfigurationModify.ts b/packages/apps/src/server/accessors/ConfigurationModify.ts deleted file mode 100644 index 66de60bb0d93a..0000000000000 --- a/packages/apps/src/server/accessors/ConfigurationModify.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { - IConfigurationModify, - ISchedulerModify, - IServerSettingsModify, - ISlashCommandsModify, -} from '@rocket.chat/apps-engine/definition/accessors'; - -export class ConfigurationModify implements IConfigurationModify { - constructor( - public readonly serverSettings: IServerSettingsModify, - public readonly slashCommands: ISlashCommandsModify, - public readonly scheduler: ISchedulerModify, - ) {} -} diff --git a/packages/apps/src/server/accessors/ContactCreator.ts b/packages/apps/src/server/accessors/ContactCreator.ts deleted file mode 100644 index 26d66414052d9..0000000000000 --- a/packages/apps/src/server/accessors/ContactCreator.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { IContactCreator } from '@rocket.chat/apps-engine/definition/accessors/IContactCreator'; -import type { ILivechatContact } from '@rocket.chat/apps-engine/definition/livechat'; - -import type { AppBridges } from '../bridges'; - -export class ContactCreator implements IContactCreator { - constructor( - private readonly bridges: AppBridges, - private readonly appId: string, - ) {} - - verifyContact(verifyContactChannelParams: { - contactId: string; - field: string; - value: string; - visitorId: string; - roomId: string; - }): Promise { - return this.bridges.getContactBridge().doVerifyContact(verifyContactChannelParams, this.appId); - } - - addContactEmail(contactId: ILivechatContact['_id'], email: string): Promise { - return this.bridges.getContactBridge().doAddContactEmail(contactId, email, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/ContactRead.ts b/packages/apps/src/server/accessors/ContactRead.ts deleted file mode 100644 index c950bca5d1327..0000000000000 --- a/packages/apps/src/server/accessors/ContactRead.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { IContactRead } from '@rocket.chat/apps-engine/definition/accessors/IContactRead'; -import type { ILivechatContact } from '@rocket.chat/apps-engine/definition/livechat'; - -import type { AppBridges } from '../bridges'; - -export class ContactRead implements IContactRead { - constructor( - private readonly bridges: AppBridges, - private readonly appId: string, - ) {} - - public getById(contactId: ILivechatContact['_id']): Promise { - return this.bridges.getContactBridge().doGetById(contactId, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/DiscussionBuilder.ts b/packages/apps/src/server/accessors/DiscussionBuilder.ts deleted file mode 100644 index 38391c871d928..0000000000000 --- a/packages/apps/src/server/accessors/DiscussionBuilder.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { IDiscussionBuilder } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; -import { RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata'; -import { RoomType } from '@rocket.chat/apps-engine/definition/rooms'; -import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms/IRoom'; - -import { RoomBuilder } from './RoomBuilder'; - -export class DiscussionBuilder extends RoomBuilder implements IDiscussionBuilder { - public declare kind: RocketChatAssociationModel.DISCUSSION; - - private reply: string; - - private parentMessage: IMessage; - - constructor(data?: Partial) { - 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; - } -} diff --git a/packages/apps/src/server/accessors/EmailCreator.ts b/packages/apps/src/server/accessors/EmailCreator.ts deleted file mode 100644 index 921378ed8504d..0000000000000 --- a/packages/apps/src/server/accessors/EmailCreator.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { IEmailCreator } from '@rocket.chat/apps-engine/definition/accessors/IEmailCreator'; -import type { IEmail } from '@rocket.chat/apps-engine/definition/email'; - -import type { AppBridges } from '../bridges'; - -export class EmailCreator implements IEmailCreator { - constructor( - private readonly bridges: AppBridges, - private readonly appId: string, - ) {} - - public async send(email: IEmail): Promise { - return this.bridges.getEmailBridge().doSendEmail(email, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/EnvironmentRead.ts b/packages/apps/src/server/accessors/EnvironmentRead.ts deleted file mode 100644 index 8400a2c79a4de..0000000000000 --- a/packages/apps/src/server/accessors/EnvironmentRead.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { - IEnvironmentalVariableRead, - IEnvironmentRead, - IServerSettingRead, - ISettingRead, -} from '@rocket.chat/apps-engine/definition/accessors'; - -export class EnvironmentRead implements IEnvironmentRead { - constructor( - private readonly settings: ISettingRead, - private readonly serverSettings: IServerSettingRead, - private readonly envRead: IEnvironmentalVariableRead, - ) {} - - public getSettings(): ISettingRead { - return this.settings; - } - - public getServerSettings(): IServerSettingRead { - return this.serverSettings; - } - - public getEnvironmentVariables(): IEnvironmentalVariableRead { - return this.envRead; - } -} diff --git a/packages/apps/src/server/accessors/EnvironmentWrite.ts b/packages/apps/src/server/accessors/EnvironmentWrite.ts deleted file mode 100644 index d13bc5b834f64..0000000000000 --- a/packages/apps/src/server/accessors/EnvironmentWrite.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { IEnvironmentWrite, IServerSettingUpdater, ISettingUpdater } from '@rocket.chat/apps-engine/definition/accessors'; - -export class EnvironmentWrite implements IEnvironmentWrite { - constructor( - private readonly settings: ISettingUpdater, - private readonly serverSettings: IServerSettingUpdater, - ) {} - - public getSettings(): ISettingUpdater { - return this.settings; - } - - public getServerSettings(): IServerSettingUpdater { - return this.serverSettings; - } -} diff --git a/packages/apps/src/server/accessors/EnvironmentalVariableRead.ts b/packages/apps/src/server/accessors/EnvironmentalVariableRead.ts deleted file mode 100644 index c8e45f936b6f6..0000000000000 --- a/packages/apps/src/server/accessors/EnvironmentalVariableRead.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { IEnvironmentalVariableRead } from '@rocket.chat/apps-engine/definition/accessors'; - -import type { EnvironmentalVariableBridge } from '../bridges'; - -export class EnvironmentalVariableRead implements IEnvironmentalVariableRead { - constructor( - private readonly bridge: EnvironmentalVariableBridge, - private readonly appId: string, - ) {} - - public getValueByName(envVarName: string): Promise { - return this.bridge.doGetValueByName(envVarName, this.appId); - } - - public isReadable(envVarName: string): Promise { - return this.bridge.doIsReadable(envVarName, this.appId); - } - - public isSet(envVarName: string): Promise { - return this.bridge.doIsSet(envVarName, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/ExperimentalRead.ts b/packages/apps/src/server/accessors/ExperimentalRead.ts deleted file mode 100644 index 0b76281d9e405..0000000000000 --- a/packages/apps/src/server/accessors/ExperimentalRead.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { IExperimentalRead } from '@rocket.chat/apps-engine/definition/accessors'; - -import type { ExperimentalBridge } from '../bridges'; - -export class ExperimentalRead implements IExperimentalRead { - constructor( - protected readonly experimentalBridge: ExperimentalBridge, - protected readonly appId: string, - ) {} -} diff --git a/packages/apps/src/server/accessors/ExternalComponentsExtend.ts b/packages/apps/src/server/accessors/ExternalComponentsExtend.ts deleted file mode 100644 index 8acfdff1d3317..0000000000000 --- a/packages/apps/src/server/accessors/ExternalComponentsExtend.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { IExternalComponentsExtend } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IExternalComponent } from '@rocket.chat/apps-engine/definition/externalComponent/IExternalComponent'; - -import type { AppExternalComponentManager } from '../managers/AppExternalComponentManager'; - -export class ExternalComponentsExtend implements IExternalComponentsExtend { - constructor( - private readonly manager: AppExternalComponentManager, - private readonly appId: string, - ) {} - - public async register(externalComponent: IExternalComponent): Promise { - return Promise.resolve(this.manager.addExternalComponent(this.appId, externalComponent)); - } -} diff --git a/packages/apps/src/server/accessors/Http.ts b/packages/apps/src/server/accessors/Http.ts deleted file mode 100644 index aa9bcf403cd9b..0000000000000 --- a/packages/apps/src/server/accessors/Http.ts +++ /dev/null @@ -1,78 +0,0 @@ -import type { IHttp, IHttpExtend, IHttpRequest, IHttpResponse } from '@rocket.chat/apps-engine/definition/accessors'; -import { RequestMethod } from '@rocket.chat/apps-engine/definition/accessors'; - -import type { AppBridges } from '../bridges/AppBridges'; -import type { AppAccessorManager } from '../managers/AppAccessorManager'; - -export class Http implements IHttp { - constructor( - private readonly accessManager: AppAccessorManager, - private readonly bridges: AppBridges, - private readonly httpExtender: IHttpExtend, - private readonly appId: string, - ) {} - - public get(url: string, options?: IHttpRequest): Promise { - return this._processHandler(url, RequestMethod.GET, options); - } - - public put(url: string, options?: IHttpRequest): Promise { - return this._processHandler(url, RequestMethod.PUT, options); - } - - public post(url: string, options?: IHttpRequest): Promise { - return this._processHandler(url, RequestMethod.POST, options); - } - - public del(url: string, options?: IHttpRequest): Promise { - return this._processHandler(url, RequestMethod.DELETE, options); - } - - public patch(url: string, options?: IHttpRequest): Promise { - return this._processHandler(url, RequestMethod.PATCH, options); - } - - private async _processHandler(url: string, method: RequestMethod, options?: IHttpRequest): Promise { - let request = options || {}; - - if (typeof request.headers === 'undefined') { - request.headers = {}; - } - - this.httpExtender.getDefaultHeaders().forEach((value: string, key: string) => { - if (typeof request.headers[key] !== 'string') { - request.headers[key] = value; - } - }); - - if (typeof request.params === 'undefined') { - request.params = {}; - } - - this.httpExtender.getDefaultParams().forEach((value: string, key: string) => { - if (typeof request.params[key] !== 'string') { - request.params[key] = value; - } - }); - - const reader = this.accessManager.getReader(this.appId); - const persis = this.accessManager.getPersistence(this.appId); - - for (const handler of this.httpExtender.getPreRequestHandlers()) { - request = await handler.executePreHttpRequest(url, request, reader, persis); - } - - let response = await this.bridges.getHttpBridge().doCall({ - appId: this.appId, - method, - url, - request, - }); - - for (const handler of this.httpExtender.getPreResponseHandlers()) { - response = await handler.executePreHttpResponse(response, reader, persis); - } - - return response; - } -} diff --git a/packages/apps/src/server/accessors/HttpExtend.ts b/packages/apps/src/server/accessors/HttpExtend.ts deleted file mode 100644 index 98311a633577b..0000000000000 --- a/packages/apps/src/server/accessors/HttpExtend.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { IHttpExtend, IHttpPreRequestHandler, IHttpPreResponseHandler } from '@rocket.chat/apps-engine/definition/accessors'; - -export class HttpExtend implements IHttpExtend { - private headers: Map; - - private params: Map; - - private requests: Array; - - private responses: Array; - - constructor() { - this.headers = new Map(); - this.params = new Map(); - this.requests = []; - this.responses = []; - } - - public provideDefaultHeader(key: string, value: string): void { - this.headers.set(key, value); - } - - public provideDefaultHeaders(headers: { [key: string]: string }): void { - Object.keys(headers).forEach((key) => this.headers.set(key, headers[key])); - } - - public provideDefaultParam(key: string, value: string): void { - this.params.set(key, value); - } - - public provideDefaultParams(params: { [key: string]: string }): void { - Object.keys(params).forEach((key) => this.params.set(key, params[key])); - } - - public providePreRequestHandler(handler: IHttpPreRequestHandler): void { - this.requests.push(handler); - } - - public providePreResponseHandler(handler: IHttpPreResponseHandler): void { - this.responses.push(handler); - } - - public getDefaultHeaders(): Map { - return new Map(this.headers); - } - - public getDefaultParams(): Map { - return new Map(this.params); - } - - public getPreRequestHandlers(): Array { - return Array.from(this.requests); - } - - public getPreResponseHandlers(): Array { - return Array.from(this.responses); - } -} diff --git a/packages/apps/src/server/accessors/LivechatCreator.ts b/packages/apps/src/server/accessors/LivechatCreator.ts deleted file mode 100644 index df51bb1debabb..0000000000000 --- a/packages/apps/src/server/accessors/LivechatCreator.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { randomBytes } from 'node:crypto'; - -import type { ILivechatCreator } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IExtraRoomParams } from '@rocket.chat/apps-engine/definition/accessors/ILivechatCreator'; -import type { ILivechatRoom } from '@rocket.chat/apps-engine/definition/livechat/ILivechatRoom'; -import type { - IVisitorExternalIdentifier, - IVisitor, - ResolveVisitorContactData, -} from '@rocket.chat/apps-engine/definition/livechat/IVisitor'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -import type { AppBridges } from '../bridges'; - -export class LivechatCreator implements ILivechatCreator { - constructor( - private readonly bridges: AppBridges, - private readonly appId: string, - ) {} - - public resolveVisitor(externalId: IVisitorExternalIdentifier, contactData?: ResolveVisitorContactData): Promise { - return this.bridges.getLivechatBridge().doResolveVisitor(externalId, contactData, this.appId); - } - - public createRoom(visitor: IVisitor, agent: IUser, extraParams?: IExtraRoomParams): Promise { - return this.bridges.getLivechatBridge().doCreateRoom(visitor, agent, this.appId, extraParams); - } - - /** - * @deprecated Use `createAndReturnVisitor` instead. - */ - public createVisitor(visitor: IVisitor): Promise { - return this.bridges.getLivechatBridge().doCreateVisitor(visitor, this.appId); - } - - public createAndReturnVisitor(visitor: IVisitor): Promise { - return this.bridges.getLivechatBridge().doCreateAndReturnVisitor(visitor, this.appId); - } - - public createToken(): string { - return randomBytes(16).toString('hex'); // Ensures 128 bits of entropy - } -} diff --git a/packages/apps/src/server/accessors/LivechatMessageBuilder.ts b/packages/apps/src/server/accessors/LivechatMessageBuilder.ts deleted file mode 100644 index ffe02e3ed0997..0000000000000 --- a/packages/apps/src/server/accessors/LivechatMessageBuilder.ts +++ /dev/null @@ -1,192 +0,0 @@ -import type { ILivechatMessageBuilder, IMessageBuilder } from '@rocket.chat/apps-engine/definition/accessors'; -import type { ILivechatMessage } from '@rocket.chat/apps-engine/definition/livechat/ILivechatMessage'; -import type { IVisitor } from '@rocket.chat/apps-engine/definition/livechat/IVisitor'; -import type { IMessage, IMessageAttachment } from '@rocket.chat/apps-engine/definition/messages'; -import { RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata'; -import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; -import { RoomType } from '@rocket.chat/apps-engine/definition/rooms'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -import { MessageBuilder } from './MessageBuilder'; - -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): ILivechatMessageBuilder { - this.msg.attachments = attachments; - return this; - } - - public getAttachments(): Array { - 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); - } -} diff --git a/packages/apps/src/server/accessors/LivechatRead.ts b/packages/apps/src/server/accessors/LivechatRead.ts deleted file mode 100644 index 6e5d5cd443163..0000000000000 --- a/packages/apps/src/server/accessors/LivechatRead.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { ILivechatRead } from '@rocket.chat/apps-engine/definition/accessors/ILivechatRead'; -import type { IDepartment } from '@rocket.chat/apps-engine/definition/livechat'; -import type { ILivechatRoom } from '@rocket.chat/apps-engine/definition/livechat/ILivechatRoom'; -import type { IVisitor } from '@rocket.chat/apps-engine/definition/livechat/IVisitor'; -import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; - -import type { LivechatBridge } from '../bridges/LivechatBridge'; - -export class LivechatRead implements ILivechatRead { - constructor( - private readonly livechatBridge: LivechatBridge, - private readonly appId: string, - ) {} - - /** - * @deprecated please use the `isOnlineAsync` method instead. - * In the next major, this method will be `async` - */ - public isOnline(departmentId?: string): boolean { - console.warn( - "The `LivechatRead.isOnline` method is deprecated and won't behave as intended. Please use `LivechatRead.isOnlineAsync` instead", - ); - - return this.livechatBridge.doIsOnline(departmentId, this.appId); - } - - public isOnlineAsync(departmentId?: string): Promise { - return this.livechatBridge.doIsOnlineAsync(departmentId, this.appId); - } - - public getDepartmentsEnabledWithAgents(): Promise> { - return this.livechatBridge.doFindDepartmentsEnabledWithAgents(this.appId); - } - - public getLivechatRooms(visitor: IVisitor, departmentId?: string): Promise> { - return this.livechatBridge.doFindRooms(visitor, departmentId, this.appId); - } - - public getLivechatTotalOpenRoomsByAgentId(agentId: string): Promise { - return this.livechatBridge.doCountOpenRoomsByAgentId(agentId, this.appId); - } - - public getLivechatOpenRoomsByAgentId(agentId: string): Promise> { - return this.livechatBridge.doFindOpenRoomsByAgentId(agentId, this.appId); - } - - /** - * @deprecated This method does not adhere to the conversion practices applied - * elsewhere in the Apps-Engine and will be removed in the next major version. - * Prefer the alternative methods to fetch visitors. - */ - public getLivechatVisitors(query: object): Promise> { - return this.livechatBridge.doFindVisitors(query, this.appId); - } - - public getLivechatVisitorById(id: string): Promise { - return this.livechatBridge.doFindVisitorById(id, this.appId); - } - - public getLivechatVisitorByEmail(email: string): Promise { - return this.livechatBridge.doFindVisitorByEmail(email, this.appId); - } - - public getLivechatVisitorByToken(token: string): Promise { - return this.livechatBridge.doFindVisitorByToken(token, this.appId); - } - - public getLivechatVisitorByPhoneNumber(phoneNumber: string): Promise { - return this.livechatBridge.doFindVisitorByPhoneNumber(phoneNumber, this.appId); - } - - public getLivechatDepartmentByIdOrName(value: string): Promise { - return this.livechatBridge.doFindDepartmentByIdOrName(value, this.appId); - } - - public _fetchLivechatRoomMessages(roomId: string): Promise> { - return this.livechatBridge.do_fetchLivechatRoomMessages(this.appId, roomId); - } -} diff --git a/packages/apps/src/server/accessors/LivechatUpdater.ts b/packages/apps/src/server/accessors/LivechatUpdater.ts deleted file mode 100644 index cc222bdc5a10b..0000000000000 --- a/packages/apps/src/server/accessors/LivechatUpdater.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { ILivechatUpdater } from '@rocket.chat/apps-engine/definition/accessors'; -import type { - ILivechatRoom, - ILivechatTransferData, - IVisitor, - IVisitorExternalIdentifier, -} from '@rocket.chat/apps-engine/definition/livechat'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -import type { AppBridges } from '../bridges'; - -export class LivechatUpdater implements ILivechatUpdater { - constructor( - private readonly bridges: AppBridges, - private readonly appId: string, - ) {} - - public transferVisitor(visitor: IVisitor, transferData: ILivechatTransferData): Promise { - return this.bridges.getLivechatBridge().doTransferVisitor(visitor, transferData, this.appId); - } - - public closeRoom(room: ILivechatRoom, comment: string, closer?: IUser): Promise { - return this.bridges.getLivechatBridge().doCloseRoom(room, comment, closer, this.appId); - } - - public setCustomFields(token: IVisitor['token'], key: string, value: string, overwrite: boolean): Promise { - return this.bridges - .getLivechatBridge() - .doSetCustomFields({ token, key, value, overwrite }, this.appId) - .then((result) => result > 0); - } - - public updateVisitorExternalId(visitorId: string, externalId: Omit): Promise { - return this.bridges.getLivechatBridge().doUpdateVisitorExternalId(visitorId, externalId, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/MessageBuilder.ts b/packages/apps/src/server/accessors/MessageBuilder.ts deleted file mode 100644 index 9b6aaf3c1e0c6..0000000000000 --- a/packages/apps/src/server/accessors/MessageBuilder.ts +++ /dev/null @@ -1,225 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion -- the builder works under the assumption that "gets" would only happen after the corresponding "sets" */ - -import type { IMessageBuilder } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IMessage, IMessageAttachment } from '@rocket.chat/apps-engine/definition/messages'; -import { RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata'; -import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; -import type { IBlock } from '@rocket.chat/apps-engine/definition/uikit'; -import { BlockBuilder } from '@rocket.chat/apps-engine/definition/uikit'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; -import type { LayoutBlock } from '@rocket.chat/ui-kit'; - -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; - } - - public setUpdateData(data: IMessage, editor: IUser): IMessageBuilder { - this.msg = data; - this.msg.editor = editor; - this.msg.editedAt = new Date(); - - return this; - } - - public setThreadId(threadId: string): IMessageBuilder { - this.msg.threadId = threadId; - - return this; - } - - public getThreadId(): string { - return this.msg.threadId!; - } - - public setRoom(room: IRoom): IMessageBuilder { - this.msg.room = room; - return this; - } - - public getRoom(): IRoom { - return this.msg.room!; - } - - public setSender(sender: IUser): IMessageBuilder { - this.msg.sender = sender; - return this; - } - - public getSender(): IUser { - return this.msg.sender!; - } - - public setText(text: string): IMessageBuilder { - this.msg.text = text; - return this; - } - - public getText(): string { - return this.msg.text!; - } - - public setEmojiAvatar(emoji: string): IMessageBuilder { - this.msg.emoji = emoji; - return this; - } - - public getEmojiAvatar(): string { - return this.msg.emoji!; - } - - public setAvatarUrl(avatarUrl: string): IMessageBuilder { - this.msg.avatarUrl = avatarUrl; - return this; - } - - public getAvatarUrl(): string { - return this.msg.avatarUrl!; - } - - public setUsernameAlias(alias: string): IMessageBuilder { - this.msg.alias = alias; - return this; - } - - 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; - } - - public setAttachments(attachments: Array): IMessageBuilder { - this.msg.attachments = attachments; - return this; - } - - public getAttachments(): Array { - 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; - } - - 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; - } - - public setEditor(user: IUser): IMessageBuilder { - this.msg.editor = user; - return this; - } - - public getEditor(): IUser { - return this.msg.editor!; - } - - public setGroupable(groupable: boolean): IMessageBuilder { - this.msg.groupable = groupable; - return this; - } - - public getGroupable(): boolean { - return this.msg.groupable!; - } - - public setParseUrls(parseUrls: boolean): IMessageBuilder { - this.msg.parseUrls = parseUrls; - return this; - } - - public getParseUrls() { - 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) { - 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; - } - - public setBlocks(blocks: BlockBuilder | Array) { - if (blocks instanceof BlockBuilder) { - this.msg.blocks = blocks.getBlocks(); - } else { - this.msg.blocks = blocks; - } - - return this; - } - - public getBlocks(): Array { - return this.msg.blocks!; - } - - public addCustomField(key: string, value: any): 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; - } -} diff --git a/packages/apps/src/server/accessors/MessageExtender.ts b/packages/apps/src/server/accessors/MessageExtender.ts deleted file mode 100644 index fee05802d0856..0000000000000 --- a/packages/apps/src/server/accessors/MessageExtender.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { IMessageExtender } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IMessage, IMessageAttachment } from '@rocket.chat/apps-engine/definition/messages'; -import { RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata'; - -import { Utilities } from '../misc/Utilities'; - -export class MessageExtender implements IMessageExtender { - public readonly kind: RocketChatAssociationModel.MESSAGE; - - constructor(private msg: IMessage) { - this.kind = RocketChatAssociationModel.MESSAGE; - - if (!Array.isArray(msg.attachments)) { - this.msg.attachments = []; - } - } - - public addCustomField(key: string, value: any): IMessageExtender { - 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; - } - - public addAttachment(attachment: IMessageAttachment): IMessageExtender { - this.msg.attachments.push(attachment); - - return this; - } - - public addAttachments(attachments: Array): IMessageExtender { - this.msg.attachments = this.msg.attachments.concat(attachments); - - return this; - } - - public getMessage(): IMessage { - return Utilities.deepClone(this.msg); - } -} diff --git a/packages/apps/src/server/accessors/MessageRead.ts b/packages/apps/src/server/accessors/MessageRead.ts deleted file mode 100644 index 914529d07f000..0000000000000 --- a/packages/apps/src/server/accessors/MessageRead.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { IMessageRead } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; -import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -import type { MessageBridge } from '../bridges/MessageBridge'; - -export class MessageRead implements IMessageRead { - constructor( - private messageBridge: MessageBridge, - private appId: string, - ) {} - - public getById(id: string): Promise { - return this.messageBridge.doGetById(id, this.appId); - } - - public async getSenderUser(messageId: string): Promise { - const msg = await this.messageBridge.doGetById(messageId, this.appId); - - if (!msg) { - return undefined; - } - - return msg.sender; - } - - public async getRoom(messageId: string): Promise { - const msg = await this.messageBridge.doGetById(messageId, this.appId); - - if (!msg) { - return undefined; - } - - return msg.room; - } -} diff --git a/packages/apps/src/server/accessors/MessageUpdater.ts b/packages/apps/src/server/accessors/MessageUpdater.ts deleted file mode 100644 index 33728a8b833e6..0000000000000 --- a/packages/apps/src/server/accessors/MessageUpdater.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { IMessageUpdater } from '@rocket.chat/apps-engine/definition/accessors/IMessageUpdater'; -import type { Reaction } from '@rocket.chat/apps-engine/definition/messages'; - -import type { AppBridges } from '../bridges'; - -export class MessageUpdater implements IMessageUpdater { - constructor( - private readonly bridges: AppBridges, - private readonly appId: string, - ) {} - - public async addReaction(messageId: string, userId: string, reaction: Reaction): Promise { - return this.bridges.getMessageBridge().doAddReaction(messageId, userId, reaction, this.appId); - } - - public async removeReaction(messageId: string, userId: string, reaction: Reaction): Promise { - return this.bridges.getMessageBridge().doRemoveReaction(messageId, userId, reaction, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/ModerationModify.ts b/packages/apps/src/server/accessors/ModerationModify.ts deleted file mode 100644 index e74772efbac22..0000000000000 --- a/packages/apps/src/server/accessors/ModerationModify.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { IModerationModify } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -import type { ModerationBridge } from '../bridges'; - -export class ModerationModify implements IModerationModify { - constructor( - private moderationBridge: ModerationBridge, - _appId: string, - ) {} - - public report(messageId: string, description: string, userId: string, appId: string): Promise { - return this.moderationBridge.doReport(messageId, description, userId, appId); - } - - public dismissReportsByMessageId(messageId: IMessage['id'], reason: string, action: string, appId: string): Promise { - return this.moderationBridge.doDismissReportsByMessageId(messageId, reason, action, appId); - } - - public dismissReportsByUserId(userId: IUser['id'], reason: string, action: string, appId: string): Promise { - return this.moderationBridge.doDismissReportsByUserId(userId, reason, action, appId); - } -} diff --git a/packages/apps/src/server/accessors/Modify.ts b/packages/apps/src/server/accessors/Modify.ts deleted file mode 100644 index e982403beed47..0000000000000 --- a/packages/apps/src/server/accessors/Modify.ts +++ /dev/null @@ -1,93 +0,0 @@ -import type { - IModify, - IModifyCreator, - IModifyDeleter, - IModifyExtender, - IModifyUpdater, - INotifier, - ISchedulerModify, - IUIController, -} from '@rocket.chat/apps-engine/definition/accessors'; -import type { IOAuthAppsModify } from '@rocket.chat/apps-engine/definition/accessors/IOAuthAppsModify'; - -import type { AppBridges } from '../bridges'; -import { ModerationModify } from './ModerationModify'; -import { ModifyCreator } from './ModifyCreator'; -import { ModifyDeleter } from './ModifyDeleter'; -import { ModifyExtender } from './ModifyExtender'; -import { ModifyUpdater } from './ModifyUpdater'; -import { Notifier } from './Notifier'; -import { OAuthAppsModify } from './OAuthAppsModify'; -import { SchedulerModify } from './SchedulerModify'; -import { UIController } from './UIController'; - -export class Modify implements IModify { - private creator: IModifyCreator; - - private deleter: IModifyDeleter; - - private updater: IModifyUpdater; - - private extender: IModifyExtender; - - private notifier: INotifier; - - private uiController: IUIController; - - private scheduler: ISchedulerModify; - - private oauthApps: IOAuthAppsModify; - - private moderation: ModerationModify; - - constructor( - private readonly bridges: AppBridges, - private readonly appId: string, - ) { - this.creator = new ModifyCreator(this.bridges, this.appId); - this.deleter = new ModifyDeleter(this.bridges, this.appId); - this.updater = new ModifyUpdater(this.bridges, this.appId); - this.extender = new ModifyExtender(this.bridges, this.appId); - this.notifier = new Notifier(this.bridges.getUserBridge(), this.bridges.getMessageBridge(), this.appId); - this.uiController = new UIController(this.appId, this.bridges); - this.scheduler = new SchedulerModify(this.bridges.getSchedulerBridge(), this.appId); - this.oauthApps = new OAuthAppsModify(this.bridges.getOAuthAppsBridge(), this.appId); - this.moderation = new ModerationModify(this.bridges.getModerationBridge(), this.appId); - } - - public getCreator(): IModifyCreator { - return this.creator; - } - - public getDeleter(): IModifyDeleter { - return this.deleter; - } - - public getUpdater(): IModifyUpdater { - return this.updater; - } - - public getExtender(): IModifyExtender { - return this.extender; - } - - public getNotifier(): INotifier { - return this.notifier; - } - - public getUiController(): IUIController { - return this.uiController; - } - - public getScheduler(): ISchedulerModify { - return this.scheduler; - } - - public getOAuthAppsModifier() { - return this.oauthApps; - } - - public getModerationModifier() { - return this.moderation; - } -} diff --git a/packages/apps/src/server/accessors/ModifyCreator.ts b/packages/apps/src/server/accessors/ModifyCreator.ts deleted file mode 100644 index 6971680ed4198..0000000000000 --- a/packages/apps/src/server/accessors/ModifyCreator.ts +++ /dev/null @@ -1,275 +0,0 @@ -import type { - IDiscussionBuilder, - ILivechatCreator, - ILivechatMessageBuilder, - IMessageBuilder, - IModifyCreator, - IRoomBuilder, - IUploadCreator, - IUserBuilder, - IVideoConferenceBuilder, -} from '@rocket.chat/apps-engine/definition/accessors'; -import type { IContactCreator } from '@rocket.chat/apps-engine/definition/accessors/IContactCreator'; -import type { IEmailCreator } from '@rocket.chat/apps-engine/definition/accessors/IEmailCreator'; -import type { ILivechatMessage } from '@rocket.chat/apps-engine/definition/livechat/ILivechatMessage'; -import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; -import { RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata'; -import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; -import { RoomType } from '@rocket.chat/apps-engine/definition/rooms'; -import { BlockBuilder } from '@rocket.chat/apps-engine/definition/uikit'; -import type { IBotUser } from '@rocket.chat/apps-engine/definition/users/IBotUser'; -import { UserType } from '@rocket.chat/apps-engine/definition/users/UserType'; -import type { AppVideoConference } from '@rocket.chat/apps-engine/definition/videoConferences'; - -import { ContactCreator } from './ContactCreator'; -import { DiscussionBuilder } from './DiscussionBuilder'; -import { EmailCreator } from './EmailCreator'; -import { LivechatCreator } from './LivechatCreator'; -import { LivechatMessageBuilder } from './LivechatMessageBuilder'; -import { MessageBuilder } from './MessageBuilder'; -import { RoomBuilder } from './RoomBuilder'; -import { UploadCreator } from './UploadCreator'; -import { UserBuilder } from './UserBuilder'; -import { VideoConferenceBuilder } from './VideoConferenceBuilder'; -import type { AppBridges } from '../bridges'; -import { UIHelper } from '../misc/UIHelper'; - -export class ModifyCreator implements IModifyCreator { - private livechatCreator: LivechatCreator; - - private uploadCreator: UploadCreator; - - private emailCreator: EmailCreator; - - private contactCreator: ContactCreator; - - constructor( - private readonly bridges: AppBridges, - private readonly appId: string, - ) { - this.livechatCreator = new LivechatCreator(bridges, appId); - this.uploadCreator = new UploadCreator(bridges, appId); - this.emailCreator = new EmailCreator(bridges, appId); - this.contactCreator = new ContactCreator(bridges, appId); - } - - public getLivechatCreator(): ILivechatCreator { - return this.livechatCreator; - } - - public getUploadCreator(): IUploadCreator { - return this.uploadCreator; - } - - public getEmailCreator(): IEmailCreator { - return this.emailCreator; - } - - public getContactCreator(): IContactCreator { - return this.contactCreator; - } - - /** - * @deprecated please prefer the rocket.chat/ui-kit components - */ - public getBlockBuilder(): BlockBuilder { - return new BlockBuilder(this.appId); - } - - public startMessage(data?: IMessage): IMessageBuilder { - if (data) { - delete data.id; - } - - return new MessageBuilder(data); - } - - public startLivechatMessage(data?: ILivechatMessage): ILivechatMessageBuilder { - if (data) { - delete data.id; - } - - return new LivechatMessageBuilder(data); - } - - public startRoom(data?: IRoom): IRoomBuilder { - if (data) { - delete data.id; - } - - return new RoomBuilder(data); - } - - public startDiscussion(data?: Partial): IDiscussionBuilder { - if (data) { - delete data.id; - } - - return new DiscussionBuilder(data); - } - - public startVideoConference(data?: Partial): IVideoConferenceBuilder { - return new VideoConferenceBuilder(data); - } - - public startBotUser(data?: Partial): IUserBuilder { - if (data) { - delete data.id; - - const { roles } = data; - - if (roles?.length) { - const hasRole = roles - .map((role) => role.toLocaleLowerCase()) - .some((role) => 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 { - switch (builder.kind) { - case RocketChatAssociationModel.MESSAGE: - return this._finishMessage(builder); - case RocketChatAssociationModel.LIVECHAT_MESSAGE: - return this._finishLivechatMessage(builder); - case RocketChatAssociationModel.ROOM: - return this._finishRoom(builder); - case RocketChatAssociationModel.DISCUSSION: - return this._finishDiscussion(builder as IDiscussionBuilder); - case RocketChatAssociationModel.VIDEO_CONFERENCE: - return this._finishVideoConference(builder); - case RocketChatAssociationModel.USER: - return this._finishUser(builder); - default: - throw new Error('Invalid builder passed to the ModifyCreator.finish function.'); - } - } - - private async _finishMessage(builder: IMessageBuilder): Promise { - const result = builder.getMessage(); - delete result.id; - - if (!result.sender?.id) { - const appUser = await this.bridges.getUserBridge().doGetAppUser(this.appId); - - if (!appUser) { - throw new Error('Invalid sender assigned to the message.'); - } - - result.sender = appUser; - } - - if (result.blocks?.length) { - result.blocks = UIHelper.assignIds(result.blocks, this.appId); - } - - return this.bridges.getMessageBridge().doCreate(result, this.appId); - } - - private _finishLivechatMessage(builder: ILivechatMessageBuilder): Promise { - if (builder.getSender() && !builder.getVisitor()) { - return this._finishMessage(builder.getMessageBuilder()); - } - - const result = builder.getMessage(); - delete result.id; - - if (!result.token && !result.visitor?.token) { - throw new Error('Invalid visitor sending the message'); - } - - result.token = result.visitor ? result.visitor.token : result.token; - - return this.bridges.getLivechatBridge().doCreateMessage(result, this.appId); - } - - private _finishRoom(builder: IRoomBuilder): Promise { - 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?.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?.trim()) { - throw new Error('Invalid slugifiedName assigned to the room.'); - } - } - - if (!result.displayName?.trim()) { - throw new Error('Invalid displayName assigned to the room.'); - } - } - - return this.bridges.getRoomBridge().doCreate(result, builder.getMembersToBeAddedUsernames(), this.appId); - } - - private _finishDiscussion(builder: IDiscussionBuilder): Promise { - const room = builder.getRoom(); - delete room.id; - - if (!room.creator?.id) { - throw new Error('Invalid creator assigned to the discussion.'); - } - - if (!room.slugifiedName?.trim()) { - throw new Error('Invalid slugifiedName assigned to the discussion.'); - } - - if (!room.displayName?.trim()) { - throw new Error('Invalid displayName assigned to the discussion.'); - } - - if (!room.parentRoom?.id) { - throw new Error('Invalid parentRoom assigned to the discussion.'); - } - - return this.bridges - .getRoomBridge() - .doCreateDiscussion(room, builder.getParentMessage(), builder.getReply(), builder.getMembersToBeAddedUsernames(), this.appId); - } - - private _finishVideoConference(builder: IVideoConferenceBuilder): Promise { - 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.'); - } - - return this.bridges.getVideoConferenceBridge().doCreate(videoConference, this.appId); - } - - private _finishUser(builder: IUserBuilder): Promise { - const user = builder.getUser(); - - return this.bridges.getUserBridge().doCreate(user, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/ModifyDeleter.ts b/packages/apps/src/server/accessors/ModifyDeleter.ts deleted file mode 100644 index 50c390f2d555d..0000000000000 --- a/packages/apps/src/server/accessors/ModifyDeleter.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { IModifyDeleter } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; -import type { IUser, UserType } from '@rocket.chat/apps-engine/definition/users'; - -import type { AppBridges } from '../bridges'; - -export class ModifyDeleter implements IModifyDeleter { - constructor( - private readonly bridges: AppBridges, - private readonly appId: string, - ) {} - - public async deleteRoom(roomId: string): Promise { - return this.bridges.getRoomBridge().doDelete(roomId, this.appId); - } - - public async deleteUsers(appId: Exclude, userType: UserType.APP | UserType.BOT): Promise { - return this.bridges.getUserBridge().doDeleteUsersCreatedByApp(appId, userType); - } - - public async deleteMessage(message: IMessage, user: IUser): Promise { - return this.bridges.getMessageBridge().doDelete(message, user, this.appId); - } - - /** - * Removes `usernames` from the room's member list - * - * For performance reasons, it is only possible to remove 50 users in one - * call to this method. Removing users is an expensive operation due to the - * amount of entity relationships that need to be modified. - */ - public async removeUsersFromRoom(roomId: string, usernames: Array) { - if (usernames.length > 50) { - throw new Error('A maximum of 50 members can be removed in a single call'); - } - - return this.bridges.getRoomBridge().doRemoveUsers(roomId, usernames, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/ModifyExtender.ts b/packages/apps/src/server/accessors/ModifyExtender.ts deleted file mode 100644 index 98f8dec4d0361..0000000000000 --- a/packages/apps/src/server/accessors/ModifyExtender.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { - IMessageExtender, - IModifyExtender, - IRoomExtender, - IVideoConferenceExtender, -} from '@rocket.chat/apps-engine/definition/accessors'; -import { RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -import { MessageExtender } from './MessageExtender'; -import { RoomExtender } from './RoomExtender'; -import { VideoConferenceExtender } from './VideoConferenceExtend'; -import type { AppBridges } from '../bridges/AppBridges'; - -export class ModifyExtender implements IModifyExtender { - constructor( - private readonly bridges: AppBridges, - private readonly appId: string, - ) {} - - public async extendMessage(messageId: string, updater: IUser): Promise { - const msg = await this.bridges.getMessageBridge().doGetById(messageId, this.appId); - msg.editor = updater; - msg.editedAt = new Date(); - - return new MessageExtender(msg); - } - - public async extendRoom(roomId: string, _updater: IUser): Promise { - const room = await this.bridges.getRoomBridge().doGetById(roomId, this.appId); - room.updatedAt = new Date(); - - return new RoomExtender(room); - } - - public async extendVideoConference(id: string): Promise { - const call = await this.bridges.getVideoConferenceBridge().doGetById(id, this.appId); - call._updatedAt = new Date(); - - return new VideoConferenceExtender(call); - } - - public finish(extender: IMessageExtender | IRoomExtender | IVideoConferenceExtender): Promise { - switch (extender.kind) { - case RocketChatAssociationModel.MESSAGE: - return this.bridges.getMessageBridge().doUpdate(extender.getMessage(), this.appId); - case RocketChatAssociationModel.ROOM: - return this.bridges.getRoomBridge().doUpdate(extender.getRoom(), extender.getUsernamesOfMembersBeingAdded(), this.appId); - case RocketChatAssociationModel.VIDEO_CONFERENCE: - return this.bridges.getVideoConferenceBridge().doUpdate(extender.getVideoConference(), this.appId); - default: - throw new Error('Invalid extender passed to the ModifyExtender.finish function.'); - } - } -} diff --git a/packages/apps/src/server/accessors/ModifyUpdater.ts b/packages/apps/src/server/accessors/ModifyUpdater.ts deleted file mode 100644 index 1da37395ef696..0000000000000 --- a/packages/apps/src/server/accessors/ModifyUpdater.ts +++ /dev/null @@ -1,118 +0,0 @@ -import type { - ILivechatUpdater, - IMessageBuilder, - IMessageUpdater, - IModifyUpdater, - IRoomBuilder, -} from '@rocket.chat/apps-engine/definition/accessors'; -import type { IUserUpdater } from '@rocket.chat/apps-engine/definition/accessors/IUserUpdater'; -import { RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata'; -import { RoomType } from '@rocket.chat/apps-engine/definition/rooms'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -import { LivechatUpdater } from './LivechatUpdater'; -import { MessageBuilder } from './MessageBuilder'; -import { MessageUpdater } from './MessageUpdater'; -import { RoomBuilder } from './RoomBuilder'; -import { UserUpdater } from './UserUpdater'; -import type { AppBridges } from '../bridges'; -import { UIHelper } from '../misc/UIHelper'; - -export class ModifyUpdater implements IModifyUpdater { - private livechatUpdater: ILivechatUpdater; - - private userUpdater: IUserUpdater; - - private messageUpdater: IMessageUpdater; - - constructor( - private readonly bridges: AppBridges, - private readonly appId: string, - ) { - this.livechatUpdater = new LivechatUpdater(this.bridges, this.appId); - this.userUpdater = new UserUpdater(this.bridges, this.appId); - this.messageUpdater = new MessageUpdater(this.bridges, this.appId); - } - - public getLivechatUpdater(): ILivechatUpdater { - return this.livechatUpdater; - } - - public getUserUpdater(): IUserUpdater { - return this.userUpdater; - } - - public getMessageUpdater(): IMessageUpdater { - return this.messageUpdater; - } - - public async message(messageId: string, _updater: IUser): Promise { - const msg = await this.bridges.getMessageBridge().doGetById(messageId, this.appId); - - return new MessageBuilder(msg); - } - - public async room(roomId: string, _updater: IUser): Promise { - const room = await this.bridges.getRoomBridge().doGetById(roomId, this.appId); - - return new RoomBuilder(room); - } - - public finish(builder: IMessageBuilder | IRoomBuilder): Promise { - switch (builder.kind) { - case RocketChatAssociationModel.MESSAGE: - return this._finishMessage(builder); - case RocketChatAssociationModel.ROOM: - return this._finishRoom(builder); - default: - throw new Error('Invalid builder passed to the ModifyUpdater.finish function.'); - } - } - - private _finishMessage(builder: IMessageBuilder): Promise { - const result = builder.getMessage(); - - if (!result.id) { - throw new Error("Invalid message, can't update a message without an id."); - } - - if (!result.sender?.id) { - throw new Error('Invalid sender assigned to the message.'); - } - - if (result.blocks?.length) { - result.blocks = UIHelper.assignIds(result.blocks, this.appId); - // result.blocks = this._assignIds(result.blocks); - } - - return this.bridges.getMessageBridge().doUpdate(result, this.appId); - } - - private _finishRoom(builder: IRoomBuilder): Promise { - const result = builder.getRoom(); - - if (!result.id) { - throw new Error('Invalid room, can not update a room without an id.'); - } - - if (!result.type) { - throw new Error('Invalid type assigned to the room.'); - } - - if (result.type !== RoomType.LIVE_CHAT) { - if (!result.creator?.id) { - throw new Error('Invalid creator assigned to the room.'); - } - - if (!result.slugifiedName?.trim()) { - throw new Error('Invalid slugifiedName assigned to the room.'); - } - } - - if (!result.displayName?.trim()) { - throw new Error('Invalid displayName assigned to the room.'); - } - - return this.bridges.getRoomBridge().doUpdate(result, builder.getMembersToBeAddedUsernames(), this.appId); - } -} diff --git a/packages/apps/src/server/accessors/Notifier.ts b/packages/apps/src/server/accessors/Notifier.ts deleted file mode 100644 index ba5b46b841717..0000000000000 --- a/packages/apps/src/server/accessors/Notifier.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { IMessageBuilder, INotifier } from '@rocket.chat/apps-engine/definition/accessors'; -import type { ITypingOptions } from '@rocket.chat/apps-engine/definition/accessors/INotifier'; -import { TypingScope } from '@rocket.chat/apps-engine/definition/accessors/INotifier'; -import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; -import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -import type { MessageBridge, UserBridge } from '../bridges'; -import { MessageBuilder } from './MessageBuilder'; - -export class Notifier implements INotifier { - constructor( - private readonly userBridge: UserBridge, - private readonly msgBridge: MessageBridge, - private readonly appId: string, - ) {} - - public async notifyUser(user: IUser, message: IMessage): Promise { - if (!message.sender?.id) { - const appUser = (await this.userBridge.doGetAppUser(this.appId)) as IUser; - - message.sender = appUser; - } - - await this.msgBridge.doNotifyUser(user, message, this.appId); - } - - public async notifyRoom(room: IRoom, message: IMessage): Promise { - if (!message.sender?.id) { - const appUser = (await this.userBridge.doGetAppUser(this.appId)) as IUser; - - message.sender = appUser; - } - - await this.msgBridge.doNotifyRoom(room, message, this.appId); - } - - public async typing(options: ITypingOptions): Promise<() => Promise> { - options.scope = options.scope || TypingScope.Room; - - if (!options.username) { - const appUser = await this.userBridge.doGetAppUser(this.appId); - options.username = appUser?.name || ''; - } - - void this.msgBridge.doTyping({ ...options, isTyping: true }, this.appId); - - return () => this.msgBridge.doTyping({ ...options, isTyping: false }, this.appId); - } - - public getMessageBuilder(): IMessageBuilder { - return new MessageBuilder(); - } -} diff --git a/packages/apps/src/server/accessors/OAuthAppsModify.ts b/packages/apps/src/server/accessors/OAuthAppsModify.ts deleted file mode 100644 index 2946504f5b08e..0000000000000 --- a/packages/apps/src/server/accessors/OAuthAppsModify.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { IOAuthAppParams } from '@rocket.chat/apps-engine/definition/accessors/IOAuthApp'; -import type { IOAuthAppsModify } from '@rocket.chat/apps-engine/definition/accessors/IOAuthAppsModify'; - -import type { OAuthAppsBridge } from '../bridges/OAuthAppsBridge'; - -export class OAuthAppsModify implements IOAuthAppsModify { - constructor( - private readonly oauthAppsBridge: OAuthAppsBridge, - private readonly appId: string, - ) {} - - public async createOAuthApp(oAuthApp: IOAuthAppParams): Promise { - return this.oauthAppsBridge.doCreate(oAuthApp, this.appId); - } - - public async updateOAuthApp(oAuthApp: IOAuthAppParams, id: string): Promise { - return this.oauthAppsBridge.doUpdate(oAuthApp, id, this.appId); - } - - public async deleteOAuthApp(id: string): Promise { - return this.oauthAppsBridge.doDelete(id, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/OAuthAppsReader.ts b/packages/apps/src/server/accessors/OAuthAppsReader.ts deleted file mode 100644 index 6de492e00a64e..0000000000000 --- a/packages/apps/src/server/accessors/OAuthAppsReader.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { IOAuthApp } from '@rocket.chat/apps-engine/definition/accessors/IOAuthApp'; -import type { IOAuthAppsReader } from '@rocket.chat/apps-engine/definition/accessors/IOAuthAppsReader'; - -import type { OAuthAppsBridge } from '../bridges/OAuthAppsBridge'; - -export class OAuthAppsReader implements IOAuthAppsReader { - constructor( - private readonly oauthAppsBridge: OAuthAppsBridge, - private readonly appId: string, - ) {} - - public async getOAuthAppById(id: string): Promise { - return this.oauthAppsBridge.doGetByid(id, this.appId); - } - - public async getOAuthAppByName(name: string): Promise> { - return this.oauthAppsBridge.doGetByName(name, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/OutboundCommunicationProviderExtend.ts b/packages/apps/src/server/accessors/OutboundCommunicationProviderExtend.ts deleted file mode 100644 index d1ba5b7fdc514..0000000000000 --- a/packages/apps/src/server/accessors/OutboundCommunicationProviderExtend.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { IOutboundCommunicationProviderExtend } from '@rocket.chat/apps-engine/definition/accessors/IOutboundCommunicationProviderExtend'; -import type { - IOutboundPhoneMessageProvider, - IOutboundEmailMessageProvider, -} from '@rocket.chat/apps-engine/definition/outboundCommunication'; - -import type { AppOutboundCommunicationProviderManager } from '../managers/AppOutboundCommunicationProviderManager'; - -export class OutboundMessageProviderExtend implements IOutboundCommunicationProviderExtend { - constructor( - private readonly manager: AppOutboundCommunicationProviderManager, - private readonly appId: string, - ) {} - - public registerPhoneProvider(provider: IOutboundPhoneMessageProvider): Promise { - return Promise.resolve(this.manager.addProvider(this.appId, provider)); - } - - public registerEmailProvider(provider: IOutboundEmailMessageProvider): Promise { - return Promise.resolve(this.manager.addProvider(this.appId, provider)); - } -} diff --git a/packages/apps/src/server/accessors/Persistence.ts b/packages/apps/src/server/accessors/Persistence.ts deleted file mode 100644 index 6cff70718069e..0000000000000 --- a/packages/apps/src/server/accessors/Persistence.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { IPersistence } from '@rocket.chat/apps-engine/definition/accessors'; -import type { RocketChatAssociationRecord } from '@rocket.chat/apps-engine/definition/metadata'; - -import type { PersistenceBridge } from '../bridges/PersistenceBridge'; - -export class Persistence implements IPersistence { - constructor( - private persistBridge: PersistenceBridge, - private appId: string, - ) {} - - public create(data: object): Promise { - return this.persistBridge.doCreate(data, this.appId); - } - - public createWithAssociation(data: object, association: RocketChatAssociationRecord): Promise { - return this.persistBridge.doCreateWithAssociations(data, new Array(association), this.appId); - } - - public createWithAssociations(data: object, associations: Array): Promise { - return this.persistBridge.doCreateWithAssociations(data, associations, this.appId); - } - - public update(id: string, data: object, upsert = false): Promise { - return this.persistBridge.doUpdate(id, data, upsert, this.appId); - } - - public updateByAssociation(association: RocketChatAssociationRecord, data: object, upsert = false): Promise { - return this.persistBridge.doUpdateByAssociations(new Array(association), data, upsert, this.appId); - } - - public updateByAssociations(associations: Array, data: object, upsert = false): Promise { - return this.persistBridge.doUpdateByAssociations(associations, data, upsert, this.appId); - } - - public remove(id: string): Promise { - return this.persistBridge.doRemove(id, this.appId); - } - - public removeByAssociation(association: RocketChatAssociationRecord): Promise> { - return this.persistBridge.doRemoveByAssociations(new Array(association), this.appId); - } - - public removeByAssociations(associations: Array): Promise> { - return this.persistBridge.doRemoveByAssociations(associations, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/PersistenceRead.ts b/packages/apps/src/server/accessors/PersistenceRead.ts deleted file mode 100644 index dc8fcddc935c4..0000000000000 --- a/packages/apps/src/server/accessors/PersistenceRead.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { IPersistenceRead } from '@rocket.chat/apps-engine/definition/accessors'; -import type { RocketChatAssociationRecord } from '@rocket.chat/apps-engine/definition/metadata'; - -import type { PersistenceBridge } from '../bridges'; - -export class PersistenceRead implements IPersistenceRead { - constructor( - private persistBridge: PersistenceBridge, - private appId: string, - ) {} - - public read(id: string): Promise { - return this.persistBridge.doReadById(id, this.appId); - } - - public readByAssociation(association: RocketChatAssociationRecord): Promise> { - return this.persistBridge.doReadByAssociations(new Array(association), this.appId); - } - - public readByAssociations(associations: Array): Promise> { - return this.persistBridge.doReadByAssociations(associations, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/Reader.ts b/packages/apps/src/server/accessors/Reader.ts deleted file mode 100644 index 2f73452b1af85..0000000000000 --- a/packages/apps/src/server/accessors/Reader.ts +++ /dev/null @@ -1,98 +0,0 @@ -import type { - ICloudWorkspaceRead, - IEnvironmentRead, - IExperimentalRead, - ILivechatRead, - IMessageRead, - INotifier, - IPersistenceRead, - IRead, - IRoomRead, - IUploadRead, - IUserRead, - IVideoConferenceRead, -} from '@rocket.chat/apps-engine/definition/accessors'; -import type { IContactRead } from '@rocket.chat/apps-engine/definition/accessors/IContactRead'; -import type { IOAuthAppsReader } from '@rocket.chat/apps-engine/definition/accessors/IOAuthAppsReader'; -import type { IRoleRead } from '@rocket.chat/apps-engine/definition/accessors/IRoleRead'; -import type { IThreadRead } from '@rocket.chat/apps-engine/definition/accessors/IThreadRead'; - -export class Reader implements IRead { - constructor( - private env: IEnvironmentRead, - private message: IMessageRead, - private persist: IPersistenceRead, - private room: IRoomRead, - private user: IUserRead, - private noti: INotifier, - private livechat: ILivechatRead, - private upload: IUploadRead, - private cloud: ICloudWorkspaceRead, - private videoConf: IVideoConferenceRead, - private contactRead: IContactRead, - private oauthApps: IOAuthAppsReader, - private thread: IThreadRead, - private role: IRoleRead, - private experimental: IExperimentalRead, - ) {} - - public getEnvironmentReader(): IEnvironmentRead { - return this.env; - } - - public getThreadReader(): IThreadRead { - return this.thread; - } - - public getMessageReader(): IMessageRead { - return this.message; - } - - public getPersistenceReader(): IPersistenceRead { - return this.persist; - } - - public getRoomReader(): IRoomRead { - return this.room; - } - - public getUserReader(): IUserRead { - return this.user; - } - - public getNotifier(): INotifier { - return this.noti; - } - - public getLivechatReader(): ILivechatRead { - return this.livechat; - } - - public getUploadReader(): IUploadRead { - return this.upload; - } - - public getCloudWorkspaceReader(): ICloudWorkspaceRead { - return this.cloud; - } - - public getVideoConferenceReader(): IVideoConferenceRead { - return this.videoConf; - } - - public getOAuthAppsReader(): IOAuthAppsReader { - return this.oauthApps; - } - - public getRoleReader(): IRoleRead { - return this.role; - } - - public getContactReader(): IContactRead { - return this.contactRead; - } - - public getExperimentalReader(): IExperimentalRead { - return this.experimental; - } -} diff --git a/packages/apps/src/server/accessors/RoleRead.ts b/packages/apps/src/server/accessors/RoleRead.ts deleted file mode 100644 index a6ad18742aea5..0000000000000 --- a/packages/apps/src/server/accessors/RoleRead.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { IRoleRead } from '@rocket.chat/apps-engine/definition/accessors/IRoleRead'; -import type { IRole } from '@rocket.chat/apps-engine/definition/roles'; - -import type { RoleBridge } from '../bridges'; - -export class RoleRead implements IRoleRead { - constructor( - private roleBridge: RoleBridge, - private appId: string, - ) {} - - public getOneByIdOrName(idOrName: string): Promise { - return this.roleBridge.doGetOneByIdOrName(idOrName, this.appId); - } - - public getCustomRoles(): Promise> { - return this.roleBridge.doGetCustomRoles(this.appId); - } -} diff --git a/packages/apps/src/server/accessors/RoomBuilder.ts b/packages/apps/src/server/accessors/RoomBuilder.ts deleted file mode 100644 index aa1e4c31d43b7..0000000000000 --- a/packages/apps/src/server/accessors/RoomBuilder.ts +++ /dev/null @@ -1,155 +0,0 @@ -import type { IRoomBuilder } from '@rocket.chat/apps-engine/definition/accessors'; -import { RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata'; -import type { IRoom, RoomType } from '@rocket.chat/apps-engine/definition/rooms'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -export class RoomBuilder implements IRoomBuilder { - public kind: RocketChatAssociationModel.ROOM | RocketChatAssociationModel.DISCUSSION; - - protected room: IRoom; - - private members: Array; - - constructor(data?: Partial) { - this.kind = RocketChatAssociationModel.ROOM; - this.room = (data || { customFields: {} }) as IRoom; - this.members = []; - } - - public setData(data: Partial): 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): IRoomBuilder { - this.setMembersToBeAddedByUsernames(usernames); - return this; - } - - /** - * @deprecated - */ - public getUsernames(): Array { - 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): IRoomBuilder { - this.members = usernames; - return this; - } - - public getMembersToBeAddedUsernames(): Array { - 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 { - return this.room.userIds; - } - - public getRoom(): IRoom { - return this.room; - } -} diff --git a/packages/apps/src/server/accessors/RoomExtender.ts b/packages/apps/src/server/accessors/RoomExtender.ts deleted file mode 100644 index 05722126d6791..0000000000000 --- a/packages/apps/src/server/accessors/RoomExtender.ts +++ /dev/null @@ -1,57 +0,0 @@ -import type { IRoomExtender } from '@rocket.chat/apps-engine/definition/accessors'; -import { RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata'; -import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -import { Utilities } from '../misc/Utilities'; - -export class RoomExtender implements IRoomExtender { - public kind: RocketChatAssociationModel.ROOM; - - private members: Array; - - constructor(private room: IRoom) { - this.kind = RocketChatAssociationModel.ROOM; - this.members = []; - } - - public addCustomField(key: string, value: any): IRoomExtender { - if (!this.room.customFields) { - this.room.customFields = {}; - } - - if (this.room.customFields[key]) { - throw new Error(`The room 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.room.customFields[key] = value; - - return this; - } - - public addMember(user: IUser): IRoomExtender { - if (this.members.find((u) => u.username === user.username)) { - throw new Error('The user is already in the room.'); - } - - this.members.push(user); - - return this; - } - - public getMembersBeingAdded(): Array { - return this.members; - } - - public getUsernamesOfMembersBeingAdded(): Array { - return this.members.map((u) => u.username); - } - - public getRoom(): IRoom { - return Utilities.deepClone(this.room); - } -} diff --git a/packages/apps/src/server/accessors/RoomRead.ts b/packages/apps/src/server/accessors/RoomRead.ts deleted file mode 100644 index 99bf71e51e913..0000000000000 --- a/packages/apps/src/server/accessors/RoomRead.ts +++ /dev/null @@ -1,112 +0,0 @@ -import type { IRoomRead } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IMessageRaw } from '@rocket.chat/apps-engine/definition/messages'; -import type { IRoom, IRoomRaw } from '@rocket.chat/apps-engine/definition/rooms'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -import type { RoomBridge } from '../bridges'; -import { type GetMessagesOptions, type GetRoomsFilters, type GetRoomsOptions, GetMessagesSortableFields } from '../bridges/RoomBridge'; - -export class RoomRead implements IRoomRead { - constructor( - private roomBridge: RoomBridge, - private appId: string, - ) {} - - public getById(id: string): Promise { - return this.roomBridge.doGetById(id, this.appId); - } - - public getCreatorUserById(id: string): Promise { - return this.roomBridge.doGetCreatorById(id, this.appId); - } - - public getByName(name: string): Promise { - return this.roomBridge.doGetByName(name, this.appId); - } - - public getCreatorUserByName(name: string): Promise { - return this.roomBridge.doGetCreatorByName(name, this.appId); - } - - public getMessages(roomId: string, options: Partial = {}): Promise { - if (typeof options.limit !== 'undefined' && (!Number.isFinite(options.limit) || options.limit > 100)) { - throw new Error(`Invalid limit provided. Expected number <= 100, got ${options.limit}`); - } - - options.limit ??= 100; - options.showThreadMessages ??= true; - - if (options.sort) { - this.validateSort(options.sort); - } - - return this.roomBridge.doGetMessages(roomId, options as GetMessagesOptions, this.appId); - } - - public getMembers(roomId: string): Promise> { - return this.roomBridge.doGetMembers(roomId, this.appId); - } - - public getAllRooms(filters: GetRoomsFilters = {}, { limit = 100, skip = 0 }: GetRoomsOptions = {}): Promise | undefined> { - if (!Number.isFinite(limit) || limit <= 0 || limit > 100) { - throw new Error(`Invalid limit provided. Expected number between 1 and 100, got ${limit}`); - } - - if (!Number.isFinite(skip) || skip < 0) { - throw new Error(`Invalid skip provided. Expected number >= 0, got ${skip}`); - } - - return this.roomBridge.doGetAllRooms(filters, { limit, skip }, this.appId); - } - - public getDirectByUsernames(usernames: Array): Promise { - return this.roomBridge.doGetDirectByUsernames(usernames, this.appId); - } - - public getModerators(roomId: string): Promise> { - return this.roomBridge.doGetModerators(roomId, this.appId); - } - - public getOwners(roomId: string): Promise> { - return this.roomBridge.doGetOwners(roomId, this.appId); - } - - public getLeaders(roomId: string): Promise> { - return this.roomBridge.doGetLeaders(roomId, this.appId); - } - - public async getUnreadByUser(roomId: string, uid: string, options: Partial = {}): Promise { - const { limit = 100, sort = { createdAt: 'asc' }, skip = 0, showThreadMessages = true } = options; - - if (typeof roomId !== 'string' || roomId.trim().length === 0) { - throw new Error('Invalid roomId: must be a non-empty string'); - } - - if (!Number.isFinite(limit) || limit <= 0 || limit > 100) { - throw new Error(`Invalid limit provided. Expected number between 1 and 100, got ${limit}`); - } - - this.validateSort(sort); - - const completeOptions: GetMessagesOptions = { limit, sort, skip, showThreadMessages }; - - return this.roomBridge.doGetUnreadByUser(roomId, uid, completeOptions, this.appId); - } - - public getUserUnreadMessageCount(roomId: string, uid: string): Promise { - return this.roomBridge.doGetUserUnreadMessageCount(roomId, uid, this.appId); - } - - // If there are any invalid fields or values, throw - private validateSort(sort: Record) { - Object.entries(sort).forEach(([key, value]) => { - if (!GetMessagesSortableFields.includes(key as (typeof GetMessagesSortableFields)[number])) { - throw new Error(`Invalid key "${key}" used in sort. Available keys for sorting are ${GetMessagesSortableFields.join(', ')}`); - } - - if (value !== 'asc' && value !== 'desc') { - throw new Error(`Invalid sort direction for field "${key}". Expected "asc" or "desc", got ${value}`); - } - }); - } -} diff --git a/packages/apps/src/server/accessors/SchedulerExtend.ts b/packages/apps/src/server/accessors/SchedulerExtend.ts deleted file mode 100644 index 753bd4aa14a1a..0000000000000 --- a/packages/apps/src/server/accessors/SchedulerExtend.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { ISchedulerExtend } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IProcessor } from '@rocket.chat/apps-engine/definition/scheduler'; - -import type { AppSchedulerManager } from '../managers/AppSchedulerManager'; - -export class SchedulerExtend implements ISchedulerExtend { - constructor( - private readonly manager: AppSchedulerManager, - private readonly appId: string, - ) {} - - public async registerProcessors(processors: Array = []): Promise> { - return this.manager.registerProcessors(processors, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/SchedulerModify.ts b/packages/apps/src/server/accessors/SchedulerModify.ts deleted file mode 100644 index 20e82909ac3eb..0000000000000 --- a/packages/apps/src/server/accessors/SchedulerModify.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { ISchedulerModify } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IOnetimeSchedule, IRecurringSchedule } from '@rocket.chat/apps-engine/definition/scheduler'; - -import type { SchedulerBridge } from '../bridges'; - -function createProcessorId(jobId: string, appId: string): string { - return jobId.includes(`_${appId}`) ? jobId : `${jobId}_${appId}`; -} - -export class SchedulerModify implements ISchedulerModify { - constructor( - private readonly bridge: SchedulerBridge, - private readonly appId: string, - ) {} - - public async scheduleOnce(job: IOnetimeSchedule): Promise { - return this.bridge.doScheduleOnce({ ...job, id: createProcessorId(job.id, this.appId) }, this.appId); - } - - public async scheduleRecurring(job: IRecurringSchedule): Promise { - return this.bridge.doScheduleRecurring({ ...job, id: createProcessorId(job.id, this.appId) }, this.appId); - } - - public async cancelJob(jobId: string): Promise { - return this.bridge.doCancelJob(createProcessorId(jobId, this.appId), this.appId); - } - - public async cancelAllJobs(): Promise { - return this.bridge.doCancelAllJobs(this.appId); - } -} diff --git a/packages/apps/src/server/accessors/ServerSettingRead.ts b/packages/apps/src/server/accessors/ServerSettingRead.ts deleted file mode 100644 index 5bfab63c4054f..0000000000000 --- a/packages/apps/src/server/accessors/ServerSettingRead.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { IServerSettingRead } from '@rocket.chat/apps-engine/definition/accessors'; -import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; - -import type { ServerSettingBridge } from '../bridges/ServerSettingBridge'; - -export class ServerSettingRead implements IServerSettingRead { - constructor( - private readonly settingBridge: ServerSettingBridge, - private readonly appId: string, - ) {} - - public getOneById(id: string): Promise { - return this.settingBridge.doGetOneById(id, this.appId); - } - - public async getValueById(id: string): Promise { - const set = await this.settingBridge.doGetOneById(id, this.appId); - - if (typeof set === 'undefined') { - throw new Error(`No Server Setting found, or it is unaccessible, by the id of "${id}".`); - } - - if (set.value === undefined || set.value === null) { - return set.packageValue; - } - - return set.value; - } - - public getAll(): Promise> { - throw new Error('Method not implemented.'); - // return this.settingBridge.getAll(this.appId); - } - - public isReadableById(id: string): Promise { - return this.settingBridge.doIsReadableById(id, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/ServerSettingUpdater.ts b/packages/apps/src/server/accessors/ServerSettingUpdater.ts deleted file mode 100644 index 280aae967a819..0000000000000 --- a/packages/apps/src/server/accessors/ServerSettingUpdater.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { IServerSettingUpdater } from '@rocket.chat/apps-engine/definition/accessors'; -import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; - -import type { AppBridges } from '../bridges'; - -export class ServerSettingUpdater implements IServerSettingUpdater { - constructor( - private readonly bridges: AppBridges, - private readonly appId: string, - ) {} - - public async updateOne(setting: ISetting): Promise { - await this.bridges.getServerSettingBridge().doUpdateOne(setting, this.appId); - } - - public async incrementValue(id: ISetting['id'], value = 1): Promise { - await this.bridges.getServerSettingBridge().doIncrementValue(id, value, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/ServerSettingsModify.ts b/packages/apps/src/server/accessors/ServerSettingsModify.ts deleted file mode 100644 index c742ffbe5bf70..0000000000000 --- a/packages/apps/src/server/accessors/ServerSettingsModify.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { IServerSettingsModify } from '@rocket.chat/apps-engine/definition/accessors'; -import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; - -import type { ServerSettingBridge } from '../bridges/ServerSettingBridge'; - -export class ServerSettingsModify implements IServerSettingsModify { - constructor( - private readonly bridge: ServerSettingBridge, - private readonly appId: string, - ) {} - - public async hideGroup(name: string): Promise { - await this.bridge.doHideGroup(name, this.appId); - } - - public async hideSetting(id: string): Promise { - await this.bridge.doHideSetting(id, this.appId); - } - - public async modifySetting(setting: ISetting): Promise { - await this.bridge.doUpdateOne(setting, this.appId); - } - - public async incrementValue(id: ISetting['id'], value = 1): Promise { - await this.bridge.doIncrementValue(id, value, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/SettingRead.ts b/packages/apps/src/server/accessors/SettingRead.ts deleted file mode 100644 index 04d076fa7d323..0000000000000 --- a/packages/apps/src/server/accessors/SettingRead.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { ISettingRead } from '@rocket.chat/apps-engine/definition/accessors'; -import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; - -import type { ProxiedApp } from '../ProxiedApp'; - -export class SettingRead implements ISettingRead { - constructor(private readonly app: ProxiedApp) {} - - public getById(id: string): Promise { - return Promise.resolve(this.app.getStorageItem().settings[id]); - } - - public async getValueById(id: string): Promise { - const set = await this.getById(id); - - if (typeof set === 'undefined') { - throw new Error(`Setting "${id}" does not exist.`); - } - - if (set.value === undefined || set.value === null) { - return set.packageValue; - } - - return set.value; - } -} diff --git a/packages/apps/src/server/accessors/SettingUpdater.ts b/packages/apps/src/server/accessors/SettingUpdater.ts deleted file mode 100644 index 45bc4b5ecabbe..0000000000000 --- a/packages/apps/src/server/accessors/SettingUpdater.ts +++ /dev/null @@ -1,67 +0,0 @@ -import type { ISettingUpdater } from '@rocket.chat/apps-engine/definition/accessors/ISettingUpdater'; -import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; - -import type { ProxiedApp } from '../ProxiedApp'; -import type { AppSettingsManager } from '../managers'; - -/** - * Implementation of ISettingUpdater that provides methods to update app settings. - */ -export class SettingUpdater implements ISettingUpdater { - constructor( - private readonly app: ProxiedApp, - private readonly manager: AppSettingsManager, - ) {} - - /** - * Updates a single setting value - * @param id The setting ID to update - * @param value The new value to set - * @returns Promise that resolves when the update is complete - * @throws Error if the setting doesn't exist - */ - public async updateValue(id: ISetting['id'], value: ISetting['value']): Promise { - const appId = this.app.getID(); - const storageItem = this.app.getStorageItem(); - - if (!storageItem.settings?.[id]) { - throw new Error(`Setting "${id}" not found for app ${appId}`); - } - - const setting = this.manager.getAppSetting(appId, id); - - await this.manager.updateAppSetting(appId, { - ...setting, - updatedAt: new Date(), - value, - }); - } - - /** - * Updates the values for a multi-value setting by overwriting them - * @param id The setting ID to update - * @param values The new values to set - * @returns Promise that resolves when the update is complete - * @throws Error if the setting doesn't exist - */ - public async updateSelectOptions(id: ISetting['id'], values: ISetting['values']): Promise { - const appId = this.app.getID(); - const storageItem = this.app.getStorageItem(); - - if (!storageItem.settings?.[id]) { - throw new Error(`Setting "${id}" not found for app ${appId}`); - } - - const setting = this.manager.getAppSetting(appId, id); - - // TODO: This operation completely overwrites existing values - // which could lead to loss of selected values. Consider: - // Adding warning logs when selected value will be removed - - await this.manager.updateAppSetting(appId, { - ...setting, - updatedAt: new Date(), - values, // Overwrite the values instead of merging - }); - } -} diff --git a/packages/apps/src/server/accessors/SettingsExtend.ts b/packages/apps/src/server/accessors/SettingsExtend.ts deleted file mode 100644 index 951c3f4610a83..0000000000000 --- a/packages/apps/src/server/accessors/SettingsExtend.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { ISettingsExtend } from '@rocket.chat/apps-engine/definition/accessors'; -import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; - -import type { ProxiedApp } from '../ProxiedApp'; - -export class SettingsExtend implements ISettingsExtend { - constructor(private readonly app: ProxiedApp) {} - - public async provideSetting(setting: ISetting): Promise { - if (this.app.getStorageItem().settings[setting.id]) { - // :see_no_evil: - const old = await Promise.resolve(this.app.getStorageItem().settings[setting.id]); - - setting.createdAt = old.createdAt; - setting.updatedAt = new Date(); - setting.value = old.value; - - this.app.getStorageItem().settings[setting.id] = setting; - - return; - } - - setting.createdAt = new Date(); - setting.updatedAt = new Date(); - this.app.getStorageItem().settings[setting.id] = setting; - } -} diff --git a/packages/apps/src/server/accessors/SlashCommandsExtend.ts b/packages/apps/src/server/accessors/SlashCommandsExtend.ts deleted file mode 100644 index 981dc8d01ffe7..0000000000000 --- a/packages/apps/src/server/accessors/SlashCommandsExtend.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { ISlashCommandsExtend } from '@rocket.chat/apps-engine/definition/accessors'; -import type { ISlashCommand } from '@rocket.chat/apps-engine/definition/slashcommands'; - -import type { AppSlashCommandManager } from '../managers/AppSlashCommandManager'; - -export class SlashCommandsExtend implements ISlashCommandsExtend { - constructor( - private readonly manager: AppSlashCommandManager, - private readonly appId: string, - ) {} - - public async provideSlashCommand(slashCommand: ISlashCommand): Promise { - await this.manager.addCommand(this.appId, slashCommand); - } -} diff --git a/packages/apps/src/server/accessors/SlashCommandsModify.ts b/packages/apps/src/server/accessors/SlashCommandsModify.ts deleted file mode 100644 index 469f9cda3c37d..0000000000000 --- a/packages/apps/src/server/accessors/SlashCommandsModify.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { ISlashCommandsModify } from '@rocket.chat/apps-engine/definition/accessors'; -import type { ISlashCommand } from '@rocket.chat/apps-engine/definition/slashcommands'; - -import type { AppSlashCommandManager } from '../managers'; - -export class SlashCommandsModify implements ISlashCommandsModify { - constructor( - private readonly manager: AppSlashCommandManager, - private readonly appId: string, - ) {} - - public modifySlashCommand(slashCommand: ISlashCommand): Promise { - return Promise.resolve(this.manager.modifyCommand(this.appId, slashCommand)); - } - - public disableSlashCommand(command: string): Promise { - return Promise.resolve(this.manager.disableCommand(this.appId, command)); - } - - public enableSlashCommand(command: string): Promise { - return Promise.resolve(this.manager.enableCommand(this.appId, command)); - } -} diff --git a/packages/apps/src/server/accessors/ThreadRead.ts b/packages/apps/src/server/accessors/ThreadRead.ts deleted file mode 100644 index 1cb6a6a66a6a9..0000000000000 --- a/packages/apps/src/server/accessors/ThreadRead.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { IThreadRead } from '@rocket.chat/apps-engine/definition/accessors/IThreadRead'; -import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; - -import type { ThreadBridge } from '../bridges/ThreadBridge'; - -export class ThreadRead implements IThreadRead { - constructor( - private threadBridge: ThreadBridge, - private appId: string, - ) {} - - public getThreadById(id: string): Promise> { - return this.threadBridge.doGetById(id, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/UIController.ts b/packages/apps/src/server/accessors/UIController.ts deleted file mode 100644 index e21cf80b845f1..0000000000000 --- a/packages/apps/src/server/accessors/UIController.ts +++ /dev/null @@ -1,126 +0,0 @@ -import type { IUIController } from '@rocket.chat/apps-engine/definition/accessors'; -import type { - IUIKitErrorInteractionParam, - IUIKitInteractionParam, - IUIKitSurfaceViewParam, -} from '@rocket.chat/apps-engine/definition/accessors/IUIController'; -import { UIKitInteractionType, UIKitSurfaceType } from '@rocket.chat/apps-engine/definition/uikit'; -import { - formatContextualBarInteraction, - formatErrorInteraction, - formatModalInteraction, -} from '@rocket.chat/apps-engine/definition/uikit/UIKitInteractionPayloadFormatter'; -import type { - IUIKitContextualBarViewParam, - IUIKitModalViewParam, -} from '@rocket.chat/apps-engine/definition/uikit/UIKitInteractionResponder'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -import type { AppBridges, UiInteractionBridge } from '../bridges'; -import { UIHelper } from '../misc/UIHelper'; - -export class UIController implements IUIController { - private readonly uiInteractionBridge: UiInteractionBridge; - - constructor( - private readonly appId: string, - bridges: AppBridges, - ) { - this.uiInteractionBridge = bridges.getUiInteractionBridge(); - } - - /** - * @deprecated please prefer the `openSurfaceView` method - */ - public openModalView(view: IUIKitModalViewParam, context: IUIKitInteractionParam, user: IUser) { - return this.openModal(view, context, user); - } - - /** - * @deprecated please prefer the `updateSurfaceView` method - */ - public updateModalView(view: IUIKitModalViewParam, context: IUIKitInteractionParam, user: IUser) { - return this.openModal(view, context, user, true); - } - - /** - * @deprecated please prefer the `openSurfaceView` method - */ - public openContextualBarView(view: IUIKitContextualBarViewParam, context: IUIKitInteractionParam, user: IUser) { - return this.openContextualBar(view, context, user); - } - - /** - * @deprecated please prefer the `updateSurfaceView` method - */ - public updateContextualBarView(view: IUIKitContextualBarViewParam, context: IUIKitInteractionParam, user: IUser) { - return this.openContextualBar(view, context, user, true); - } - - public openSurfaceView(view: IUIKitSurfaceViewParam, context: IUIKitInteractionParam, user: IUser) { - const blocks = UIHelper.assignIds(view.blocks, this.appId); - const viewWithIds = { ...view, blocks }; - - switch (view.type) { - case UIKitSurfaceType.CONTEXTUAL_BAR: - return this.openContextualBar(viewWithIds, context, user); - case UIKitSurfaceType.MODAL: - return this.openModal(viewWithIds, context, user); - } - } - - public updateSurfaceView(view: IUIKitSurfaceViewParam, context: IUIKitInteractionParam, user: IUser) { - const blocks = UIHelper.assignIds(view.blocks, this.appId); - const viewWithIds = { ...view, blocks }; - - switch (view.type) { - case UIKitSurfaceType.CONTEXTUAL_BAR: - return this.openContextualBar(viewWithIds, context, user, true); - case UIKitSurfaceType.MODAL: - return this.openModal(viewWithIds, context, user, true); - } - } - - public setViewError(errorInteraction: IUIKitErrorInteractionParam, context: IUIKitInteractionParam, user: IUser) { - const interactionContext = { - ...context, - type: UIKitInteractionType.ERRORS, - appId: this.appId, - }; - - return this.uiInteractionBridge.doNotifyUser(user, formatErrorInteraction(errorInteraction, interactionContext), this.appId); - } - - private openContextualBar( - view: IUIKitContextualBarViewParam, - context: IUIKitInteractionParam, - user: IUser, - isUpdate = false, - ): Promise { - let type = UIKitInteractionType.CONTEXTUAL_BAR_OPEN; - if (isUpdate) { - type = UIKitInteractionType.CONTEXTUAL_BAR_UPDATE; - } - const interactionContext = { - ...context, - type, - appId: this.appId, - }; - - return this.uiInteractionBridge.doNotifyUser(user, formatContextualBarInteraction(view, interactionContext), this.appId); - } - - private openModal(view: IUIKitModalViewParam, context: IUIKitInteractionParam, user: IUser, isUpdate = false): Promise { - let type = UIKitInteractionType.MODAL_OPEN; - if (isUpdate) { - type = UIKitInteractionType.MODAL_UPDATE; - } - const interactionContext = { - ...context, - type, - appId: this.appId, - }; - - return this.uiInteractionBridge.doNotifyUser(user, formatModalInteraction(view, interactionContext), this.appId); - } -} diff --git a/packages/apps/src/server/accessors/UIExtend.ts b/packages/apps/src/server/accessors/UIExtend.ts deleted file mode 100644 index 7369461dae569..0000000000000 --- a/packages/apps/src/server/accessors/UIExtend.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { IUIExtend } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IUIActionButtonDescriptor } from '@rocket.chat/apps-engine/definition/ui'; - -import type { UIActionButtonManager } from '../managers/UIActionButtonManager'; - -export class UIExtend implements IUIExtend { - constructor( - private readonly manager: UIActionButtonManager, - private readonly appId: string, - ) {} - - public registerButton(button: IUIActionButtonDescriptor): void { - this.manager.registerActionButton(this.appId, button); - } -} diff --git a/packages/apps/src/server/accessors/UploadCreator.ts b/packages/apps/src/server/accessors/UploadCreator.ts deleted file mode 100644 index f33a30f0e4259..0000000000000 --- a/packages/apps/src/server/accessors/UploadCreator.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { IUploadCreator } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IUpload } from '@rocket.chat/apps-engine/definition/uploads'; -import type { IUploadDescriptor } from '@rocket.chat/apps-engine/definition/uploads/IUploadDescriptor'; -import type { IUploadDetails } from '@rocket.chat/apps-engine/definition/uploads/IUploadDetails'; - -import type { AppBridges } from '../bridges'; - -export class UploadCreator implements IUploadCreator { - constructor( - private readonly bridges: AppBridges, - private readonly appId: string, - ) {} - - public async uploadBuffer(buffer: Buffer, descriptor: IUploadDescriptor): Promise { - if (!Object.hasOwn(descriptor, 'user') && !descriptor.visitorToken) { - descriptor.user = await this.bridges.getUserBridge().doGetAppUser(this.appId); - } - - const details = { - name: descriptor.filename, - size: buffer.length, - rid: descriptor.room.id, - userId: descriptor.user?.id, - visitorToken: descriptor.visitorToken, - } as IUploadDetails; - - return this.bridges.getUploadBridge().doCreateUpload(details, buffer, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/UploadRead.ts b/packages/apps/src/server/accessors/UploadRead.ts deleted file mode 100644 index 5df4ed5b2755c..0000000000000 --- a/packages/apps/src/server/accessors/UploadRead.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { IUploadRead } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IUpload } from '@rocket.chat/apps-engine/definition/uploads'; - -import type { UploadBridge } from '../bridges/UploadBridge'; - -export class UploadRead implements IUploadRead { - constructor( - private readonly uploadBridge: UploadBridge, - private readonly appId: string, - ) {} - - public getById(id: string): Promise { - return this.uploadBridge.doGetById(id, this.appId); - } - - public getBuffer(upload: IUpload): Promise { - return this.uploadBridge.doGetBuffer(upload, this.appId); - } - - public async getBufferById(id: string): Promise { - const upload = await this.uploadBridge.doGetById(id, this.appId); - - return this.uploadBridge.doGetBuffer(upload, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/UserBuilder.ts b/packages/apps/src/server/accessors/UserBuilder.ts deleted file mode 100644 index f1c891ec73bd6..0000000000000 --- a/packages/apps/src/server/accessors/UserBuilder.ts +++ /dev/null @@ -1,74 +0,0 @@ -import type { IUserBuilder } from '@rocket.chat/apps-engine/definition/accessors'; -import { RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata'; -import type { IUser, IUserEmail } from '@rocket.chat/apps-engine/definition/users'; -import type { IUserSettings } from '@rocket.chat/apps-engine/definition/users/IUserSettings'; - -export class UserBuilder implements IUserBuilder { - public kind: RocketChatAssociationModel.USER; - - private user: Partial; - - constructor(user?: Partial) { - this.kind = RocketChatAssociationModel.USER; - this.user = user || ({} as Partial); - } - - public setData(data: Partial): IUserBuilder { - delete data.id; - this.user = data; - - return this; - } - - public setEmails(emails: Array): IUserBuilder { - this.user.emails = emails; - return this; - } - - public getEmails(): Array { - 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): IUserBuilder { - this.user.roles = roles; - return this; - } - - public getRoles(): Array { - return this.user.roles; - } - - public getSettings(): Partial { - return this.user.settings; - } - - public getUser(): Partial { - 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; - } -} diff --git a/packages/apps/src/server/accessors/UserRead.ts b/packages/apps/src/server/accessors/UserRead.ts deleted file mode 100644 index 1d6a6d0d4c55a..0000000000000 --- a/packages/apps/src/server/accessors/UserRead.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { IUserRead } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -import type { UserBridge } from '../bridges/UserBridge'; - -export class UserRead implements IUserRead { - constructor( - private userBridge: UserBridge, - private appId: string, - ) {} - - public getById(id: string): Promise { - return this.userBridge.doGetById(id, this.appId); - } - - public getByUsername(username: string): Promise { - return this.userBridge.doGetByUsername(username, this.appId); - } - - public getBySipExtension(extension: string): Promise { - if (!extension) { - return Promise.resolve(undefined); - } - - return this.userBridge.doGetBySipExtension(extension, this.appId); - } - - public getAppUser(appId: string = this.appId): Promise { - return this.userBridge.doGetAppUser(appId); - } - - public getUserUnreadMessageCount(uid: string): Promise { - return this.userBridge.doGetUserUnreadMessageCount(uid, this.appId); - } - - public getUserRoomIds(userId: string): Promise { - return this.userBridge.doGetUserRoomIds(userId, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/UserUpdater.ts b/packages/apps/src/server/accessors/UserUpdater.ts deleted file mode 100644 index 4eb2e5f11b42b..0000000000000 --- a/packages/apps/src/server/accessors/UserUpdater.ts +++ /dev/null @@ -1,43 +0,0 @@ -import type { IUserUpdater } from '@rocket.chat/apps-engine/definition/accessors/IUserUpdater'; -import type { UserStatusConnection } from '@rocket.chat/apps-engine/definition/users'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users/IUser'; - -import type { AppBridges } from '../bridges'; - -export class UserUpdater implements IUserUpdater { - constructor( - private readonly bridges: AppBridges, - private readonly appId: string, - ) {} - - public async updateStatusText(user: IUser, statusText: IUser['statusText']) { - return this.bridges.getUserBridge().doUpdate(user, { statusText }, this.appId); - } - - public async updateStatus(user: IUser, statusText: IUser['statusText'], status: UserStatusConnection) { - return this.bridges.getUserBridge().doUpdate(user, { statusText, status }, this.appId); - } - - public async updateBio(user: IUser, bio: IUser['bio']) { - return this.bridges.getUserBridge().doUpdate(user, { bio }, this.appId); - } - - public async updateCustomFields(user: IUser, customFields: IUser['customFields']) { - return this.bridges.getUserBridge().doUpdate(user, { customFields }, this.appId); - } - - public async deactivate(userId: IUser['id'], confirmRelinquish: boolean) { - return this.bridges.getUserBridge().doDeactivate(userId, confirmRelinquish, this.appId); - } - - public async setActiveState( - userId: IUser['id'], - state: Pick, - ) { - return this.bridges.getUserBridge().doSetActiveState(userId, state, this.appId); - } - - public async endActiveState(userId: IUser['id'], statusId?: string) { - return this.bridges.getUserBridge().doEndActiveState(userId, this.appId, statusId); - } -} diff --git a/packages/apps/src/server/accessors/VideoConfProviderExtend.ts b/packages/apps/src/server/accessors/VideoConfProviderExtend.ts deleted file mode 100644 index 45bb2b174e381..0000000000000 --- a/packages/apps/src/server/accessors/VideoConfProviderExtend.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { IVideoConfProvidersExtend } from '@rocket.chat/apps-engine/definition/accessors'; -import type { IVideoConfProvider } from '@rocket.chat/apps-engine/definition/videoConfProviders'; - -import type { AppVideoConfProviderManager } from '../managers/AppVideoConfProviderManager'; - -export class VideoConfProviderExtend implements IVideoConfProvidersExtend { - constructor( - private readonly manager: AppVideoConfProviderManager, - private readonly appId: string, - ) {} - - public provideVideoConfProvider(provider: IVideoConfProvider): Promise { - return Promise.resolve(this.manager.addProvider(this.appId, provider)); - } -} diff --git a/packages/apps/src/server/accessors/VideoConferenceBuilder.ts b/packages/apps/src/server/accessors/VideoConferenceBuilder.ts deleted file mode 100644 index a7c101b9851e7..0000000000000 --- a/packages/apps/src/server/accessors/VideoConferenceBuilder.ts +++ /dev/null @@ -1,83 +0,0 @@ -import type { IVideoConferenceBuilder } from '@rocket.chat/apps-engine/definition/accessors'; -import { RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata'; -import type { AppVideoConference } from '@rocket.chat/apps-engine/definition/videoConferences'; - -export class VideoConferenceBuilder implements IVideoConferenceBuilder { - public kind: RocketChatAssociationModel.VIDEO_CONFERENCE = RocketChatAssociationModel.VIDEO_CONFERENCE; - - protected call: AppVideoConference; - - constructor(data?: Partial) { - this.call = (data || {}) as AppVideoConference; - } - - public setData(data: Partial): IVideoConferenceBuilder { - this.call = { - rid: data.rid, - createdBy: data.createdBy, - providerName: data.providerName, - title: data.title, - discussionRid: data.discussionRid, - }; - - 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 | undefined): IVideoConferenceBuilder { - this.call.providerData = data; - return this; - } - - public getProviderData(): Record | undefined { - return this.call.providerData; - } - - public setTitle(userId: string): IVideoConferenceBuilder { - this.call.title = userId; - return this; - } - - public getTitle(): string { - 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; - } -} diff --git a/packages/apps/src/server/accessors/VideoConferenceExtend.ts b/packages/apps/src/server/accessors/VideoConferenceExtend.ts deleted file mode 100644 index 01c816bf952ad..0000000000000 --- a/packages/apps/src/server/accessors/VideoConferenceExtend.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { IVideoConferenceExtender } from '@rocket.chat/apps-engine/definition/accessors'; -import { RocketChatAssociationModel } from '@rocket.chat/apps-engine/definition/metadata'; -import type { IVideoConferenceUser, VideoConference } from '@rocket.chat/apps-engine/definition/videoConferences'; -import type { VideoConferenceMember } from '@rocket.chat/apps-engine/definition/videoConferences/IVideoConference'; - -import { Utilities } from '../misc/Utilities'; - -export class VideoConferenceExtender implements IVideoConferenceExtender { - public kind: RocketChatAssociationModel.VIDEO_CONFERENCE; - - constructor(private videoConference: VideoConference) { - this.kind = RocketChatAssociationModel.VIDEO_CONFERENCE; - } - - public setProviderData(value: Record): IVideoConferenceExtender { - this.videoConference.providerData = value; - - return this; - } - - public setStatus(value: VideoConference['status']): IVideoConferenceExtender { - this.videoConference.status = value; - - return this; - } - - public setEndedBy(value: IVideoConferenceUser['_id']): IVideoConferenceExtender { - this.videoConference.endedBy = { - _id: value, - // Name and username will be loaded automatically by the bridge - username: '', - name: '', - }; - - return this; - } - - public setEndedAt(value: VideoConference['endedAt']): IVideoConferenceExtender { - this.videoConference.endedAt = value; - - return this; - } - - public addUser(userId: VideoConferenceMember['_id'], ts?: VideoConferenceMember['ts']): IVideoConferenceExtender { - this.videoConference.users.push({ - _id: userId, - ts, - // Name and username will be loaded automatically by the bridge - username: '', - name: '', - }); - - return this; - } - - public setDiscussionRid(rid: VideoConference['discussionRid']): IVideoConferenceExtender { - this.videoConference.discussionRid = rid; - - return this; - } - - public getVideoConference(): VideoConference { - return Utilities.deepClone(this.videoConference); - } -} diff --git a/packages/apps/src/server/accessors/VideoConferenceRead.ts b/packages/apps/src/server/accessors/VideoConferenceRead.ts deleted file mode 100644 index 02dc89e356dd6..0000000000000 --- a/packages/apps/src/server/accessors/VideoConferenceRead.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { IVideoConferenceRead } from '@rocket.chat/apps-engine/definition/accessors'; -import type { VideoConference } from '@rocket.chat/apps-engine/definition/videoConferences'; - -import type { VideoConferenceBridge } from '../bridges'; - -export class VideoConferenceRead implements IVideoConferenceRead { - constructor( - private videoConfBridge: VideoConferenceBridge, - private appId: string, - ) {} - - public getById(id: string): Promise { - return this.videoConfBridge.doGetById(id, this.appId); - } -} diff --git a/packages/apps/src/server/accessors/index.ts b/packages/apps/src/server/accessors/index.ts deleted file mode 100644 index eb5cbdc0218c7..0000000000000 --- a/packages/apps/src/server/accessors/index.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { ApiExtend } from './ApiExtend'; -import { AppAccessors } from './AppAccessors'; -import { ConfigurationExtend } from './ConfigurationExtend'; -import { ConfigurationModify } from './ConfigurationModify'; -import { EnvironmentRead } from './EnvironmentRead'; -import { EnvironmentWrite } from './EnvironmentWrite'; -import { EnvironmentalVariableRead } from './EnvironmentalVariableRead'; -import { ExternalComponentsExtend } from './ExternalComponentsExtend'; -import { Http } from './Http'; -import { HttpExtend } from './HttpExtend'; -import { LivechatRead } from './LivechatRead'; -import { MessageBuilder } from './MessageBuilder'; -import { MessageExtender } from './MessageExtender'; -import { MessageRead } from './MessageRead'; -import { ModerationModify } from './ModerationModify'; -import { Modify } from './Modify'; -import { ModifyCreator } from './ModifyCreator'; -import { ModifyExtender } from './ModifyExtender'; -import { ModifyUpdater } from './ModifyUpdater'; -import { Notifier } from './Notifier'; -import { OAuthAppsModify } from './OAuthAppsModify'; -import { OAuthAppsReader } from './OAuthAppsReader'; -import { OutboundMessageProviderExtend } from './OutboundCommunicationProviderExtend'; -import { Persistence } from './Persistence'; -import { PersistenceRead } from './PersistenceRead'; -import { Reader } from './Reader'; -import { RoleRead } from './RoleRead'; -import { RoomBuilder } from './RoomBuilder'; -import { RoomExtender } from './RoomExtender'; -import { RoomRead } from './RoomRead'; -import { SchedulerExtend } from './SchedulerExtend'; -import { SchedulerModify } from './SchedulerModify'; -import { ServerSettingRead } from './ServerSettingRead'; -import { ServerSettingUpdater } from './ServerSettingUpdater'; -import { ServerSettingsModify } from './ServerSettingsModify'; -import { SettingRead } from './SettingRead'; -import { SettingUpdater } from './SettingUpdater'; -import { SettingsExtend } from './SettingsExtend'; -import { SlashCommandsExtend } from './SlashCommandsExtend'; -import { SlashCommandsModify } from './SlashCommandsModify'; -import { UploadRead } from './UploadRead'; -import { UserBuilder } from './UserBuilder'; -import { UserRead } from './UserRead'; -import { VideoConfProviderExtend } from './VideoConfProviderExtend'; -import { VideoConferenceBuilder } from './VideoConferenceBuilder'; -import { VideoConferenceExtender } from './VideoConferenceExtend'; -import { VideoConferenceRead } from './VideoConferenceRead'; - -export { - ApiExtend, - AppAccessors, - ConfigurationExtend, - ConfigurationModify, - EnvironmentalVariableRead, - EnvironmentRead, - EnvironmentWrite, - ExternalComponentsExtend, - Http, - HttpExtend, - LivechatRead, - MessageBuilder, - MessageExtender, - MessageRead, - ModerationModify, - Modify, - ModifyCreator, - ModifyExtender, - ModifyUpdater, - Notifier, - Persistence, - PersistenceRead, - Reader, - RoleRead, - RoomBuilder, - RoomExtender, - RoomRead, - ServerSettingRead, - ServerSettingsModify, - ServerSettingUpdater, - SettingRead, - SettingsExtend, - SettingUpdater, - SlashCommandsExtend, - SlashCommandsModify, - UploadRead, - UserBuilder, - UserRead, - SchedulerExtend, - SchedulerModify, - VideoConferenceBuilder, - VideoConferenceExtender, - VideoConferenceRead, - VideoConfProviderExtend, - OAuthAppsModify, - OAuthAppsReader, - OutboundMessageProviderExtend, -}; diff --git a/packages/apps/src/server/managers/AppAccessorManager.ts b/packages/apps/src/server/managers/AppAccessorManager.ts deleted file mode 100644 index 57681c85856d5..0000000000000 --- a/packages/apps/src/server/managers/AppAccessorManager.ts +++ /dev/null @@ -1,252 +0,0 @@ -import type { - IConfigurationExtend, - IConfigurationModify, - IEnvironmentRead, - IEnvironmentWrite, - IHttp, - IHttpExtend, - IModify, - IPersistence, - IRead, -} from '@rocket.chat/apps-engine/definition/accessors'; - -import type { AppManager } from '../AppManager'; -import { - ApiExtend, - ConfigurationExtend, - ConfigurationModify, - EnvironmentalVariableRead, - EnvironmentRead, - EnvironmentWrite, - ExternalComponentsExtend, - Http, - HttpExtend, - LivechatRead, - MessageRead, - Modify, - Notifier, - OAuthAppsReader, - OutboundMessageProviderExtend, - Persistence, - PersistenceRead, - Reader, - RoleRead, - RoomRead, - SchedulerExtend, - SchedulerModify, - ServerSettingRead, - ServerSettingsModify, - ServerSettingUpdater, - SettingRead, - SettingsExtend, - SettingUpdater, - SlashCommandsExtend, - SlashCommandsModify, - UploadRead, - UserRead, - VideoConferenceRead, - VideoConfProviderExtend, -} from '../accessors'; -import { CloudWorkspaceRead } from '../accessors/CloudWorkspaceRead'; -import { ContactRead } from '../accessors/ContactRead'; -import { ExperimentalRead } from '../accessors/ExperimentalRead'; -import { ThreadRead } from '../accessors/ThreadRead'; -import { UIExtend } from '../accessors/UIExtend'; -import type { AppBridges } from '../bridges/AppBridges'; - -export class AppAccessorManager { - private readonly bridges: AppBridges; - - private readonly configExtenders: Map; - - private readonly envReaders: Map; - - private readonly envWriters: Map; - - private readonly configModifiers: Map; - - private readonly readers: Map; - - private readonly modifiers: Map; - - private readonly persists: Map; - - private readonly https: Map; - - constructor(private readonly manager: AppManager) { - this.bridges = this.manager.getBridges(); - this.configExtenders = new Map(); - this.envReaders = new Map(); - this.envWriters = new Map(); - this.configModifiers = new Map(); - this.readers = new Map(); - this.modifiers = new Map(); - this.persists = new Map(); - this.https = new Map(); - } - - /** - * Purifies the accessors for the provided App. - * - * @param appId The id of the App to purge the accessors for. - */ - public purifyApp(appId: string): void { - this.configExtenders.delete(appId); - this.envReaders.delete(appId); - this.envWriters.delete(appId); - this.configModifiers.delete(appId); - this.readers.delete(appId); - this.modifiers.delete(appId); - this.persists.delete(appId); - this.https.delete(appId); - } - - public getConfigurationExtend(appId: string): IConfigurationExtend { - if (!this.configExtenders.has(appId)) { - const rl = this.manager.getOneById(appId); - - if (!rl) { - throw new Error(`No App found by the provided id: ${appId}`); - } - - const htt = new HttpExtend(); - const cmds = new SlashCommandsExtend(this.manager.getCommandManager(), appId); - const videoConf = new VideoConfProviderExtend(this.manager.getVideoConfProviderManager(), appId); - const apis = new ApiExtend(this.manager.getApiManager(), appId); - const sets = new SettingsExtend(rl); - const excs = new ExternalComponentsExtend(this.manager.getExternalComponentManager(), appId); - const scheduler = new SchedulerExtend(this.manager.getSchedulerManager(), appId); - const ui = new UIExtend(this.manager.getUIActionButtonManager(), appId); - const outboundComms = new OutboundMessageProviderExtend(this.manager.getOutboundCommunicationProviderManager(), appId); - - this.configExtenders.set(appId, new ConfigurationExtend(htt, sets, cmds, apis, excs, scheduler, ui, videoConf, outboundComms)); - } - - return this.configExtenders.get(appId); - } - - public getEnvironmentRead(appId: string): IEnvironmentRead { - if (!this.envReaders.has(appId)) { - const rl = this.manager.getOneById(appId); - - if (!rl) { - throw new Error(`No App found by the provided id: ${appId}`); - } - - const sets = new SettingRead(rl); - const servsets = new ServerSettingRead(this.bridges.getServerSettingBridge(), appId); - const env = new EnvironmentalVariableRead(this.bridges.getEnvironmentalVariableBridge(), appId); - - this.envReaders.set(appId, new EnvironmentRead(sets, servsets, env)); - } - - return this.envReaders.get(appId); - } - - public getEnvironmentWrite(appId: string): IEnvironmentWrite { - if (!this.envWriters.has(appId)) { - const rl = this.manager.getOneById(appId); - - if (!rl) { - throw new Error(`No App found by the provided id: ${appId}`); - } - - const sets = new SettingUpdater(rl, this.manager.getSettingsManager()); - const serverSetting = new ServerSettingUpdater(this.bridges, appId); - - this.envWriters.set(appId, new EnvironmentWrite(sets, serverSetting)); - } - - return this.envWriters.get(appId); - } - - public getConfigurationModify(appId: string): IConfigurationModify { - if (!this.configModifiers.has(appId)) { - this.configModifiers.set( - appId, - new ConfigurationModify( - new ServerSettingsModify(this.bridges.getServerSettingBridge(), appId), - new SlashCommandsModify(this.manager.getCommandManager(), appId), - new SchedulerModify(this.bridges.getSchedulerBridge(), appId), - ), - ); - } - - return this.configModifiers.get(appId); - } - - public getReader(appId: string): IRead { - if (!this.readers.has(appId)) { - const env = this.getEnvironmentRead(appId); - const msg = new MessageRead(this.bridges.getMessageBridge(), appId); - const persist = new PersistenceRead(this.bridges.getPersistenceBridge(), appId); - const room = new RoomRead(this.bridges.getRoomBridge(), appId); - const user = new UserRead(this.bridges.getUserBridge(), appId); - const noti = new Notifier(this.bridges.getUserBridge(), this.bridges.getMessageBridge(), appId); - const livechat = new LivechatRead(this.bridges.getLivechatBridge(), appId); - const upload = new UploadRead(this.bridges.getUploadBridge(), appId); - const cloud = new CloudWorkspaceRead(this.bridges.getCloudWorkspaceBridge(), appId); - const videoConf = new VideoConferenceRead(this.bridges.getVideoConferenceBridge(), appId); - const oauthApps = new OAuthAppsReader(this.bridges.getOAuthAppsBridge(), appId); - const contactReader = new ContactRead(this.bridges, appId); - const thread = new ThreadRead(this.bridges.getThreadBridge(), appId); - const role = new RoleRead(this.bridges.getRoleBridge(), appId); - const experimental = new ExperimentalRead(this.bridges.getExperimentalBridge(), appId); - - this.readers.set( - appId, - new Reader( - env, - msg, - persist, - room, - user, - noti, - livechat, - upload, - cloud, - videoConf, - contactReader, - oauthApps, - thread, - role, - experimental, - ), - ); - } - - return this.readers.get(appId); - } - - public getModifier(appId: string): IModify { - if (!this.modifiers.has(appId)) { - this.modifiers.set(appId, new Modify(this.bridges, appId)); - } - - return this.modifiers.get(appId); - } - - public getPersistence(appId: string): IPersistence { - if (!this.persists.has(appId)) { - this.persists.set(appId, new Persistence(this.bridges.getPersistenceBridge(), appId)); - } - - return this.persists.get(appId); - } - - public getHttp(appId: string): IHttp { - if (!this.https.has(appId)) { - let ext: IHttpExtend; - if (this.configExtenders.has(appId)) { - ext = this.configExtenders.get(appId).http; - } else { - const cf = this.getConfigurationExtend(appId); - ext = cf.http; - } - - this.https.set(appId, new Http(this, this.bridges, ext, appId)); - } - - return this.https.get(appId); - } -} diff --git a/packages/apps/src/server/managers/AppApi.ts b/packages/apps/src/server/managers/AppApi.ts index 88205731dd0da..e16a337ea2e9e 100644 --- a/packages/apps/src/server/managers/AppApi.ts +++ b/packages/apps/src/server/managers/AppApi.ts @@ -5,7 +5,6 @@ import type { IApiEndpointInfo } from '@rocket.chat/apps-engine/definition/api/I import type { ProxiedApp } from '../ProxiedApp'; import type { AppLogStorage } from '../storage'; -import type { AppAccessorManager } from './AppAccessorManager'; export class AppApi { public readonly computedPath: string; @@ -41,7 +40,7 @@ export class AppApi { this.implementedMethods = endpoint._availableMethods; } - public async runExecutor(request: IApiRequest, _logStorage: AppLogStorage, _accessors: AppAccessorManager): Promise { + public async runExecutor(request: IApiRequest, _logStorage: AppLogStorage): Promise { const { path } = this.endpoint; const { method } = request; diff --git a/packages/apps/src/server/managers/AppApiManager.ts b/packages/apps/src/server/managers/AppApiManager.ts index e553eef9743ef..72cc68940e406 100644 --- a/packages/apps/src/server/managers/AppApiManager.ts +++ b/packages/apps/src/server/managers/AppApiManager.ts @@ -5,7 +5,6 @@ import type { IApi, IApiEndpointMetadata, IApiRequest, IApiResponse } from '@roc import type { AppManager } from '../AppManager'; import type { ApiBridge } from '../bridges'; import { PathAlreadyExistsError } from '../errors'; -import type { AppAccessorManager } from './AppAccessorManager'; import { AppApi } from './AppApi'; /** @@ -18,15 +17,12 @@ import { AppApi } from './AppApi'; export class AppApiManager { private readonly bridge: ApiBridge; - private readonly accessors: AppAccessorManager; - // Variable that contains the api's which have been provided by apps. // The key of the top map is app id and the key of the inner map is the path private providedApis: Map>; constructor(private readonly manager: AppManager) { this.bridge = this.manager.getBridges().getApiBridge(); - this.accessors = this.manager.getAccessorManager(); this.providedApis = new Map>(); } @@ -123,7 +119,7 @@ export class AppApiManager { }; } - return api.runExecutor(request, this.manager.getLogStorage(), this.accessors); + return api.runExecutor(request, this.manager.getLogStorage()); } /** diff --git a/packages/apps/src/server/managers/AppListenerManager.ts b/packages/apps/src/server/managers/AppListenerManager.ts index 37e9a0dc3fa7e..a44db79910368 100644 --- a/packages/apps/src/server/managers/AppListenerManager.ts +++ b/packages/apps/src/server/managers/AppListenerManager.ts @@ -31,7 +31,6 @@ import type { import type { IFileUploadInternalContext } from '@rocket.chat/apps-engine/definition/uploads/IFileUploadContext'; import type { IUser, IUserContext, IUserStatusContext, IUserUpdateContext } from '@rocket.chat/apps-engine/definition/users'; -import type { AppAccessorManager } from './AppAccessorManager'; import type { AppManager } from '../AppManager'; import type { ProxiedApp } from '../ProxiedApp'; import { Utilities } from '../misc/Utilities'; @@ -248,8 +247,6 @@ export interface IListenerExecutor { // type EventReturn = void | boolean | IMessage | IRoom | IUser | IUIKitResponse | ILivechatRoom | IEmailDescriptor; export class AppListenerManager { - private am: AppAccessorManager; - private listeners: Map>; private defaultHandlers = new Map(); @@ -263,7 +260,6 @@ export class AppListenerManager { private lockedEvents: Map>; constructor(private readonly manager: AppManager) { - this.am = manager.getAccessorManager(); this.listeners = new Map>(); this.lockedEvents = new Map>(); @@ -557,8 +553,7 @@ export class AppListenerManager { for (const appId of this.listeners.get(AppInterface.IPostMessageSentToBot)) { const app = this.manager.getOneById(appId); - const reader = this.am.getReader(appId); - const bot = await reader.getUserReader().getAppUser(); + const bot = await this.manager.getBridges().getUserBridge().doGetAppUser(appId); if (!bot) { continue; } diff --git a/packages/apps/src/server/managers/AppOutboundCommunicationProvider.ts b/packages/apps/src/server/managers/AppOutboundCommunicationProvider.ts index ad93ea1e4136c..4cd5e54797bae 100644 --- a/packages/apps/src/server/managers/AppOutboundCommunicationProvider.ts +++ b/packages/apps/src/server/managers/AppOutboundCommunicationProvider.ts @@ -5,7 +5,6 @@ import type { ProviderMetadata, } from '@rocket.chat/apps-engine/definition/outboundCommunication'; -import type { AppAccessorManager } from '.'; import type { ProxiedApp } from '../ProxiedApp'; import { AppOutboundProcessError } from '../errors/AppOutboundProcessError'; import type { AppLogStorage } from '../storage'; @@ -20,18 +19,17 @@ export class OutboundMessageProvider { this.isRegistered = false; } - public async runGetProviderMetadata(logStorage: AppLogStorage, accessors: AppAccessorManager): Promise { - return this.runTheCode(AppMethod._OUTBOUND_GET_PROVIDER_METADATA, logStorage, accessors, []); + public async runGetProviderMetadata(logStorage: AppLogStorage): Promise { + return this.runTheCode(AppMethod._OUTBOUND_GET_PROVIDER_METADATA, logStorage, []); } - public async runSendOutboundMessage(logStorage: AppLogStorage, accessors: AppAccessorManager, body: IOutboundMessage): Promise { - await this.runTheCode(AppMethod._OUTBOUND_SEND_MESSAGE, logStorage, accessors, [body]); + public async runSendOutboundMessage(logStorage: AppLogStorage, body: IOutboundMessage): Promise { + await this.runTheCode(AppMethod._OUTBOUND_SEND_MESSAGE, logStorage, [body]); } private async runTheCode( method: AppMethod._OUTBOUND_GET_PROVIDER_METADATA | AppMethod._OUTBOUND_SEND_MESSAGE, _logStorage: AppLogStorage, - _accessors: AppAccessorManager, runContextArgs: Array, ): Promise { const provider = `${this.provider.name}-${this.provider.type}`; diff --git a/packages/apps/src/server/managers/AppOutboundCommunicationProviderManager.ts b/packages/apps/src/server/managers/AppOutboundCommunicationProviderManager.ts index a4767c2ab665b..a07793abb1b71 100644 --- a/packages/apps/src/server/managers/AppOutboundCommunicationProviderManager.ts +++ b/packages/apps/src/server/managers/AppOutboundCommunicationProviderManager.ts @@ -6,7 +6,6 @@ import type { IOutboundMessage, } from '@rocket.chat/apps-engine/definition/outboundCommunication'; -import type { AppAccessorManager } from '.'; import type { AppManager } from '../AppManager'; import type { OutboundMessageBridge } from '../bridges'; import { OutboundMessageProvider } from './AppOutboundCommunicationProvider'; @@ -15,15 +14,12 @@ import { PermissionDeniedError } from '../errors/PermissionDeniedError'; import { AppPermissions } from '../permissions/AppPermissions'; export class AppOutboundCommunicationProviderManager { - private readonly accessors: AppAccessorManager; - private readonly bridge: OutboundMessageBridge; private outboundMessageProviders: Map>; constructor(private readonly manager: AppManager) { this.bridge = this.manager.getBridges().getOutboundMessageBridge(); - this.accessors = this.manager.getAccessorManager(); this.outboundMessageProviders = new Map>(); } @@ -125,7 +121,7 @@ export class AppOutboundCommunicationProviderManager { throw new Error('provider-not-registered'); } - return providerInfo.runGetProviderMetadata(this.manager.getLogStorage(), this.accessors); + return providerInfo.runGetProviderMetadata(this.manager.getLogStorage()); } public sendOutboundMessage(appId: string, providerType: ValidOutboundProvider, body: IOutboundMessage) { @@ -134,6 +130,6 @@ export class AppOutboundCommunicationProviderManager { throw new Error('provider-not-registered'); } - return providerInfo.runSendOutboundMessage(this.manager.getLogStorage(), this.accessors, body); + return providerInfo.runSendOutboundMessage(this.manager.getLogStorage(), body); } } diff --git a/packages/apps/src/server/managers/AppSlashCommand.ts b/packages/apps/src/server/managers/AppSlashCommand.ts index a69f81112a970..3aa1cf3eeb8aa 100644 --- a/packages/apps/src/server/managers/AppSlashCommand.ts +++ b/packages/apps/src/server/managers/AppSlashCommand.ts @@ -8,7 +8,6 @@ import type { import type { ProxiedApp } from '../ProxiedApp'; import type { AppLogStorage } from '../storage'; -import type { AppAccessorManager } from './AppAccessorManager'; export class AppSlashCommand { /** @@ -47,24 +46,21 @@ export class AppSlashCommand { method: AppMethod._COMMAND_EXECUTOR | AppMethod._COMMAND_PREVIEWER, context: SlashCommandContext, logStorage: AppLogStorage, - accessors: AppAccessorManager, ): Promise { - return this.runTheCode(method, logStorage, accessors, context, []); + return this.runTheCode(method, logStorage, context, []); } public async runPreviewExecutor( previewItem: ISlashCommandPreviewItem, context: SlashCommandContext, logStorage: AppLogStorage, - accessors: AppAccessorManager, ): Promise { - await this.runTheCode(AppMethod._COMMAND_PREVIEW_EXECUTOR, logStorage, accessors, context, [previewItem]); + await this.runTheCode(AppMethod._COMMAND_PREVIEW_EXECUTOR, logStorage, context, [previewItem]); } private async runTheCode( method: AppMethod._COMMAND_EXECUTOR | AppMethod._COMMAND_PREVIEWER | AppMethod._COMMAND_PREVIEW_EXECUTOR, _logStorage: AppLogStorage, - _accessors: AppAccessorManager, context: SlashCommandContext, runContextArgs: Array, ): Promise { diff --git a/packages/apps/src/server/managers/AppSlashCommandManager.ts b/packages/apps/src/server/managers/AppSlashCommandManager.ts index 41cac1ecdd966..fe73b3f113b73 100644 --- a/packages/apps/src/server/managers/AppSlashCommandManager.ts +++ b/packages/apps/src/server/managers/AppSlashCommandManager.ts @@ -6,7 +6,6 @@ import { SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashco import type { AppManager } from '../AppManager'; import type { CommandBridge } from '../bridges'; import { CommandAlreadyExistsError, CommandHasAlreadyBeenTouchedError } from '../errors'; -import type { AppAccessorManager } from './AppAccessorManager'; import { AppSlashCommand } from './AppSlashCommand'; import { Room } from '../rooms/Room'; @@ -22,8 +21,6 @@ import { Room } from '../rooms/Room'; export class AppSlashCommandManager { private readonly bridge: CommandBridge; - private readonly accessors: AppAccessorManager; - /** * Variable that contains the commands which have been provided by apps. * The key of the top map is app id and the key of the inner map is the command @@ -51,7 +48,6 @@ export class AppSlashCommandManager { constructor(private readonly manager: AppManager) { this.bridge = this.manager.getBridges().getCommandBridge(); - this.accessors = this.manager.getAccessorManager(); this.touchedCommandsToApps = new Map(); this.appsTouchedCommands = new Map>(); this.providedCommands = new Map>(); @@ -343,12 +339,7 @@ export class AppSlashCommandManager { } const appCmd = this.retrieveCommandInfo(cmd, app.getID()); - await appCmd.runExecutorOrPreviewer( - AppMethod._COMMAND_EXECUTOR, - this.ensureContext(context), - this.manager.getLogStorage(), - this.accessors, - ); + await appCmd.runExecutorOrPreviewer(AppMethod._COMMAND_EXECUTOR, this.ensureContext(context), this.manager.getLogStorage()); } public async getPreviews(command: string, context: SlashCommandContext): Promise { @@ -372,7 +363,6 @@ export class AppSlashCommandManager { AppMethod._COMMAND_PREVIEWER, this.ensureContext(context), this.manager.getLogStorage(), - this.accessors, ); if (!result) { @@ -399,7 +389,7 @@ export class AppSlashCommandManager { } const appCmd = this.retrieveCommandInfo(cmd, app.getID()); - await appCmd.runPreviewExecutor(previewItem, this.ensureContext(context), this.manager.getLogStorage(), this.accessors); + await appCmd.runPreviewExecutor(previewItem, this.ensureContext(context), this.manager.getLogStorage()); } private ensureContext(context: SlashCommandContext): SlashCommandContext { diff --git a/packages/apps/src/server/managers/AppVideoConfProvider.ts b/packages/apps/src/server/managers/AppVideoConfProvider.ts index f93196f68bfc5..e537e719621e0 100644 --- a/packages/apps/src/server/managers/AppVideoConfProvider.ts +++ b/packages/apps/src/server/managers/AppVideoConfProvider.ts @@ -10,7 +10,6 @@ import type { VideoConference } from '@rocket.chat/apps-engine/definition/videoC import type { IVideoConferenceUser } from '@rocket.chat/apps-engine/definition/videoConferences/IVideoConferenceUser'; import type { ProxiedApp } from '../ProxiedApp'; -import type { AppAccessorManager } from './AppAccessorManager'; import { JSONRPC_METHOD_NOT_FOUND } from '../runtime/base/BaseRuntimeSubprocessController'; import type { AppLogStorage } from '../storage'; @@ -31,12 +30,12 @@ export class AppVideoConfProvider { this.isRegistered = true; } - public async runIsFullyConfigured(logStorage: AppLogStorage, accessors: AppAccessorManager): Promise { - return !!(await this.runTheCode(AppMethod._VIDEOCONF_IS_CONFIGURED, logStorage, accessors, [])); + public async runIsFullyConfigured(logStorage: AppLogStorage): Promise { + return !!(await this.runTheCode(AppMethod._VIDEOCONF_IS_CONFIGURED, logStorage, [])); } - public async runGenerateUrl(call: VideoConfData, logStorage: AppLogStorage, accessors: AppAccessorManager): Promise { - return (await this.runTheCode(AppMethod._VIDEOCONF_GENERATE_URL, logStorage, accessors, [call])) as string; + public async runGenerateUrl(call: VideoConfData, logStorage: AppLogStorage): Promise { + return (await this.runTheCode(AppMethod._VIDEOCONF_GENERATE_URL, logStorage, [call])) as string; } public async runCustomizeUrl( @@ -44,35 +43,28 @@ export class AppVideoConfProvider { user: IVideoConferenceUser | undefined, options: IVideoConferenceOptions = {}, logStorage: AppLogStorage, - accessors: AppAccessorManager, ): Promise { - return (await this.runTheCode(AppMethod._VIDEOCONF_CUSTOMIZE_URL, logStorage, accessors, [call, user, options])) as string; + return (await this.runTheCode(AppMethod._VIDEOCONF_CUSTOMIZE_URL, logStorage, [call, user, options])) as string; } - public async runOnNewVideoConference(call: VideoConference, logStorage: AppLogStorage, accessors: AppAccessorManager): Promise { - await this.runTheCode(AppMethod._VIDEOCONF_NEW, logStorage, accessors, [call]); + public async runOnNewVideoConference(call: VideoConference, logStorage: AppLogStorage): Promise { + await this.runTheCode(AppMethod._VIDEOCONF_NEW, logStorage, [call]); } - public async runOnVideoConferenceChanged(call: VideoConference, logStorage: AppLogStorage, accessors: AppAccessorManager): Promise { - await this.runTheCode(AppMethod._VIDEOCONF_CHANGED, logStorage, accessors, [call]); + public async runOnVideoConferenceChanged(call: VideoConference, logStorage: AppLogStorage): Promise { + await this.runTheCode(AppMethod._VIDEOCONF_CHANGED, logStorage, [call]); } - public async runOnUserJoin( - call: VideoConference, - user: IVideoConferenceUser | undefined, - logStorage: AppLogStorage, - accessors: AppAccessorManager, - ): Promise { - await this.runTheCode(AppMethod._VIDEOCONF_USER_JOINED, logStorage, accessors, [call, user]); + public async runOnUserJoin(call: VideoConference, user: IVideoConferenceUser | undefined, logStorage: AppLogStorage): Promise { + await this.runTheCode(AppMethod._VIDEOCONF_USER_JOINED, logStorage, [call, user]); } public async runGetVideoConferenceInfo( call: VideoConference, user: IVideoConferenceUser | undefined, logStorage: AppLogStorage, - accessors: AppAccessorManager, ): Promise | undefined> { - return (await this.runTheCode(AppMethod._VIDEOCONF_GET_INFO, logStorage, accessors, [call, user])) as Array | undefined; + return (await this.runTheCode(AppMethod._VIDEOCONF_GET_INFO, logStorage, [call, user])) as Array | undefined; } private async runTheCode( @@ -85,7 +77,6 @@ export class AppVideoConfProvider { | AppMethod._VIDEOCONF_GET_INFO | AppMethod._VIDEOCONF_USER_JOINED, _logStorage: AppLogStorage, - _accessors: AppAccessorManager, runContextArgs: Array, ): Promise | undefined> { const provider = this.provider.name; diff --git a/packages/apps/src/server/managers/AppVideoConfProviderManager.ts b/packages/apps/src/server/managers/AppVideoConfProviderManager.ts index 2a3ec752dd10c..ef8596c93e0e6 100644 --- a/packages/apps/src/server/managers/AppVideoConfProviderManager.ts +++ b/packages/apps/src/server/managers/AppVideoConfProviderManager.ts @@ -11,15 +11,12 @@ import type { IVideoConferenceUser } from '@rocket.chat/apps-engine/definition/v import type { AppManager } from '../AppManager'; import type { VideoConferenceBridge } from '../bridges'; import { VideoConfProviderAlreadyExistsError, VideoConfProviderNotRegisteredError } from '../errors'; -import type { AppAccessorManager } from './AppAccessorManager'; import { AppPermissionManager } from './AppPermissionManager'; import { AppVideoConfProvider } from './AppVideoConfProvider'; import { PermissionDeniedError } from '../errors/PermissionDeniedError'; import { AppPermissions } from '../permissions/AppPermissions'; export class AppVideoConfProviderManager { - private readonly accessors: AppAccessorManager; - private readonly bridge: VideoConferenceBridge; private videoConfProviders: Map>; @@ -28,7 +25,6 @@ export class AppVideoConfProviderManager { constructor(private readonly manager: AppManager) { this.bridge = this.manager.getBridges().getVideoConferenceBridge(); - this.accessors = this.manager.getAccessorManager(); this.videoConfProviders = new Map>(); this.providerApps = new Map(); @@ -111,7 +107,7 @@ export class AppVideoConfProviderManager { throw new VideoConfProviderNotRegisteredError(providerName); } - return providerInfo.runIsFullyConfigured(this.manager.getLogStorage(), this.accessors); + return providerInfo.runIsFullyConfigured(this.manager.getLogStorage()); } public async onNewVideoConference(providerName: string, call: VideoConference): Promise { @@ -120,7 +116,7 @@ export class AppVideoConfProviderManager { throw new VideoConfProviderNotRegisteredError(providerName); } - return providerInfo.runOnNewVideoConference(call, this.manager.getLogStorage(), this.accessors); + return providerInfo.runOnNewVideoConference(call, this.manager.getLogStorage()); } public async onVideoConferenceChanged(providerName: string, call: VideoConference): Promise { @@ -129,7 +125,7 @@ export class AppVideoConfProviderManager { throw new VideoConfProviderNotRegisteredError(providerName); } - return providerInfo.runOnVideoConferenceChanged(call, this.manager.getLogStorage(), this.accessors); + return providerInfo.runOnVideoConferenceChanged(call, this.manager.getLogStorage()); } public async onUserJoin(providerName: string, call: VideoConference, user?: IVideoConferenceUser): Promise { @@ -138,7 +134,7 @@ export class AppVideoConfProviderManager { throw new VideoConfProviderNotRegisteredError(providerName); } - return providerInfo.runOnUserJoin(call, user, this.manager.getLogStorage(), this.accessors); + return providerInfo.runOnUserJoin(call, user, this.manager.getLogStorage()); } public async getVideoConferenceInfo( @@ -151,7 +147,7 @@ export class AppVideoConfProviderManager { throw new VideoConfProviderNotRegisteredError(providerName); } - return providerInfo.runGetVideoConferenceInfo(call, user, this.manager.getLogStorage(), this.accessors); + return providerInfo.runGetVideoConferenceInfo(call, user, this.manager.getLogStorage()); } public async generateUrl(providerName: string, call: VideoConfData): Promise { @@ -160,7 +156,7 @@ export class AppVideoConfProviderManager { throw new VideoConfProviderNotRegisteredError(providerName); } - return providerInfo.runGenerateUrl(call, this.manager.getLogStorage(), this.accessors); + return providerInfo.runGenerateUrl(call, this.manager.getLogStorage()); } public async customizeUrl( @@ -174,7 +170,7 @@ export class AppVideoConfProviderManager { throw new VideoConfProviderNotRegisteredError(providerName); } - return providerInfo.runCustomizeUrl(call, user, options, this.manager.getLogStorage(), this.accessors); + return providerInfo.runCustomizeUrl(call, user, options, this.manager.getLogStorage()); } private retrieveProviderInfo(providerName: string): AppVideoConfProvider | undefined { diff --git a/packages/apps/src/server/managers/index.ts b/packages/apps/src/server/managers/index.ts index 9d7b22c79bc53..c467f6c24d9a6 100644 --- a/packages/apps/src/server/managers/index.ts +++ b/packages/apps/src/server/managers/index.ts @@ -1,4 +1,3 @@ -import { AppAccessorManager } from './AppAccessorManager'; import { AppApiManager } from './AppApiManager'; import { AppExternalComponentManager } from './AppExternalComponentManager'; import { AppLicenseManager } from './AppLicenseManager'; @@ -10,7 +9,6 @@ import { AppSlashCommandManager } from './AppSlashCommandManager'; import { AppVideoConfProviderManager } from './AppVideoConfProviderManager'; export { - AppAccessorManager, AppLicenseManager, AppListenerManager, AppExternalComponentManager, diff --git a/packages/apps/src/server/misc/UIHelper.ts b/packages/apps/src/server/misc/UIHelper.ts deleted file mode 100644 index acfe6d1ffea0c..0000000000000 --- a/packages/apps/src/server/misc/UIHelper.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { randomUUID } from 'node:crypto'; - -import type { IBlock } from '@rocket.chat/apps-engine/definition/uikit'; -import type { LayoutBlock } from '@rocket.chat/ui-kit'; - -export class UIHelper { - /** - * Assign blockId, appId and actionId to every block/element inside the array - * @param blocks the blocks that will be iterated and assigned the ids - * @param appId the appId that will be assigned to - * @returns the array of block with the ids properties assigned - */ - public static assignIds(blocks: Array, appId: string): Array { - blocks.forEach((block: (IBlock | LayoutBlock) & { appId?: string; blockId?: string; elements?: Array }) => { - if (!block.appId) { - block.appId = appId; - } - if (!block.blockId) { - block.blockId = randomUUID(); - } - if (block.elements) { - block.elements.forEach((element) => { - if (!element.actionId) { - element.actionId = randomUUID(); - } - }); - } - }); - - return blocks; - } -} diff --git a/packages/apps/src/server/runtime/base/BaseRuntimeSubprocessController.ts b/packages/apps/src/server/runtime/base/BaseRuntimeSubprocessController.ts index 92f1c22458af9..ca3a06ddcbcb7 100644 --- a/packages/apps/src/server/runtime/base/BaseRuntimeSubprocessController.ts +++ b/packages/apps/src/server/runtime/base/BaseRuntimeSubprocessController.ts @@ -17,35 +17,11 @@ import type { AppBridges } from '../../bridges'; import { AppResourceBridge } from '../../bridges/AppResourceBridge'; import type { IParseAppPackageResult } from '../../compiler'; import { AppConsole, type ILoggerStorageEntry } from '../../logging'; -import type { AppAccessorManager, AppApiManager } from '../../managers'; import type { AppLogStorage, IAppStorageItem } from '../../storage'; import type { IRuntimeController } from '../IRuntimeController'; const inspect = (value: unknown) => utilInspect(value, { depth: 10, compact: true, breakLength: Infinity }); -export const ALLOWED_ACCESSOR_METHODS = [ - 'getConfigurationExtend', - 'getEnvironmentRead', - 'getEnvironmentWrite', - 'getConfigurationModify', - 'getReader', - 'getPersistence', - 'getHttp', - 'getModifier', -] as Array< - keyof Pick< - AppAccessorManager, - | 'getConfigurationExtend' - | 'getEnvironmentRead' - | 'getEnvironmentWrite' - | 'getConfigurationModify' - | 'getReader' - | 'getPersistence' - | 'getHttp' - | 'getModifier' - > ->; - const COMMAND_PONG = '_zPONG'; export const JSONRPC_METHOD_NOT_FOUND = -32601; @@ -64,10 +40,6 @@ function getRuntimeTimeout() { return envValue; } -function isValidOrigin(accessor: string): accessor is (typeof ALLOWED_ACCESSOR_METHODS)[number] { - return ALLOWED_ACCESSOR_METHODS.includes(accessor as any); -} - /** * Resolves the absolute path to @rocket.chat/apps-engine's src/ directory. * Uses require.resolve so it works regardless of the runtime environment @@ -90,8 +62,8 @@ export type ProcessConfiguration = { /** * Holds the platform-agnostic logic for controlling an app subprocess: spawning, - * killing, restarting, liveness, and the full JSON-RPC message loop (accessor, - * bridge, result and error handling). + * killing, restarting, liveness, and the full JSON-RPC message loop (bridge, + * result and error handling). * * The only platform-specific concern - how to actually launch the subprocess for * a given runtime (Deno, Node, ...) - is delegated to {@link buildProcessConfiguration}, @@ -115,10 +87,6 @@ export abstract class BaseRuntimeSubprocessController extends EventEmitter imple timeout: getRuntimeTimeout(), }; - private readonly accessors: AppAccessorManager; - - private readonly api: AppApiManager; - private readonly logStorage: AppLogStorage; private readonly bridges: AppBridges; @@ -156,8 +124,6 @@ export abstract class BaseRuntimeSubprocessController extends EventEmitter imple this.state = 'uninitialized'; - this.accessors = manager.getAccessorManager(); - this.api = manager.getApiManager(); this.logStorage = manager.getLogStorage(); this.bridges = manager.getBridges(); this.appResourceBridge = new AppResourceBridge(manager); @@ -425,103 +391,6 @@ export abstract class BaseRuntimeSubprocessController extends EventEmitter imple void this.parseStdout(this.process.stdout); } - // Probable should extract this to a separate file - private async handleAccessorMessage({ payload: { method, id, params } }: jsonrpc.IParsedObjectRequest): Promise { - const accessorMethods = method.substring(9).split(':'); // First 9 characters are always 'accessor:' - - this.debug('Handling accessor message %s with params %s', inspect(accessorMethods), inspect(params)); - - const managerOrigin = accessorMethods.shift(); - const tailMethodName = accessorMethods.pop(); - - // If we're restarting the app, we can't register resources again, so we - // hijack requests for the `ConfigurationExtend` accessor and don't let them through - // This needs to be refactored ASAP - if (this.state === 'restarting' && managerOrigin === 'getConfigurationExtend') { - return jsonrpc.success(id, null); - } - - if (managerOrigin === 'api' && tailMethodName === 'listApis') { - const result = this.api.listApis(this.appPackage.info.id); - - return jsonrpc.success(id, result); - } - - /** - * At this point, the accessorMethods array will contain the path to the accessor from the origin (AppAccessorManager) - * The accessor is the one that contains the actual method the app wants to call - * - * Most of the times, it will take one step from origin to accessor - * For example, for the call AppAccessorManager.getEnvironmentRead().getServerSettings().getValueById() we'll have - * the following: - * - * ``` - * const managerOrigin = 'getEnvironmentRead' - * const tailMethod = 'getValueById' - * const accessorMethods = ['getServerSettings'] - * ``` - * - * But sometimes there can be more steps, like in the following example: - * AppAccessorManager.getReader().getEnvironmentReader().getEnvironmentVariables().getValueByName() - * In this case, we'll have: - * - * ``` - * const managerOrigin = 'getReader' - * const tailMethod = 'getValueByName' - * const accessorMethods = ['getEnvironmentReader', 'getEnvironmentVariables'] - * ``` - **/ - // Prevent app from trying to get properties from the manager that - // are not intended for public access - if (!isValidOrigin(managerOrigin)) { - throw new Error(`Invalid accessor namespace "${managerOrigin}"`); - } - - // Need to fix typing of return value - const getAccessorForOrigin = ( - accessorMethods: string[], - managerOrigin: (typeof ALLOWED_ACCESSOR_METHODS)[number], - accessorManager: AppAccessorManager, - ) => { - const origin = accessorManager[managerOrigin](this.appPackage.info.id); - - if (managerOrigin === 'getHttp' || managerOrigin === 'getPersistence') { - return origin; - } - - if (managerOrigin === 'getConfigurationExtend' || managerOrigin === 'getConfigurationModify') { - return origin[accessorMethods[0] as keyof typeof origin]; - } - - let accessor = origin; - - // Call all intermediary objects to "resolve" the accessor - accessorMethods.forEach((methodName) => { - const method = accessor[methodName as keyof typeof accessor] as unknown; - - if (typeof method !== 'function') { - throw new Error(`Invalid accessor method "${methodName}"`); - } - - accessor = method.apply(accessor); - }); - - return accessor; - }; - - const accessor = getAccessorForOrigin(accessorMethods, managerOrigin, this.accessors); - - const tailMethod = accessor[tailMethodName as keyof typeof accessor] as unknown; - - if (typeof tailMethod !== 'function') { - throw new Error(`Invalid accessor method "${tailMethodName}"`); - } - - const result = await tailMethod.apply(accessor, params); - - return jsonrpc.success(id, typeof result === 'undefined' ? null : result); - } - private async handleBridgeMessage({ payload: { method, id, params }, }: jsonrpc.IParsedObjectRequest): Promise { @@ -580,20 +449,6 @@ export abstract class BaseRuntimeSubprocessController extends EventEmitter imple private async handleIncomingMessage(message: jsonrpc.IParsedObjectNotification | jsonrpc.IParsedObjectRequest): Promise { const { method } = message.payload; - if (method.startsWith('accessor:')) { - let result: jsonrpc.SuccessObject | jsonrpc.ErrorObject; - - try { - result = await this.handleAccessorMessage(message as jsonrpc.IParsedObjectRequest); - } catch (e) { - result = jsonrpc.error((message.payload as jsonrpc.RequestObject).id, new jsonrpc.JsonRpcError(e.message, 1000)); - } - - this.messenger.send(result); - - return; - } - if (method.startsWith('bridges:')) { let result: jsonrpc.SuccessObject | jsonrpc.ErrorObject; diff --git a/packages/apps/tests/server/AppManager.test.ts b/packages/apps/tests/server/AppManager.test.ts index f4b7db974e9c3..18cb65f5f0362 100644 --- a/packages/apps/tests/server/AppManager.test.ts +++ b/packages/apps/tests/server/AppManager.test.ts @@ -5,7 +5,6 @@ import { AppManager } from '../../src/server/AppManager'; import { AppBridges } from '../../src/server/bridges'; import { AppCompiler, AppPackageParser } from '../../src/server/compiler'; import { - AppAccessorManager, AppApiManager, AppExternalComponentManager, AppListenerManager, @@ -131,7 +130,6 @@ describe('AppManager', () => { assert.ok(manager.getParser() instanceof AppPackageParser); assert.ok(manager.getCompiler() instanceof AppCompiler); - assert.ok(manager.getAccessorManager() instanceof AppAccessorManager); assert.ok(manager.getBridges() instanceof AppBridges); assert.ok(manager.getListenerManager() instanceof AppListenerManager); assert.ok(manager.getCommandManager() instanceof AppSlashCommandManager); diff --git a/packages/apps/tests/server/accessors/AppAccessors.test.ts b/packages/apps/tests/server/accessors/AppAccessors.test.ts deleted file mode 100644 index 9cd414de009fa..0000000000000 --- a/packages/apps/tests/server/accessors/AppAccessors.test.ts +++ /dev/null @@ -1,121 +0,0 @@ -import * as assert from 'node:assert'; -import { afterEach, beforeEach, describe, it, mock } from 'node:test'; - -import { AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus'; -import type { AppMethod } from '@rocket.chat/apps-engine/definition/metadata'; - -import type { AppManager } from '../../../src/server/AppManager'; -import type { ProxiedApp } from '../../../src/server/ProxiedApp'; -import { AppAccessors } from '../../../src/server/accessors'; -import type { AppBridges } from '../../../src/server/bridges'; -import { AppConsole } from '../../../src/server/logging'; -import type { - AppExternalComponentManager, - AppSchedulerManager, - AppSettingsManager, - AppSlashCommandManager, - AppVideoConfProviderManager, -} from '../../../src/server/managers'; -import { AppAccessorManager, AppApiManager } from '../../../src/server/managers'; -import type { AppOutboundCommunicationProviderManager } from '../../../src/server/managers/AppOutboundCommunicationProviderManager'; -import type { UIActionButtonManager } from '../../../src/server/managers/UIActionButtonManager'; -import type { AppsEngineRuntime } from '../../../src/server/runtime/AppsEngineRuntime'; -import type { AppLogStorage } from '../../../src/server/storage'; -import { TestsAppBridges } from '../../test-data/bridges/appBridges'; -import { TestsAppLogStorage } from '../../test-data/storage/logStorage'; -import { TestData } from '../../test-data/utilities'; - -describe('AppAccessors', () => { - let mockBridges: TestsAppBridges; - let mockApp: ProxiedApp; - let mockAccessors: AppAccessorManager; - let mockManager: AppManager; - let mockApiManager: AppApiManager; - - beforeEach(() => { - mockBridges = new TestsAppBridges(); - - mockApp = { - getRuntime() { - return {} as AppsEngineRuntime; - }, - getID() { - return 'testing'; - }, - getStatus() { - return Promise.resolve(AppStatus.AUTO_ENABLED); - }, - setupLogger(method: AppMethod): AppConsole { - return new AppConsole(method); - }, - } as ProxiedApp; - - const bri = mockBridges; - const app = mockApp; - mockManager = { - getBridges(): AppBridges { - return bri; - }, - getCommandManager() { - return {} as AppSlashCommandManager; - }, - getExternalComponentManager() { - return {} as AppExternalComponentManager; - }, - getOneById(appId: string): ProxiedApp { - return appId === 'failMePlease' ? undefined : app; - }, - getLogStorage(): AppLogStorage { - return new TestsAppLogStorage(); - }, - getSchedulerManager() { - return {} as AppSchedulerManager; - }, - getUIActionButtonManager() { - return {} as UIActionButtonManager; - }, - getVideoConfProviderManager() { - return {} as AppVideoConfProviderManager; - }, - getSettingsManager() { - return {} as AppSettingsManager; - }, - getOutboundCommunicationProviderManager() { - return {} as AppOutboundCommunicationProviderManager; - }, - } as unknown as AppManager; - - mockAccessors = new AppAccessorManager(mockManager); - const ac = mockAccessors; - mockManager.getAccessorManager = function _getAccessorManager(): AppAccessorManager { - return ac; - }; - - mockApiManager = new AppApiManager(mockManager); - const apiManager = mockApiManager; - mockManager.getApiManager = function _getApiManager(): AppApiManager { - return apiManager; - }; - }); - - afterEach(() => { - mock.restoreAll(); - }); - - it('testAppAccessor', () => { - assert.throws(() => new AppAccessors({} as AppManager, '')); - assert.doesNotThrow(() => new AppAccessors(mockManager, 'testing')); - - const appAccessors = new AppAccessors(mockManager, 'testing'); - - assert.deepStrictEqual(appAccessors.environmentReader, mockAccessors.getEnvironmentRead('testing')); - assert.deepStrictEqual(appAccessors.environmentWriter, mockAccessors.getEnvironmentWrite('testing')); - assert.deepStrictEqual(appAccessors.reader, mockAccessors.getReader('testing')); - assert.deepStrictEqual(appAccessors.http, mockAccessors.getHttp('testing')); - assert.deepStrictEqual(appAccessors.providedApiEndpoints, mockApiManager.listApis('testing')); - - mockApiManager.addApi('testing', TestData.getApi('app-accessor-api')); - - assert.deepStrictEqual(appAccessors.providedApiEndpoints, mockApiManager.listApis('testing')); - }); -}); diff --git a/packages/apps/tests/server/accessors/ConfigurationExtend.test.ts b/packages/apps/tests/server/accessors/ConfigurationExtend.test.ts deleted file mode 100644 index fda3204f9d0c4..0000000000000 --- a/packages/apps/tests/server/accessors/ConfigurationExtend.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { - IApiExtend, - IExternalComponentsExtend, - IHttpExtend, - IOutboundCommunicationProviderExtend, - ISchedulerExtend, - ISettingsExtend, - ISlashCommandsExtend, - IUIExtend, - IVideoConfProvidersExtend, -} from '@rocket.chat/apps-engine/definition/accessors'; - -import { ConfigurationExtend } from '../../../src/server/accessors'; - -describe('ConfigurationExtend', () => { - it('useConfigurationExtend', () => { - const he = {} as IHttpExtend; - const se = {} as ISettingsExtend; - const sce = {} as ISlashCommandsExtend; - const api = {} as IApiExtend; - const externalComponent = {} as IExternalComponentsExtend; - const schedulerExtend = {} as ISchedulerExtend; - const uiExtend = {} as IUIExtend; - const vcProvidersExtend = {} as IVideoConfProvidersExtend; - const outboundCommunication = {} as IOutboundCommunicationProviderExtend; - - assert.doesNotThrow( - () => - new ConfigurationExtend(he, se, sce, api, externalComponent, schedulerExtend, uiExtend, vcProvidersExtend, outboundCommunication), - ); - - const ce = new ConfigurationExtend( - he, - se, - sce, - api, - externalComponent, - schedulerExtend, - uiExtend, - vcProvidersExtend, - outboundCommunication, - ); - assert.ok(ce.http !== undefined); - assert.ok(ce.settings !== undefined); - assert.ok(ce.slashCommands !== undefined); - assert.ok(ce.api !== undefined); - assert.ok(ce.externalComponents !== undefined); - assert.ok(ce.scheduler !== undefined); - assert.ok(ce.ui !== undefined); - assert.ok(ce.videoConfProviders !== undefined); - assert.ok(ce.outboundCommunication !== undefined); - }); -}); diff --git a/packages/apps/tests/server/accessors/ConfigurationModify.test.ts b/packages/apps/tests/server/accessors/ConfigurationModify.test.ts deleted file mode 100644 index 96d8439638d7f..0000000000000 --- a/packages/apps/tests/server/accessors/ConfigurationModify.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it, beforeEach } from 'node:test'; - -import type { ISchedulerModify, IServerSettingsModify, ISlashCommandsModify } from '@rocket.chat/apps-engine/definition/accessors'; - -import { ConfigurationModify } from '../../../src/server/accessors'; - -describe('ConfigurationModify', () => { - let ssm: IServerSettingsModify; - let scm: ISlashCommandsModify; - let scheduler: ISchedulerModify; - - beforeEach(() => { - ssm = {} as IServerSettingsModify; - scm = {} as ISlashCommandsModify; - scheduler = {} as ISchedulerModify; - }); - - it('useConfigurationModify', () => { - assert.doesNotThrow(() => new ConfigurationModify(ssm, scm, scheduler)); - - const sm = new ConfigurationModify(ssm, scm, scheduler); - assert.strictEqual(sm.serverSettings, ssm); - assert.strictEqual(sm.slashCommands, scm); - assert.strictEqual(sm.scheduler, scheduler); - }); -}); diff --git a/packages/apps/tests/server/accessors/EnvironmentRead.test.ts b/packages/apps/tests/server/accessors/EnvironmentRead.test.ts deleted file mode 100644 index df41ac7a72989..0000000000000 --- a/packages/apps/tests/server/accessors/EnvironmentRead.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { IEnvironmentalVariableRead, IServerSettingRead, ISettingRead } from '@rocket.chat/apps-engine/definition/accessors'; - -import { EnvironmentRead } from '../../../src/server/accessors'; - -describe('EnvironmentRead', () => { - it('useEnvironmentRead', () => { - const evr = {} as IEnvironmentalVariableRead; - const ssr = {} as IServerSettingRead; - const sr = {} as ISettingRead; - - assert.doesNotThrow(() => new EnvironmentRead(sr, ssr, evr)); - - const er = new EnvironmentRead(sr, ssr, evr); - assert.ok(er.getSettings() !== undefined); - assert.ok(er.getServerSettings() !== undefined); - assert.ok(er.getEnvironmentVariables() !== undefined); - }); -}); diff --git a/packages/apps/tests/server/accessors/EnvironmentWrite.test.ts b/packages/apps/tests/server/accessors/EnvironmentWrite.test.ts deleted file mode 100644 index b7f2ce4ae8d78..0000000000000 --- a/packages/apps/tests/server/accessors/EnvironmentWrite.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { IServerSettingUpdater, ISettingUpdater } from '@rocket.chat/apps-engine/definition/accessors'; - -import { EnvironmentWrite } from '../../../src/server/accessors'; - -describe('EnvironmentWrite', () => { - it('useEnvironmentWrite', () => { - const sr = {} as ISettingUpdater; - const serverSettings = {} as IServerSettingUpdater; - - assert.doesNotThrow(() => new EnvironmentWrite(sr, serverSettings)); - - const er = new EnvironmentWrite(sr, serverSettings); - assert.ok(er.getSettings() !== undefined); - assert.ok(er.getServerSettings() !== undefined); - }); -}); diff --git a/packages/apps/tests/server/accessors/EnvironmentalVariableRead.test.ts b/packages/apps/tests/server/accessors/EnvironmentalVariableRead.test.ts deleted file mode 100644 index 423a6ff9036f4..0000000000000 --- a/packages/apps/tests/server/accessors/EnvironmentalVariableRead.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import { EnvironmentalVariableRead } from '../../../src/server/accessors'; -import type { EnvironmentalVariableBridge } from '../../../src/server/bridges'; - -describe('EnvironmentalVariableRead', () => { - it('useEnvironmentalVariableRead', async () => { - const mockEnvVarBridge = { - doGetValueByName(name: string, appId: string): Promise { - return Promise.resolve('value'); - }, - doIsReadable(name: string, appId: string): Promise { - return Promise.resolve(true); - }, - doIsSet(name: string, appId: string): Promise { - return Promise.resolve(false); - }, - } as EnvironmentalVariableBridge; - - assert.doesNotThrow(() => new EnvironmentalVariableRead(mockEnvVarBridge, 'testing')); - - const evr = new EnvironmentalVariableRead(mockEnvVarBridge, 'testing'); - assert.strictEqual(await evr.getValueByName('testing'), 'value'); - assert.ok(await evr.isReadable('testing')); - assert.ok(!(await evr.isSet('testing2'))); - }); -}); diff --git a/packages/apps/tests/server/accessors/Http.test.ts b/packages/apps/tests/server/accessors/Http.test.ts deleted file mode 100644 index 69d5ffd94afdb..0000000000000 --- a/packages/apps/tests/server/accessors/Http.test.ts +++ /dev/null @@ -1,155 +0,0 @@ -import * as assert from 'node:assert'; -import { afterEach, beforeEach, describe, it, mock } from 'node:test'; - -import type { - IHttpExtend, - IHttpPreRequestHandler, - IHttpPreResponseHandler, - IHttpRequest, - IHttpResponse, - IPersistence, - IRead, -} from '@rocket.chat/apps-engine/definition/accessors'; - -import { Http, HttpExtend } from '../../../src/server/accessors'; -import type { AppBridges, HttpBridge, IHttpBridgeRequestInfo } from '../../../src/server/bridges'; -import type { AppAccessorManager } from '../../../src/server/managers'; - -describe('Http', () => { - let mockAppId: string; - let mockHttpBridge: HttpBridge; - let mockAppBridge: AppBridges; - let mockHttpExtender: IHttpExtend; - let mockReader: IRead; - let mockPersis: IPersistence; - let mockAccessorManager: AppAccessorManager; - let mockPreRequestHandler: IHttpPreRequestHandler; - let mockPreResponseHandler: IHttpPreResponseHandler; - let mockResponse: IHttpResponse; - - beforeEach(() => { - mockAppId = 'testing-app'; - - mockResponse = { statusCode: 200 } as IHttpResponse; - const res = mockResponse; - mockHttpBridge = { - doCall(info: IHttpBridgeRequestInfo): Promise { - return Promise.resolve(res); - }, - } as HttpBridge; - - const httpBridge = mockHttpBridge; - mockAppBridge = { - getHttpBridge(): HttpBridge { - return httpBridge; - }, - } as AppBridges; - - mockHttpExtender = new HttpExtend(); - - mockReader = {} as IRead; - mockPersis = {} as IPersistence; - const reader = mockReader; - const persis = mockPersis; - mockAccessorManager = { - getReader(appId: string): IRead { - return reader; - }, - getPersistence(appId: string): IPersistence { - return persis; - }, - } as AppAccessorManager; - - mockPreRequestHandler = { - executePreHttpRequest(url: string, request: IHttpRequest, read: IRead, persistence: IPersistence): Promise { - return Promise.resolve(request); - }, - } as IHttpPreRequestHandler; - - mockPreResponseHandler = { - executePreHttpResponse(response: IHttpResponse, read: IRead, persistence: IPersistence): Promise { - return Promise.resolve(response); - }, - } as IHttpPreResponseHandler; - }); - - afterEach(() => { - mock.restoreAll(); - }); - - it('useHttp', async () => { - assert.doesNotThrow(() => new Http(mockAccessorManager, mockAppBridge, mockHttpExtender, mockAppId)); - - const http = new Http(mockAccessorManager, mockAppBridge, mockHttpExtender, mockAppId); - - const doCallSpy = mock.method(mockHttpBridge, 'doCall'); - const preRequestSpy = mock.method(mockPreRequestHandler, 'executePreHttpRequest'); - const preResponseSpy = mock.method(mockPreResponseHandler, 'executePreHttpResponse'); - - assert.ok((await http.get('url-here')) !== undefined); - assert.ok((await http.post('url-here')) !== undefined); - assert.ok((await http.put('url-here')) !== undefined); - assert.ok((await http.del('url-here')) !== undefined); - assert.ok((await http.get('url-here', { headers: {}, params: {} })) !== undefined); - - const request1 = {} as IHttpRequest; - mockHttpExtender.provideDefaultHeader('Auth-Token', 'Bearer asdfasdf'); - assert.ok((await http.post('url-here', request1)) !== undefined); - assert.strictEqual(request1.headers['Auth-Token'], 'Bearer asdfasdf'); - request1.headers['Auth-Token'] = 'mine'; - assert.ok((await http.put('url-here', request1)) !== undefined); // Check that the default doesn't override provided - assert.strictEqual(request1.headers['Auth-Token'], 'mine'); - - const request2 = {} as IHttpRequest; - mockHttpExtender.provideDefaultParam('count', '20'); - assert.ok((await http.del('url-here', request2)) !== undefined); - assert.strictEqual(request2.params.count, '20'); - request2.params.count = '50'; - assert.ok((await http.get('url-here', request2)) !== undefined); // Check that the default doesn't override provided - assert.strictEqual(request2.params.count, '50'); - - mockHttpExtender.providePreRequestHandler(mockPreRequestHandler); - const request3 = {} as IHttpRequest; - assert.ok((await http.post('url-here', request3)) !== undefined); - assert.strictEqual(preRequestSpy.mock.calls.length, 1); - assert.deepStrictEqual(preRequestSpy.mock.calls[0].arguments, ['url-here', request3, mockReader, mockPersis]); - (mockHttpExtender as any).requests = []; - - mockHttpExtender.providePreResponseHandler(mockPreResponseHandler); - assert.ok((await http.post('url-here')) !== undefined); - assert.strictEqual(preResponseSpy.mock.calls.length, 1); - assert.deepStrictEqual(preResponseSpy.mock.calls[0].arguments, [mockResponse, mockReader, mockPersis]); - - assert.strictEqual(doCallSpy.mock.calls.length, 11); - }); - - it('ssrfValidationOption', async () => { - const http = new Http(mockAccessorManager, mockAppBridge, mockHttpExtender, mockAppId); - - let capturedInfo: IHttpBridgeRequestInfo | undefined; - - // Override doCall to capture the info parameter - const originalDoCall = mockHttpBridge.doCall.bind(mockHttpBridge); - mockHttpBridge.doCall = async (info: IHttpBridgeRequestInfo) => { - capturedInfo = info; - return originalDoCall(info); - }; - - // Test with ssrfValidation enabled - await http.get('url-here', { ssrfValidation: true }); - assert.ok(capturedInfo !== undefined); - assert.strictEqual(capturedInfo!.request.ssrfValidation, true); - - // Test with ssrfValidation disabled - await http.post('url-here', { ssrfValidation: false }); - assert.strictEqual(capturedInfo!.request.ssrfValidation, false); - - // Test with ssrfValidation undefined (default) - await http.put('url-here', {}); - assert.strictEqual(capturedInfo!.request.ssrfValidation, undefined); - - // Test with no options - await http.del('url-here'); - assert.strictEqual(capturedInfo!.request.ssrfValidation, undefined); - }); -}); diff --git a/packages/apps/tests/server/accessors/HttpExtend.test.ts b/packages/apps/tests/server/accessors/HttpExtend.test.ts deleted file mode 100644 index 4f80e69e13924..0000000000000 --- a/packages/apps/tests/server/accessors/HttpExtend.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { IHttpPreRequestHandler, IHttpPreResponseHandler } from '@rocket.chat/apps-engine/definition/accessors'; - -import { HttpExtend } from '../../../src/server/accessors'; - -describe('HttpExtend', () => { - it('basicHttpExtend', () => { - assert.doesNotThrow(() => new HttpExtend()); - - const he = new HttpExtend(); - assert.deepStrictEqual(he.getDefaultHeaders(), new Map()); - assert.deepStrictEqual(he.getDefaultParams(), new Map()); - assert.strictEqual(he.getPreRequestHandlers().length, 0); - assert.strictEqual(he.getPreResponseHandlers().length, 0); - }); - - it('defaultHeadersInHttpExtend', () => { - const he = new HttpExtend(); - - assert.doesNotThrow(() => he.provideDefaultHeader('Auth', 'token')); - assert.strictEqual(he.getDefaultHeaders().size, 1); - assert.strictEqual(he.getDefaultHeaders().get('Auth'), 'token'); - - assert.doesNotThrow(() => - he.provideDefaultHeaders({ - Auth: 'token2', - Another: 'thing', - }), - ); - assert.strictEqual(he.getDefaultHeaders().size, 2); - assert.strictEqual(he.getDefaultHeaders().get('Auth'), 'token2'); - assert.strictEqual(he.getDefaultHeaders().get('Another'), 'thing'); - }); - - it('defaultParamsInHttpExtend', () => { - const he = new HttpExtend(); - - assert.doesNotThrow(() => he.provideDefaultParam('id', 'abcdefg')); - assert.strictEqual(he.getDefaultParams().size, 1); - assert.strictEqual(he.getDefaultParams().get('id'), 'abcdefg'); - - assert.doesNotThrow(() => - he.provideDefaultParams({ - id: 'zyxwvu', - count: '4', - }), - ); - assert.strictEqual(he.getDefaultParams().size, 2); - assert.strictEqual(he.getDefaultParams().get('id'), 'zyxwvu'); - assert.strictEqual(he.getDefaultParams().get('count'), '4'); - }); - - it('preRequestHandlersInHttpExtend', () => { - const he = new HttpExtend(); - - const preRequestHandler: IHttpPreRequestHandler = { - executePreHttpRequest: function _thing(url, req) { - return new Promise((resolve) => resolve(req)); - }, - }; - - assert.doesNotThrow(() => he.providePreRequestHandler(preRequestHandler)); - assert.ok(he.getPreRequestHandlers().length > 0); - }); - - it('preResponseHandlersInHttpExtend', () => { - const he = new HttpExtend(); - - const preResponseHandler: IHttpPreResponseHandler = { - executePreHttpResponse: function _thing(res) { - return new Promise((resolve) => resolve(res)); - }, - }; - - assert.doesNotThrow(() => he.providePreResponseHandler(preResponseHandler)); - assert.ok(he.getPreResponseHandlers().length > 0); - }); -}); diff --git a/packages/apps/tests/server/accessors/MessageBuilder.test.ts b/packages/apps/tests/server/accessors/MessageBuilder.test.ts deleted file mode 100644 index e73d04b856874..0000000000000 --- a/packages/apps/tests/server/accessors/MessageBuilder.test.ts +++ /dev/null @@ -1,134 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -import { MessageBuilder, UserBuilder } from '../../../src/server/accessors'; -import { TestData } from '../../test-data/utilities'; - -describe('MessageBuilder', () => { - it('basicMessageBuilder', () => { - assert.doesNotThrow(() => new MessageBuilder()); - assert.doesNotThrow(() => new MessageBuilder(TestData.getMessage())); - }); - - it('settingOnMessageBuilder', () => { - const mbOnce = new MessageBuilder(); - - // setData just replaces the passed in object, so let's treat it differently - assert.strictEqual(mbOnce.setData({ text: 'hello' } as IMessage), mbOnce); - assert.strictEqual((mbOnce as any).msg.text, 'hello'); - - const mbUpdate = new MessageBuilder(); - const editor = new UserBuilder(); - editor.setUsername('username'); - editor.setDisplayName('name'); - - // setUpdateData keeps the ID passed in the message object, so let's treat it differently - assert.strictEqual(mbUpdate.setUpdateData({ text: 'hello', id: 'messageID' } as IMessage, editor.getUser() as IUser), mbUpdate); - assert.strictEqual((mbUpdate as any).msg.text, 'hello'); - assert.strictEqual((mbUpdate as any).msg.id, 'messageID'); - - const msg: IMessage = {} as IMessage; - const mb = new MessageBuilder(msg); - - assert.strictEqual(mb.setThreadId('a random thread id'), mb); - assert.strictEqual(msg.threadId, 'a random thread id'); - assert.strictEqual(mb.getThreadId(), 'a random thread id'); - - const room = TestData.getRoom(); - assert.strictEqual(mb.setRoom(room), mb); - assert.deepStrictEqual(msg.room, room); - assert.deepStrictEqual(mb.getRoom(), room); - - const sender = TestData.getUser(); - assert.strictEqual(mb.setSender(sender), mb); - assert.deepStrictEqual(msg.sender, sender); - assert.deepStrictEqual(mb.getSender(), sender); - - assert.strictEqual(mb.setText('testing, yo!'), mb); - assert.deepStrictEqual(msg.text, 'testing, yo!'); - assert.deepStrictEqual(mb.getText(), 'testing, yo!'); - - assert.strictEqual(mb.setEmojiAvatar(':ghost:'), mb); - assert.deepStrictEqual(msg.emoji, ':ghost:'); - assert.deepStrictEqual(mb.getEmojiAvatar(), ':ghost:'); - - assert.strictEqual(mb.setAvatarUrl('https://rocket.chat/'), mb); - assert.deepStrictEqual(msg.avatarUrl, 'https://rocket.chat/'); - assert.deepStrictEqual(mb.getAvatarUrl(), 'https://rocket.chat/'); - - assert.strictEqual(mb.setUsernameAlias('Some Bot'), mb); - assert.deepStrictEqual(msg.alias, 'Some Bot'); - assert.deepStrictEqual(mb.getUsernameAlias(), 'Some Bot'); - - assert.strictEqual(msg.attachments, undefined); - assert.strictEqual(mb.getAttachments(), undefined); - assert.strictEqual(mb.addAttachment({ color: '#0ff' }), mb); - assert.ok(msg.attachments !== undefined); - assert.ok(mb.getAttachments() !== undefined); - assert.ok(msg.attachments.length > 0); - assert.ok(mb.getAttachments().length > 0); - - assert.deepStrictEqual(msg.attachments[0].color, '#0ff'); - assert.deepStrictEqual(mb.getAttachments()[0].color, '#0ff'); - - assert.strictEqual(mb.setAttachments([]), mb); - assert.strictEqual(msg.attachments.length, 0); - assert.strictEqual(mb.getAttachments().length, 0); - - delete msg.attachments; - assert.throws(() => mb.replaceAttachment(1, {}), { name: 'Error', message: 'No attachment found at the index of "1" to replace.' }); - assert.strictEqual(mb.addAttachment({}), mb); - assert.strictEqual(mb.replaceAttachment(0, { color: '#f0f' }), mb); - assert.deepStrictEqual(msg.attachments[0].color, '#f0f'); - assert.deepStrictEqual(mb.getAttachments()[0].color, '#f0f'); - - assert.strictEqual(mb.removeAttachment(0), mb); - assert.strictEqual(msg.attachments.length, 0); - assert.strictEqual(mb.getAttachments().length, 0); - - delete msg.attachments; - assert.throws(() => mb.removeAttachment(4), { name: 'Error', message: 'No attachment found at the index of "4" to remove.' }); - - const msgEditor = TestData.getUser('msg-editor-id'); - assert.strictEqual(mb.setEditor(msgEditor), mb); - assert.ok(msg.editor !== undefined); - assert.ok(mb.getEditor() !== undefined); - assert.deepStrictEqual(msg.editor.id, 'msg-editor-id'); - assert.deepStrictEqual(mb.getEditor().id, 'msg-editor-id'); - - assert.strictEqual(mb.getMessage(), msg); - delete msg.room; - assert.throws(() => mb.getMessage(), { name: 'Error', message: 'The "room" property is required.' }); - - assert.strictEqual(mb.setGroupable(true), mb); - assert.deepStrictEqual(msg.groupable, true); - assert.deepStrictEqual(mb.getGroupable(), true); - - assert.strictEqual(mb.setGroupable(false), mb); - assert.deepStrictEqual(msg.groupable, false); - assert.deepStrictEqual(mb.getGroupable(), false); - - assert.strictEqual(mb.setParseUrls(true), mb); - assert.deepStrictEqual(msg.parseUrls, true); - assert.deepStrictEqual(mb.getParseUrls(), true); - - assert.strictEqual(mb.setParseUrls(false), mb); - assert.deepStrictEqual(msg.parseUrls, false); - assert.deepStrictEqual(mb.getParseUrls(), false); - - assert.strictEqual(mb.addCustomField('thing', 'value'), mb); - assert.ok(msg.customFields !== undefined); - assert.strictEqual(msg.customFields.thing, 'value'); - assert.throws(() => mb.addCustomField('thing', 'second'), { - name: 'Error', - message: 'The message already contains a custom field by the key: thing', - }); - assert.throws(() => mb.addCustomField('thing.', 'second'), { - name: 'Error', - message: 'The given key contains a period, which is not allowed. Key: thing.', - }); - }); -}); diff --git a/packages/apps/tests/server/accessors/MessageExtender.test.ts b/packages/apps/tests/server/accessors/MessageExtender.test.ts deleted file mode 100644 index 2031e41598b1d..0000000000000 --- a/packages/apps/tests/server/accessors/MessageExtender.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; - -import { MessageExtender } from '../../../src/server/accessors'; -import { TestData } from '../../test-data/utilities'; - -describe('MessageExtender', () => { - it('basicMessageExtender', () => { - assert.doesNotThrow(() => new MessageExtender({} as IMessage)); - assert.doesNotThrow(() => new MessageExtender(TestData.getMessage())); - }); - - it('usingMessageExtender', () => { - const msg: IMessage = {} as IMessage; - const me = new MessageExtender(msg); - - assert.ok(msg.attachments !== undefined); - assert.strictEqual(msg.attachments.length, 0); - assert.strictEqual(me.addCustomField('thing', 'value'), me); - assert.ok(msg.customFields !== undefined); - assert.strictEqual(msg.customFields.thing, 'value'); - assert.throws(() => me.addCustomField('thing', 'second'), { - name: 'Error', - message: 'The message already contains a custom field by the key: thing', - }); - assert.throws(() => me.addCustomField('thing.', 'second'), { - name: 'Error', - message: 'The given key contains a period, which is not allowed. Key: thing.', - }); - - assert.strictEqual(me.addAttachment({}), me); - assert.strictEqual(msg.attachments.length, 1); - assert.strictEqual(me.addAttachments([{ collapsed: true }, { color: '#f00' }]), me); - assert.strictEqual(msg.attachments.length, 3); - - assert.notStrictEqual(me.getMessage(), msg); - assert.deepStrictEqual(me.getMessage(), msg); - }); -}); diff --git a/packages/apps/tests/server/accessors/MessageRead.test.ts b/packages/apps/tests/server/accessors/MessageRead.test.ts deleted file mode 100644 index 30ab6affa4df6..0000000000000 --- a/packages/apps/tests/server/accessors/MessageRead.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; - -import { MessageRead } from '../../../src/server/accessors'; -import type { MessageBridge } from '../../../src/server/bridges'; -import { TestData } from '../../test-data/utilities'; - -describe('MessageRead', () => { - const msg = TestData.getMessage(); - - const mockMsgBridgeWithMsg = { - doGetById(id: string, appId: string): Promise { - return Promise.resolve(msg); - }, - } as MessageBridge; - - const mockMsgBridgeNoMsg = { - doGetById(id: string, appId: string) { - return Promise.resolve(undefined); - }, - } as MessageBridge; - - it('expectDataFromMessageRead', async () => { - assert.doesNotThrow(() => new MessageRead(mockMsgBridgeWithMsg, 'testing-app')); - - const mr = new MessageRead(mockMsgBridgeWithMsg, 'testing-app'); - - assert.ok((await mr.getById('fake')) !== undefined); - assert.deepStrictEqual(await mr.getById('fake'), msg); - - assert.ok((await mr.getSenderUser('fake')) !== undefined); - assert.deepStrictEqual(await mr.getSenderUser('fake'), msg.sender); - - assert.ok((await mr.getRoom('fake')) !== undefined); - assert.deepStrictEqual(await mr.getRoom('fake'), msg.room); - }); - - it('doNotExpectDataFromMessageRead', async () => { - assert.doesNotThrow(() => new MessageRead(mockMsgBridgeNoMsg, 'testing')); - - const nomr = new MessageRead(mockMsgBridgeNoMsg, 'testing'); - assert.strictEqual(await nomr.getById('fake'), undefined); - assert.strictEqual(await nomr.getSenderUser('fake'), undefined); - assert.strictEqual(await nomr.getRoom('fake'), undefined); - }); -}); diff --git a/packages/apps/tests/server/accessors/Modify.test.ts b/packages/apps/tests/server/accessors/Modify.test.ts deleted file mode 100644 index 982c48419d39f..0000000000000 --- a/packages/apps/tests/server/accessors/Modify.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import { Modify } from '../../../src/server/accessors'; -import type { - AppBridges, - MessageBridge, - ModerationBridge, - SchedulerBridge, - UiInteractionBridge, - UserBridge, -} from '../../../src/server/bridges'; -import type { OAuthAppsBridge } from '../../../src/server/bridges/OAuthAppsBridge'; - -describe('Modify', () => { - it('useModify', () => { - const mockAppBridges = { - getUserBridge(): UserBridge { - return {} as UserBridge; - }, - getMessageBridge(): MessageBridge { - return {} as MessageBridge; - }, - getUiInteractionBridge(): UiInteractionBridge { - return {} as UiInteractionBridge; - }, - getSchedulerBridge() { - return {} as SchedulerBridge; - }, - getOAuthAppsBridge() { - return {} as OAuthAppsBridge; - }, - getModerationBridge() { - return {} as ModerationBridge; - }, - } as AppBridges; - - assert.doesNotThrow(() => new Modify(mockAppBridges, 'testing')); - - const md = new Modify(mockAppBridges, 'testing'); - assert.ok(md.getCreator() !== undefined); - assert.ok(md.getExtender() !== undefined); - assert.ok(md.getNotifier() !== undefined); - assert.ok(md.getUpdater() !== undefined); - }); -}); diff --git a/packages/apps/tests/server/accessors/ModifyCreator.test.ts b/packages/apps/tests/server/accessors/ModifyCreator.test.ts deleted file mode 100644 index ea3d49c15894b..0000000000000 --- a/packages/apps/tests/server/accessors/ModifyCreator.test.ts +++ /dev/null @@ -1,130 +0,0 @@ -import * as assert from 'node:assert'; -import { afterEach, beforeEach, describe, it, mock } from 'node:test'; - -import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; -import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; -import { RoomType } from '@rocket.chat/apps-engine/definition/rooms'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; -import { UserStatusConnection, UserType } from '@rocket.chat/apps-engine/definition/users'; - -import { ModifyCreator } from '../../../src/server/accessors'; -import type { AppBridges, MessageBridge, RoomBridge, UserBridge } from '../../../src/server/bridges'; -import { TestData } from '../../test-data/utilities'; - -describe('ModifyCreator', () => { - let mockAppId: string; - let mockRoomBridge: RoomBridge; - let mockMessageBridge: MessageBridge; - let mockAppBridge: AppBridges; - let mockAppUser: IUser; - let mockUserBridge: UserBridge; - - beforeEach(() => { - mockAppId = 'testing-app'; - - mockAppUser = { - id: 'mockAppUser', - isEnabled: true, - name: 'mockAppUser', - roles: ['app'], - status: 'online', - statusConnection: UserStatusConnection.UNDEFINED, - type: UserType.APP, - username: 'mockAppUser', - emails: [], - utcOffset: -5, - createdAt: new Date(), - updatedAt: new Date(), - lastLoginAt: new Date(), - }; - - mockRoomBridge = { - doCreate(room: IRoom, members: Array, appId: string): Promise { - return Promise.resolve('roomId'); - }, - } as RoomBridge; - - mockMessageBridge = { - doCreate(msg: IMessage, appId: string): Promise { - return Promise.resolve('msgId'); - }, - } as MessageBridge; - - const appUser = mockAppUser; - mockUserBridge = { - doGetAppUser: (appId: string) => { - return Promise.resolve(appUser); - }, - } as UserBridge; - - const msgBridge = mockMessageBridge; - const rmBridge = mockRoomBridge; - const userBridge = mockUserBridge; - mockAppBridge = { - getMessageBridge: () => msgBridge, - getRoomBridge: () => rmBridge, - getUserBridge: () => userBridge, - } as AppBridges; - }); - - afterEach(() => { - mock.restoreAll(); - }); - - it('basicModifyCreator', async () => { - assert.doesNotThrow(() => new ModifyCreator(mockAppBridge, mockAppId)); - - const mc = new ModifyCreator(mockAppBridge, mockAppId); - assert.ok(mc.startMessage() !== undefined); - assert.ok(mc.startMessage({ id: 'value' } as IMessage) !== undefined); - assert.ok(mc.startRoom() !== undefined); - assert.ok(mc.startRoom({ id: 'value' } as IRoom) !== undefined); - - assert.throws(() => mc.finish({} as any), { name: 'Error', message: 'Invalid builder passed to the ModifyCreator.finish function.' }); - }); - - it('msgModifyCreator', async () => { - const mc = new ModifyCreator(mockAppBridge, mockAppId); - - const msg = {} as IMessage; - const msgBd = mc.startMessage(msg); - await assert.rejects(() => mc.finish(msgBd), { name: 'Error', message: 'The "room" property is required.' }); - msgBd.setRoom(TestData.getRoom()); - assert.ok(msg.room !== undefined); - await assert.doesNotReject(() => mc.finish(msgBd)); - msgBd.setSender(TestData.getUser()); - assert.ok(msg.sender !== undefined); - - const msgBriSpy = mock.method(mockMessageBridge, 'doCreate'); - assert.strictEqual(await mc.finish(msgBd), 'msgId'); - assert.strictEqual(msgBriSpy.mock.calls.length, 1); - assert.deepStrictEqual(msgBriSpy.mock.calls[0].arguments, [msg, mockAppId]); - }); - - it('roomModifyCreator', async () => { - const mc = new ModifyCreator(mockAppBridge, mockAppId); - - const room = {} as IRoom; - const roomBd = mc.startRoom(room); - assert.throws(() => mc.finish(roomBd), { name: 'Error', message: 'Invalid type assigned to the room.' }); - roomBd.setType(RoomType.CHANNEL); - assert.strictEqual(room.type, RoomType.CHANNEL); - - assert.throws(() => mc.finish(roomBd), { name: 'Error', message: 'Invalid creator assigned to the room.' }); - roomBd.setCreator(TestData.getUser()); - assert.ok(room.creator !== undefined); - - assert.throws(() => mc.finish(roomBd), { name: 'Error', message: 'Invalid slugifiedName assigned to the room.' }); - roomBd.setSlugifiedName('testing-room'); - assert.strictEqual(room.slugifiedName, 'testing-room'); - - assert.throws(() => mc.finish(roomBd), { name: 'Error', message: 'Invalid displayName assigned to the room.' }); - roomBd.setDisplayName('Display Name'); - assert.strictEqual(room.displayName, 'Display Name'); - - const roomBriSpy = mock.method(mockRoomBridge, 'doCreate'); - assert.strictEqual(await mc.finish(roomBd), 'roomId'); - assert.strictEqual(roomBriSpy.mock.calls.length, 1); - assert.deepStrictEqual(roomBriSpy.mock.calls[0].arguments, [room, roomBd.getMembersToBeAddedUsernames(), mockAppId]); - }); -}); diff --git a/packages/apps/tests/server/accessors/ModifyExtender.test.ts b/packages/apps/tests/server/accessors/ModifyExtender.test.ts deleted file mode 100644 index f355661c42cd6..0000000000000 --- a/packages/apps/tests/server/accessors/ModifyExtender.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import * as assert from 'node:assert'; -import { afterEach, beforeEach, describe, it, mock } from 'node:test'; - -import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; -import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; - -import { ModifyExtender } from '../../../src/server/accessors'; -import type { AppBridges, MessageBridge, RoomBridge } from '../../../src/server/bridges'; -import { TestData } from '../../test-data/utilities'; - -describe('ModifyExtender', () => { - let mockAppId: string; - let mockRoomBridge: RoomBridge; - let mockMessageBridge: MessageBridge; - let mockAppBridge: AppBridges; - - beforeEach(() => { - mockAppId = 'testing-app'; - - mockRoomBridge = { - doGetById(roomId: string, appId: string): Promise { - return Promise.resolve(TestData.getRoom()); - }, - doUpdate(room: IRoom, members: Array, appId: string): Promise { - return Promise.resolve(); - }, - } as RoomBridge; - - mockMessageBridge = { - doGetById(msgId: string, appId: string): Promise { - return Promise.resolve(TestData.getMessage()); - }, - doUpdate(msg: IMessage, appId: string): Promise { - return Promise.resolve(); - }, - } as MessageBridge; - - const rmBridge = mockRoomBridge; - const msgBridge = mockMessageBridge; - mockAppBridge = { - getMessageBridge() { - return msgBridge; - }, - getRoomBridge() { - return rmBridge; - }, - } as AppBridges; - }); - - afterEach(() => { - mock.restoreAll(); - }); - - it('useModifyExtender', async () => { - assert.doesNotThrow(() => new ModifyExtender(mockAppBridge, mockAppId)); - - const me = new ModifyExtender(mockAppBridge, mockAppId); - - const doGetByIdRoomSpy = mock.method(mockRoomBridge, 'doGetById'); - const doUpdateRoomSpy = mock.method(mockRoomBridge, 'doUpdate'); - const doGetByIdMsgSpy = mock.method(mockMessageBridge, 'doGetById'); - const doUpdateMsgSpy = mock.method(mockMessageBridge, 'doUpdate'); - - assert.ok((await me.extendRoom('roomId', TestData.getUser())) !== undefined); - assert.strictEqual(doGetByIdRoomSpy.mock.calls.length, 1); - assert.deepStrictEqual(doGetByIdRoomSpy.mock.calls[0].arguments, ['roomId', mockAppId]); - assert.ok((await me.extendMessage('msgId', TestData.getUser())) !== undefined); - assert.strictEqual(doGetByIdMsgSpy.mock.calls.length, 1); - assert.deepStrictEqual(doGetByIdMsgSpy.mock.calls[0].arguments, ['msgId', mockAppId]); - - assert.throws(() => me.finish({} as any), { name: 'Error', message: 'Invalid extender passed to the ModifyExtender.finish function.' }); - assert.strictEqual(await me.finish(await me.extendRoom('roomId', TestData.getUser())), undefined); - assert.ok(doUpdateRoomSpy.mock.calls.length > 0); - assert.strictEqual(await me.finish(await me.extendMessage('msgId', TestData.getUser())), undefined); - assert.ok(doUpdateMsgSpy.mock.calls.length > 0); - }); -}); diff --git a/packages/apps/tests/server/accessors/ModifyUpdater.test.ts b/packages/apps/tests/server/accessors/ModifyUpdater.test.ts deleted file mode 100644 index e3c31bb450ddf..0000000000000 --- a/packages/apps/tests/server/accessors/ModifyUpdater.test.ts +++ /dev/null @@ -1,140 +0,0 @@ -import * as assert from 'node:assert'; -import { afterEach, beforeEach, describe, it, mock } from 'node:test'; - -import type { ILivechatRoom } from '@rocket.chat/apps-engine/definition/livechat/ILivechatRoom'; -import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; -import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; -import { RoomType } from '@rocket.chat/apps-engine/definition/rooms'; - -import { MessageBuilder, ModifyUpdater, RoomBuilder } from '../../../src/server/accessors'; -import type { AppBridges, MessageBridge, RoomBridge } from '../../../src/server/bridges'; -import { TestData } from '../../test-data/utilities'; - -describe('ModifyUpdater', () => { - let mockAppId: string; - let mockRoomBridge: RoomBridge; - let mockMessageBridge: MessageBridge; - let mockAppBridge: AppBridges; - - beforeEach(() => { - mockAppId = 'testing-app'; - - mockRoomBridge = { - doGetById(roomId: string, appId: string): Promise { - return Promise.resolve(TestData.getRoom()); - }, - doUpdate(room: IRoom, members: Array, appId: string): Promise { - return Promise.resolve(); - }, - } as RoomBridge; - - mockMessageBridge = { - doGetById(msgId: string, appId: string): Promise { - return Promise.resolve(TestData.getMessage()); - }, - doUpdate(msg: IMessage, appId: string): Promise { - return Promise.resolve(); - }, - } as MessageBridge; - - const rmBridge = mockRoomBridge; - const msgBridge = mockMessageBridge; - mockAppBridge = { - getMessageBridge() { - return msgBridge; - }, - getRoomBridge() { - return rmBridge; - }, - } as AppBridges; - }); - - afterEach(() => { - mock.restoreAll(); - }); - - it('basicModifyUpdater', async () => { - assert.doesNotThrow(() => new ModifyUpdater(mockAppBridge, mockAppId)); - - const mc = new ModifyUpdater(mockAppBridge, mockAppId); - assert.ok((await mc.message('msgId', TestData.getUser())) !== undefined); - assert.ok((await mc.room('roomId', TestData.getUser())) !== undefined); - - assert.throws(() => mc.finish({} as any), { - name: 'Error', - message: 'Invalid builder passed to the ModifyUpdater.finish function.', - }); - }); - - it('msgModifyUpdater', async () => { - const mc = new ModifyUpdater(mockAppBridge, mockAppId); - - const msg = {} as IMessage; - const msgBd = new MessageBuilder(msg); - assert.throws(() => mc.finish(msgBd), { name: 'Error', message: 'The "room" property is required.' }); - msgBd.setRoom(TestData.getRoom()); - assert.ok(msg.room !== undefined); - assert.throws(() => mc.finish(msgBd), { name: 'Error', message: "Invalid message, can't update a message without an id." }); - msg.id = 'testing-msg'; - assert.throws(() => mc.finish(msgBd), { name: 'Error', message: 'Invalid sender assigned to the message.' }); - msgBd.setSender(TestData.getUser()); - assert.ok(msg.sender !== undefined); - - const msgBriSpy = mock.method(mockMessageBridge, 'doUpdate'); - assert.strictEqual(await mc.finish(msgBd), undefined); - assert.strictEqual(msgBriSpy.mock.calls.length, 1); - assert.deepStrictEqual(msgBriSpy.mock.calls[0].arguments, [msg, mockAppId]); - }); - - it('roomModifyUpdater', async () => { - const mc = new ModifyUpdater(mockAppBridge, mockAppId); - - const room = {} as IRoom; - const roomBd = new RoomBuilder(room); - assert.throws(() => mc.finish(roomBd), { name: 'Error', message: 'Invalid room, can not update a room without an id.' }); - room.id = 'testing-room'; - - assert.throws(() => mc.finish(roomBd), { name: 'Error', message: 'Invalid type assigned to the room.' }); - roomBd.setType(RoomType.CHANNEL); - assert.strictEqual(room.type, RoomType.CHANNEL); - - assert.throws(() => mc.finish(roomBd), { name: 'Error', message: 'Invalid creator assigned to the room.' }); - roomBd.setCreator(TestData.getUser()); - assert.ok(room.creator !== undefined); - - assert.throws(() => mc.finish(roomBd), { name: 'Error', message: 'Invalid slugifiedName assigned to the room.' }); - roomBd.setSlugifiedName('testing-room'); - assert.strictEqual(room.slugifiedName, 'testing-room'); - - assert.throws(() => mc.finish(roomBd), { name: 'Error', message: 'Invalid displayName assigned to the room.' }); - roomBd.setDisplayName('Display Name'); - assert.strictEqual(room.displayName, 'Display Name'); - - const roomBriSpy = mock.method(mockRoomBridge, 'doUpdate'); - assert.strictEqual(await mc.finish(roomBd), undefined); - assert.strictEqual(roomBriSpy.mock.calls.length, 1); - assert.deepStrictEqual(roomBriSpy.mock.calls[0].arguments, [room, roomBd.getMembersToBeAddedUsernames(), mockAppId]); - }); - - it('livechatRoomModifyUpdater', async () => { - const mc = new ModifyUpdater(mockAppBridge, mockAppId); - - const room = {} as ILivechatRoom; - const roomBd = new RoomBuilder(room); - assert.throws(() => mc.finish(roomBd), { name: 'Error', message: 'Invalid room, can not update a room without an id.' }); - room.id = 'testing-room'; - - assert.throws(() => mc.finish(roomBd), { name: 'Error', message: 'Invalid type assigned to the room.' }); - roomBd.setType(RoomType.LIVE_CHAT); - assert.strictEqual(room.type, RoomType.LIVE_CHAT); - - assert.throws(() => mc.finish(roomBd), { name: 'Error', message: 'Invalid displayName assigned to the room.' }); - roomBd.setDisplayName('Display Name'); - assert.strictEqual(room.displayName, 'Display Name'); - - const roomBriSpy = mock.method(mockRoomBridge, 'doUpdate'); - assert.strictEqual(await mc.finish(roomBd), undefined); - assert.strictEqual(roomBriSpy.mock.calls.length, 1); - assert.deepStrictEqual(roomBriSpy.mock.calls[0].arguments, [room, roomBd.getMembersToBeAddedUsernames(), mockAppId]); - }); -}); diff --git a/packages/apps/tests/server/accessors/Notifier.test.ts b/packages/apps/tests/server/accessors/Notifier.test.ts deleted file mode 100644 index fd22099a3fdb4..0000000000000 --- a/packages/apps/tests/server/accessors/Notifier.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it, mock } from 'node:test'; - -import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; -import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -import { MessageBuilder, Notifier } from '../../../src/server/accessors'; -import type { MessageBridge, UserBridge } from '../../../src/server/bridges'; -import { TestData } from '../../test-data/utilities'; - -describe('Notifier', () => { - it('useNotifier', async () => { - const mockUserBridge = {} as UserBridge; - const mockMsgBridge = { - doNotifyUser(user: IUser, msg: IMessage, appId: string): Promise { - return Promise.resolve(); - }, - doNotifyRoom(room: IRoom, msg: IMessage, appId: string): Promise { - return Promise.resolve(); - }, - } as MessageBridge; - - assert.doesNotThrow(() => new Notifier(mockUserBridge, mockMsgBridge, 'testing')); - - const noti = new Notifier(mockUserBridge, mockMsgBridge, 'testing'); - - const doNotifyRoomSpy = mock.method(mockMsgBridge, 'doNotifyRoom'); - const doNotifyUserSpy = mock.method(mockMsgBridge, 'doNotifyUser'); - - const room = TestData.getRoom(); - const user = TestData.getUser(); - const roomMsg = TestData.getMessage(); - const userMsg = TestData.getMessage(); - - await assert.doesNotReject(() => noti.notifyRoom(room, roomMsg)); - assert.strictEqual(doNotifyRoomSpy.mock.calls.length, 1); - assert.strictEqual(doNotifyRoomSpy.mock.calls[0].arguments[0], room); - assert.strictEqual(doNotifyRoomSpy.mock.calls[0].arguments[1], roomMsg); - assert.strictEqual(doNotifyRoomSpy.mock.calls[0].arguments[2], 'testing'); - - await assert.doesNotReject(() => noti.notifyUser(user, userMsg)); - assert.strictEqual(doNotifyUserSpy.mock.calls.length, 1); - assert.strictEqual(doNotifyUserSpy.mock.calls[0].arguments[0], user); - assert.strictEqual(doNotifyUserSpy.mock.calls[0].arguments[1], userMsg); - assert.strictEqual(doNotifyUserSpy.mock.calls[0].arguments[2], 'testing'); - - assert.ok(noti.getMessageBuilder() instanceof MessageBuilder); - }); -}); diff --git a/packages/apps/tests/server/accessors/Persistence.test.ts b/packages/apps/tests/server/accessors/Persistence.test.ts deleted file mode 100644 index f101139363b2c..0000000000000 --- a/packages/apps/tests/server/accessors/Persistence.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import * as assert from 'node:assert'; -import { afterEach, beforeEach, describe, it, mock } from 'node:test'; - -import { RocketChatAssociationModel, RocketChatAssociationRecord } from '@rocket.chat/apps-engine/definition/metadata'; - -import { Persistence } from '../../../src/server/accessors'; -import type { PersistenceBridge } from '../../../src/server/bridges'; - -describe('Persistence', () => { - let mockAppId: string; - let mockPersisBridge: PersistenceBridge; - let mockAssoc: RocketChatAssociationRecord; - let data: object; - - beforeEach(() => { - mockAppId = 'testing-app'; - data = { hello: 'world' }; - - const theData = data; - mockPersisBridge = { - doCreate(d: any, appId: string): Promise { - return Promise.resolve('id'); - }, - doCreateWithAssociations(d: any, assocs: Array, appId: string): Promise { - return Promise.resolve('id2'); - }, - doUpdate(id: string, d: object, upsert: boolean, appId: string): Promise { - return Promise.resolve('id3'); - }, - doRemove(id: string, appId: string): Promise { - return Promise.resolve(theData); - }, - doRemoveByAssociations(assocs: Array, appId: string): Promise> { - return Promise.resolve([theData]); - }, - doUpdateByAssociations(associations: Array, d: object, upsert: boolean, appId: string): Promise { - return Promise.resolve('id4'); - }, - } as PersistenceBridge; - mockAssoc = new RocketChatAssociationRecord(RocketChatAssociationModel.USER, 'fake-id'); - }); - - afterEach(() => { - mock.restoreAll(); - }); - - it('usePersistenceAccessor', async () => { - assert.doesNotThrow(() => new Persistence(mockPersisBridge, mockAppId)); - - const sp1 = mock.method(mockPersisBridge, 'doCreate'); - const sp2 = mock.method(mockPersisBridge, 'doCreateWithAssociations'); - const sp3 = mock.method(mockPersisBridge, 'doUpdate'); - const sp4 = mock.method(mockPersisBridge, 'doRemove'); - const sp5 = mock.method(mockPersisBridge, 'doRemoveByAssociations'); - const sp6 = mock.method(mockPersisBridge, 'doUpdateByAssociations'); - - const ps = new Persistence(mockPersisBridge, mockAppId); - - assert.strictEqual(await ps.create(data), 'id'); - assert.strictEqual(sp1.mock.calls.length, 1); - assert.deepStrictEqual(sp1.mock.calls[0].arguments, [data, mockAppId]); - - assert.strictEqual(await ps.createWithAssociation(data, mockAssoc), 'id2'); - assert.strictEqual(await ps.createWithAssociations(data, [mockAssoc]), 'id2'); - assert.strictEqual(sp2.mock.calls.length, 2); - - assert.strictEqual(await ps.update('id', data), 'id3'); - assert.strictEqual(sp3.mock.calls.length, 1); - assert.deepStrictEqual(sp3.mock.calls[0].arguments, ['id', data, false, mockAppId]); - - assert.deepStrictEqual(await ps.remove('id'), data); - assert.strictEqual(sp4.mock.calls.length, 1); - assert.deepStrictEqual(sp4.mock.calls[0].arguments, ['id', mockAppId]); - - assert.ok((await ps.removeByAssociation(mockAssoc)) !== undefined); - assert.ok((await ps.removeByAssociations([mockAssoc])) !== undefined); - assert.strictEqual(sp5.mock.calls.length, 2); - - assert.ok((await ps.updateByAssociation(mockAssoc, data)) !== undefined); - assert.ok((await ps.updateByAssociations([mockAssoc], data)) !== undefined); - assert.strictEqual(sp6.mock.calls.length, 2); - }); -}); diff --git a/packages/apps/tests/server/accessors/PersistenceRead.test.ts b/packages/apps/tests/server/accessors/PersistenceRead.test.ts deleted file mode 100644 index 865b19abdfa17..0000000000000 --- a/packages/apps/tests/server/accessors/PersistenceRead.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { RocketChatAssociationRecord } from '@rocket.chat/apps-engine/definition/metadata'; - -import { PersistenceRead } from '../../../src/server/accessors'; -import type { PersistenceBridge } from '../../../src/server/bridges'; - -describe('PersistenceRead', () => { - it('usePersistenceRead', async () => { - const mockPersisBridge = { - doReadById(id: string, appId: string): Promise { - return Promise.resolve({ id, appId }); - }, - doReadByAssociations(assocs: Array, appId: string): Promise> { - return Promise.resolve([{ appId }]); - }, - } as PersistenceBridge; - - assert.doesNotThrow(() => new PersistenceRead(mockPersisBridge, 'testing')); - - const pr = new PersistenceRead(mockPersisBridge, 'testing'); - assert.deepStrictEqual(await pr.read('thing'), { id: 'thing', appId: 'testing' }); - assert.deepStrictEqual(await pr.readByAssociation({} as RocketChatAssociationRecord), [{ appId: 'testing' }]); - assert.deepStrictEqual(await pr.readByAssociations([{} as RocketChatAssociationRecord]), [{ appId: 'testing' }]); - }); -}); diff --git a/packages/apps/tests/server/accessors/Reader.test.ts b/packages/apps/tests/server/accessors/Reader.test.ts deleted file mode 100644 index cbfdf00256fab..0000000000000 --- a/packages/apps/tests/server/accessors/Reader.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { - ICloudWorkspaceRead, - IEnvironmentRead, - IExperimentalRead, - ILivechatRead, - IMessageRead, - INotifier, - IPersistenceRead, - IRoleRead, - IRoomRead, - IUploadRead, - IUserRead, - IVideoConferenceRead, -} from '@rocket.chat/apps-engine/definition/accessors'; -import type { IContactRead } from '@rocket.chat/apps-engine/definition/accessors/IContactRead'; -import type { IOAuthAppsReader } from '@rocket.chat/apps-engine/definition/accessors/IOAuthAppsReader'; -import type { IThreadRead } from '@rocket.chat/apps-engine/definition/accessors/IThreadRead'; - -import { Reader } from '../../../src/server/accessors'; - -describe('Reader', () => { - const env = {} as IEnvironmentRead; - const msg = {} as IMessageRead; - const pr = {} as IPersistenceRead; - const rm = {} as IRoomRead; - const ur = {} as IUserRead; - const ni = {} as INotifier; - const livechat = {} as ILivechatRead; - const upload = {} as IUploadRead; - const cloud = {} as ICloudWorkspaceRead; - const videoConf = {} as IVideoConferenceRead; - const oauthApps = {} as IOAuthAppsReader; - const thread = {} as IThreadRead; - const role = {} as IRoleRead; - const contact = {} as IContactRead; - const experimental = {} as IExperimentalRead; - - it('useReader', () => { - assert.doesNotThrow( - () => new Reader(env, msg, pr, rm, ur, ni, livechat, upload, cloud, videoConf, contact, oauthApps, thread, role, experimental), - ); - - const rd = new Reader(env, msg, pr, rm, ur, ni, livechat, upload, cloud, videoConf, contact, oauthApps, thread, role, experimental); - - assert.ok(rd.getEnvironmentReader() !== undefined); - assert.ok(rd.getMessageReader() !== undefined); - assert.ok(rd.getNotifier() !== undefined); - assert.ok(rd.getPersistenceReader() !== undefined); - assert.ok(rd.getRoomReader() !== undefined); - assert.ok(rd.getUserReader() !== undefined); - assert.ok(rd.getLivechatReader() !== undefined); - assert.ok(rd.getUploadReader() !== undefined); - assert.ok(rd.getVideoConferenceReader() !== undefined); - assert.ok(rd.getRoleReader() !== undefined); - }); -}); diff --git a/packages/apps/tests/server/accessors/RoomBuilder.test.ts b/packages/apps/tests/server/accessors/RoomBuilder.test.ts deleted file mode 100644 index 403dd97a86e85..0000000000000 --- a/packages/apps/tests/server/accessors/RoomBuilder.test.ts +++ /dev/null @@ -1,92 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; -import { RoomType } from '@rocket.chat/apps-engine/definition/rooms'; - -import { RoomBuilder } from '../../../src/server/accessors'; -import { TestData } from '../../test-data/utilities'; - -describe('RoomBuilder', () => { - it('basicRoomBuilder', () => { - assert.doesNotThrow(() => new RoomBuilder()); - assert.doesNotThrow(() => new RoomBuilder(TestData.getRoom())); - }); - - it('settingOnRoomBuilder', () => { - const rbOnce = new RoomBuilder(); - - // setData just replaces the passed in object, so let's treat it differently - assert.strictEqual(rbOnce.setData({ displayName: 'Testing Channel' } as IRoom), rbOnce); - assert.strictEqual((rbOnce as any).room.displayName, 'Testing Channel'); - - const room: IRoom = {} as IRoom; - const rb = new RoomBuilder(room); - assert.strictEqual(rb.setDisplayName('Just a Test'), rb); - assert.deepStrictEqual(room.displayName, 'Just a Test'); - assert.deepStrictEqual(rb.getDisplayName(), 'Just a Test'); - - assert.strictEqual(rb.setSlugifiedName('just_a_test'), rb); - assert.deepStrictEqual(room.slugifiedName, 'just_a_test'); - assert.deepStrictEqual(rb.getSlugifiedName(), 'just_a_test'); - - assert.strictEqual(rb.setType(RoomType.CHANNEL), rb); - assert.deepStrictEqual(room.type, RoomType.CHANNEL); - assert.deepStrictEqual(rb.getType(), RoomType.CHANNEL); - - const creator = TestData.getUser(); - - assert.strictEqual(rb.setCreator(creator), rb); - assert.deepStrictEqual(room.creator, creator); - assert.deepStrictEqual(rb.getCreator(), creator); - - assert.strictEqual(rb.addUsername('testing.username'), rb); - assert.strictEqual(room.usernames, undefined); - assert.ok(rb.getUsernames().length > 0); - assert.strictEqual(room.usernames, undefined); - assert.deepStrictEqual(rb.getUsernames()[0], 'testing.username'); - assert.strictEqual(rb.addUsername('another.username'), rb); - assert.strictEqual(room.usernames, undefined); - assert.strictEqual(rb.getUsernames().length, 2); - - assert.strictEqual(rb.setUsernames([]), rb); - assert.strictEqual(room.usernames, undefined); - assert.strictEqual(rb.getUsernames().length, 0); - - assert.strictEqual(rb.addMemberToBeAddedByUsername('testing.username'), rb); - assert.ok(rb.getMembersToBeAddedUsernames().length > 0); - assert.deepStrictEqual(rb.getMembersToBeAddedUsernames()[0], 'testing.username'); - assert.strictEqual(rb.addMemberToBeAddedByUsername('another.username'), rb); - assert.strictEqual(rb.getMembersToBeAddedUsernames().length, 2); - - assert.strictEqual(rb.setMembersToBeAddedByUsernames([]), rb); - assert.strictEqual(rb.getMembersToBeAddedUsernames().length, 0); - - assert.strictEqual(rb.setDefault(true), rb); - assert.ok(room.isDefault); - assert.ok(rb.getIsDefault()); - - assert.strictEqual(rb.setReadOnly(false), rb); - assert.ok(!room.isReadOnly); - assert.ok(!rb.getIsReadOnly()); - - assert.strictEqual(rb.setDisplayingOfSystemMessages(true), rb); - assert.ok(room.displaySystemMessages); - assert.ok(rb.getDisplayingOfSystemMessages()); - - assert.strictEqual(rb.addCustomField('thing', {}), rb); - assert.ok(Object.keys(room.customFields).length > 0); - assert.ok(Object.keys(rb.getCustomFields()).length > 0); - assert.ok(room.customFields.thing !== undefined); - assert.ok(rb.getCustomFields().thing !== undefined); - assert.strictEqual(rb.addCustomField('another', { thingy: 'two' }), rb); - assert.deepStrictEqual(room.customFields.another, { thingy: 'two' }); - assert.deepStrictEqual(rb.getCustomFields().another, { thingy: 'two' }); - - assert.strictEqual(rb.setCustomFields({}), rb); - assert.strictEqual(Object.keys(room.customFields).length, 0); - assert.strictEqual(Object.keys(rb.getCustomFields()).length, 0); - - assert.strictEqual(rb.getRoom(), room); - }); -}); diff --git a/packages/apps/tests/server/accessors/RoomExtender.test.ts b/packages/apps/tests/server/accessors/RoomExtender.test.ts deleted file mode 100644 index 099f7598a1b2f..0000000000000 --- a/packages/apps/tests/server/accessors/RoomExtender.test.ts +++ /dev/null @@ -1,47 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; - -import { RoomExtender } from '../../../src/server/accessors'; -import { TestData } from '../../test-data/utilities'; - -describe('RoomExtender', () => { - it('basicRoomExtender', () => { - assert.doesNotThrow(() => new RoomExtender({} as IRoom)); - assert.doesNotThrow(() => new RoomExtender(TestData.getRoom())); - }); - - it('usingRoomExtender', () => { - const room: IRoom = {} as IRoom; - const re = new RoomExtender(room); - - assert.ok(room.customFields === undefined); - assert.strictEqual(re.addCustomField('thing', 'value'), re); - assert.ok(room.customFields !== undefined); - assert.strictEqual(room.customFields.thing as any, 'value'); - assert.throws(() => re.addCustomField('thing', 'second'), { - name: 'Error', - message: 'The room already contains a custom field by the key: thing', - }); - assert.throws(() => re.addCustomField('thing.', 'second'), { - name: 'Error', - message: 'The given key contains a period, which is not allowed. Key: thing.', - }); - - assert.ok(room.usernames === undefined); - assert.strictEqual(re.addMember(TestData.getUser('theId', 'bradley')), re); - assert.ok(room.usernames === undefined); - assert.ok(re.getMembersBeingAdded() !== undefined); - assert.ok(re.getMembersBeingAdded().length > 0); - assert.ok(re.getMembersBeingAdded()[0] !== undefined); - assert.strictEqual(re.getMembersBeingAdded()[0].username, 'bradley'); - assert.throws(() => re.addMember(TestData.getUser('theSameUsername', 'bradley')), { - name: 'Error', - message: 'The user is already in the room.', - }); - - assert.notStrictEqual(re.getRoom(), room); - assert.deepStrictEqual(re.getRoom(), room); - }); -}); diff --git a/packages/apps/tests/server/accessors/RoomRead.test.ts b/packages/apps/tests/server/accessors/RoomRead.test.ts deleted file mode 100644 index aa4b9b7b2b3f9..0000000000000 --- a/packages/apps/tests/server/accessors/RoomRead.test.ts +++ /dev/null @@ -1,150 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { IMessageRaw } from '@rocket.chat/apps-engine/definition/messages'; -import type { IRoom, IRoomRaw } from '@rocket.chat/apps-engine/definition/rooms'; -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -import { RoomRead } from '../../../src/server/accessors'; -import type { RoomBridge } from '../../../src/server/bridges'; -import { TestData } from '../../test-data/utilities'; - -describe('RoomRead', () => { - const room = TestData.getRoom(); - room.id = room.id || 'room-id'; - const user = TestData.getUser(); - const messages: IMessageRaw[] = ['507f1f77bcf86cd799439011', '507f191e810c19729de860ea'].map((id) => TestData.getMessageRaw(id)); - const unreadRoomId = messages[0].roomId; - const unreadUserId = messages[0].sender._id; - - const theRooms: IRoomRaw[] = [ - { - id: room.id, - slugifiedName: room.slugifiedName, - displayName: room.displayName, - type: room.type, - creator: { - _id: room.creator.id, - username: room.creator.username, - name: room.creator.name, - }, - }, - ]; - - const mockRoomBridgeWithRoom = { - doGetById(id: string, appId: string): Promise { - return Promise.resolve(room); - }, - doGetByName(name: string, appId: string): Promise { - return Promise.resolve(room); - }, - doGetCreatorById(id: string, appId: string): Promise { - return Promise.resolve(user); - }, - doGetCreatorByName(name: string, appId: string): Promise { - return Promise.resolve(user); - }, - doGetDirectByUsernames(usernames: Array, appId: string): Promise { - return Promise.resolve(room); - }, - doGetMembers(name: string, appId: string): Promise> { - return Promise.resolve([user]); - }, - doGetAllRooms(filter: any, appId: string): Promise> { - return Promise.resolve(theRooms); - }, - doGetMessages(roomId: string, options: any, appId: string): Promise { - return Promise.resolve(messages); - }, - doGetUnreadByUser(roomId: string, uid: string, options: any, appId: string): Promise { - if (roomId === unreadRoomId && uid === unreadUserId) { - return Promise.resolve(messages); - } - return Promise.resolve([]); - }, - } as unknown as RoomBridge; - - it('expectDataFromRoomRead', async () => { - assert.doesNotThrow(() => new RoomRead(mockRoomBridgeWithRoom, 'testing-app')); - - const rr = new RoomRead(mockRoomBridgeWithRoom, 'testing-app'); - - assert.ok((await rr.getById('fake')) !== undefined); - assert.strictEqual(await rr.getById('fake'), room); - assert.ok((await rr.getByName('testing-room')) !== undefined); - assert.strictEqual(await rr.getByName('testing-room'), room); - assert.ok((await rr.getCreatorUserById('testing')) !== undefined); - assert.strictEqual(await rr.getCreatorUserById('testing'), user); - assert.ok((await rr.getCreatorUserByName('testing')) !== undefined); - assert.strictEqual(await rr.getCreatorUserByName('testing'), user); - assert.ok((await rr.getDirectByUsernames([user.username])) !== undefined); - assert.strictEqual(await rr.getDirectByUsernames([user.username]), room); - assert.ok((await rr.getMessages('testing')) !== undefined); - assert.strictEqual(await rr.getMessages('testing'), messages); - assert.ok((await rr.getAllRooms()) !== undefined); - assert.deepStrictEqual(await rr.getAllRooms(), [ - { - id: room.id, - slugifiedName: room.slugifiedName, - displayName: room.displayName, - type: room.type, - creator: { - _id: room.creator.id, - username: room.creator.username, - name: room.creator.name, - }, - }, - ]); - assert.ok((await rr.getUnreadByUser(unreadRoomId, unreadUserId)) !== undefined); - assert.deepStrictEqual(await rr.getUnreadByUser(unreadRoomId, unreadUserId), messages); - - assert.ok((await rr.getUnreadByUser('fake', 'fake')) !== undefined); - assert.deepStrictEqual(await rr.getUnreadByUser('fake', 'fake'), []); - }); - - it('useTheIterators', async () => { - assert.doesNotThrow(() => new RoomRead(mockRoomBridgeWithRoom, 'testing-app')); - - const rr = new RoomRead(mockRoomBridgeWithRoom, 'testing-app'); - - assert.ok((await rr.getMembers('testing')) !== undefined); - assert.ok(((await rr.getMembers('testing')) as Array).length > 0); - assert.strictEqual((await rr.getMembers('testing'))[0], user); - }); - - it('validateGetAllRoomsEdgeCases', async () => { - const rr = new RoomRead(mockRoomBridgeWithRoom, 'testing-app'); - - // Test negative limit - await assert.rejects(async () => rr.getAllRooms({}, { limit: -1 })); - await assert.rejects(async () => rr.getAllRooms({}, { limit: -100 })); - - // Test zero limit - await assert.rejects(async () => rr.getAllRooms({}, { limit: 0 })); - // Test non-finite limit values - await assert.rejects(async () => rr.getAllRooms({}, { limit: NaN })); - await assert.rejects(async () => rr.getAllRooms({}, { limit: Infinity })); - await assert.rejects(async () => rr.getAllRooms({}, { limit: -Infinity })); - - // Test limit > 100 (existing test case) - await assert.rejects(async () => rr.getAllRooms({}, { limit: 101 })); - await assert.rejects(async () => rr.getAllRooms({}, { limit: 200 })); - - // Test negative skip values - await assert.rejects(async () => rr.getAllRooms({}, { skip: -1 })); - await assert.rejects(async () => rr.getAllRooms({}, { skip: -100 })); - - // Test non-finite skip values - await assert.rejects(async () => rr.getAllRooms({}, { skip: NaN })); - await assert.rejects(async () => rr.getAllRooms({}, { skip: Infinity })); - await assert.rejects(async () => rr.getAllRooms({}, { skip: -Infinity })); - - // Test valid calls to ensure validation doesn't break normal behavior - await assert.doesNotReject(async () => rr.getAllRooms({}, { limit: 1 })); - await assert.doesNotReject(async () => rr.getAllRooms({}, { limit: 50 })); - await assert.doesNotReject(async () => rr.getAllRooms({}, { limit: 100 })); - await assert.doesNotReject(async () => rr.getAllRooms({}, { skip: 0 })); - await assert.doesNotReject(async () => rr.getAllRooms({}, { skip: 10 })); - await assert.doesNotReject(async () => rr.getAllRooms({}, { limit: 50, skip: 10 })); - }); -}); diff --git a/packages/apps/tests/server/accessors/ServerSettingRead.test.ts b/packages/apps/tests/server/accessors/ServerSettingRead.test.ts deleted file mode 100644 index e35e089803943..0000000000000 --- a/packages/apps/tests/server/accessors/ServerSettingRead.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import { ServerSettingRead } from '../../../src/server/accessors'; -import type { ServerSettingBridge } from '../../../src/server/bridges'; -import { TestData } from '../../test-data/utilities'; - -describe('ServerSettingRead', () => { - it('expectDataFromServerSettingRead', async () => { - const setting = TestData.getSetting('testing'); - - const theSetting = setting; - const mockServerSettingBridge = { - doGetOneById(id: string, appId: string) { - return Promise.resolve(id === 'testing' ? theSetting : undefined); - }, - doIsReadableById(id: string, appId: string): Promise { - return Promise.resolve(true); - }, - } as ServerSettingBridge; - - assert.doesNotThrow(() => new ServerSettingRead(mockServerSettingBridge, 'testing-app')); - - const ssr = new ServerSettingRead(mockServerSettingBridge, 'testing-app'); - - assert.ok((await ssr.getOneById('testing')) !== undefined); - assert.deepStrictEqual(await ssr.getOneById('testing'), setting); - assert.deepStrictEqual(await ssr.getValueById('testing'), setting.packageValue); - setting.value = 'theValue'; - assert.strictEqual(await ssr.getValueById('testing'), 'theValue'); - await assert.rejects(async () => ssr.getValueById('fake'), { - name: 'Error', - message: 'No Server Setting found, or it is unaccessible, by the id of "fake".', - }); - assert.throws(() => ssr.getAll(), { - name: 'Error', - message: 'Method not implemented.', - }); - assert.strictEqual(await ssr.isReadableById('testing'), true); - }); -}); diff --git a/packages/apps/tests/server/accessors/ServerSettingsModify.test.ts b/packages/apps/tests/server/accessors/ServerSettingsModify.test.ts deleted file mode 100644 index 736751265acfc..0000000000000 --- a/packages/apps/tests/server/accessors/ServerSettingsModify.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it, mock } from 'node:test'; - -import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; - -import { ServerSettingsModify } from '../../../src/server/accessors'; -import type { ServerSettingBridge } from '../../../src/server/bridges'; -import { TestData } from '../../test-data/utilities'; - -describe('ServerSettingsModify', () => { - it('useServerSettingsModify', async () => { - const setting = TestData.getSetting(); - const mockAppId = 'testing-app'; - const mockServerSettingBridge = { - doHideGroup(name: string, appId: string): Promise { - return Promise.resolve(); - }, - doHideSetting(id: string, appId: string): Promise { - return Promise.resolve(); - }, - doUpdateOne(setting: ISetting, appId: string): Promise { - return Promise.resolve(); - }, - doIncrementValue(id: ISetting['id'], value: number, appId: string): Promise { - return Promise.resolve(); - }, - } as ServerSettingBridge; - - assert.doesNotThrow(() => new ServerSettingsModify(mockServerSettingBridge, mockAppId)); - - const hideGroupSpy = mock.method(mockServerSettingBridge, 'doHideGroup'); - const hideSettingSpy = mock.method(mockServerSettingBridge, 'doHideSetting'); - const updateOneSpy = mock.method(mockServerSettingBridge, 'doUpdateOne'); - const incrementValueSpy = mock.method(mockServerSettingBridge, 'doIncrementValue'); - - const ssm = new ServerSettingsModify(mockServerSettingBridge, mockAppId); - - assert.ok((await ssm.hideGroup('api')) === undefined); - assert.strictEqual(hideGroupSpy.mock.calls.length, 1); - assert.deepStrictEqual(hideGroupSpy.mock.calls[0].arguments, ['api', mockAppId]); - - assert.ok((await ssm.hideSetting('api')) === undefined); - assert.strictEqual(hideSettingSpy.mock.calls.length, 1); - assert.deepStrictEqual(hideSettingSpy.mock.calls[0].arguments, ['api', mockAppId]); - - assert.ok((await ssm.modifySetting(setting)) === undefined); - assert.strictEqual(updateOneSpy.mock.calls.length, 1); - assert.deepStrictEqual(updateOneSpy.mock.calls[0].arguments, [setting, mockAppId]); - - assert.ok((await ssm.incrementValue(setting.id, 5)) === undefined); - assert.strictEqual(incrementValueSpy.mock.calls.length, 1); - assert.deepStrictEqual(incrementValueSpy.mock.calls[0].arguments, [setting.id, 5, mockAppId]); - }); -}); diff --git a/packages/apps/tests/server/accessors/SettingRead.test.ts b/packages/apps/tests/server/accessors/SettingRead.test.ts deleted file mode 100644 index 4d222cd8a3533..0000000000000 --- a/packages/apps/tests/server/accessors/SettingRead.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { ProxiedApp } from '../../../src/server/ProxiedApp'; -import { SettingRead } from '../../../src/server/accessors'; -import type { IAppStorageItem } from '../../../src/server/storage'; -import { TestData } from '../../test-data/utilities'; - -describe('SettingRead', () => { - it('appSettingRead', async () => { - const mockStorageItem = { - settings: {}, - } as IAppStorageItem; - mockStorageItem.settings.testing = TestData.getSetting('testing'); - - const si = mockStorageItem; - const mockProxiedApp = { - getStorageItem(): IAppStorageItem { - return si; - }, - } as ProxiedApp; - - assert.doesNotThrow(() => new SettingRead({} as ProxiedApp)); - - const sr = new SettingRead(mockProxiedApp); - assert.ok((await sr.getById('testing')) !== undefined); - assert.deepStrictEqual(await sr.getById('testing'), TestData.getSetting('testing')); - assert.strictEqual(await sr.getValueById('testing'), 'The packageValue'); - mockStorageItem.settings.testing.value = 'my value'; - assert.strictEqual(await sr.getValueById('testing'), 'my value'); - await assert.rejects(() => sr.getValueById('superfake'), { - name: 'Error', - message: 'Setting "superfake" does not exist.', - }); - }); -}); diff --git a/packages/apps/tests/server/accessors/SettingUpdater.test.ts b/packages/apps/tests/server/accessors/SettingUpdater.test.ts deleted file mode 100644 index 136e8b1c15c0d..0000000000000 --- a/packages/apps/tests/server/accessors/SettingUpdater.test.ts +++ /dev/null @@ -1,104 +0,0 @@ -import * as assert from 'node:assert'; -import { afterEach, beforeEach, describe, it, mock } from 'node:test'; - -import type { ProxiedApp } from '../../../src/server/ProxiedApp'; -import { SettingUpdater } from '../../../src/server/accessors'; -import type { AppSettingsManager } from '../../../src/server/managers'; -import type { IAppStorageItem } from '../../../src/server/storage'; -import { TestData } from '../../test-data/utilities'; - -describe('SettingUpdater', () => { - let mockStorageItem: IAppStorageItem; - let mockProxiedApp: ProxiedApp; - let mockSettingsManager: AppSettingsManager; - - beforeEach(() => { - // Set up mock storage with test settings - mockStorageItem = { - settings: {}, - } as IAppStorageItem; - - mockStorageItem.settings.singleValue = TestData.getSetting('singleValue'); - mockStorageItem.settings.multiValue = { - ...TestData.getSetting('multiValue'), - values: [ - { key: 'key1', i18nLabel: 'value1' }, - { key: 'key2', i18nLabel: 'value2' }, - ], - }; - - // Mock ProxiedApp - const si = mockStorageItem; - mockProxiedApp = { - getStorageItem(): IAppStorageItem { - return si; - }, - getID(): string { - return 'test-app-id'; - }, - } as ProxiedApp; - - // Mock AppSettingsManager - mockSettingsManager = {} as AppSettingsManager; - mockSettingsManager.getAppSetting = (appId: string, settingId: string) => { - return mockStorageItem.settings[settingId]; - }; - mockSettingsManager.updateAppSetting = (appId: string, setting: any) => { - mockStorageItem.settings[setting.id] = setting; - return Promise.resolve(); - }; - }); - - afterEach(() => { - mock.restoreAll(); - }); - - it('updateValueSuccessfully', async () => { - const updateAppSettingSpy = mock.method(mockSettingsManager, 'updateAppSetting'); - const settingUpdater = new SettingUpdater(mockProxiedApp, mockSettingsManager); - - await settingUpdater.updateValue('singleValue', 'updated value'); - - assert.ok(updateAppSettingSpy.mock.calls.length > 0); - assert.strictEqual(mockStorageItem.settings.singleValue.value, 'updated value'); - // Verify updatedAt was set - assert.ok(mockStorageItem.settings.singleValue.updatedAt !== undefined); - }); - - it('updateValueThrowsErrorForNonExistentSetting', async () => { - const settingUpdater = new SettingUpdater(mockProxiedApp, mockSettingsManager); - - await assert.rejects(() => settingUpdater.updateValue('nonExistent', 'value'), { - name: 'Error', - message: 'Setting "nonExistent" not found for app test-app-id', - }); - }); - - it('updateSelectOptionsSuccessfully', async () => { - const updateAppSettingSpy = mock.method(mockSettingsManager, 'updateAppSetting'); - const settingUpdater = new SettingUpdater(mockProxiedApp, mockSettingsManager); - const newValues = [ - { key: 'key3', i18nLabel: 'value3' }, - { key: 'key4', i18nLabel: 'value4' }, - ]; - - await settingUpdater.updateSelectOptions('multiValue', newValues); - - assert.ok(updateAppSettingSpy.mock.calls.length > 0); - const updatedValues = mockStorageItem.settings.multiValue.values; - // Should completely replace old values - assert.strictEqual((updatedValues ?? []).length, 2); - assert.deepStrictEqual(updatedValues, newValues); - // Verify updatedAt was set - assert.ok(mockStorageItem.settings.multiValue.updatedAt !== undefined); - }); - - it('updateSelectOptionsThrowsErrorForNonExistentSetting', async () => { - const settingUpdater = new SettingUpdater(mockProxiedApp, mockSettingsManager); - - await assert.rejects(() => settingUpdater.updateSelectOptions('nonExistent', [{ key: 'test', i18nLabel: 'value' }]), { - name: 'Error', - message: 'Setting "nonExistent" not found for app test-app-id', - }); - }); -}); diff --git a/packages/apps/tests/server/accessors/SettingsExtend.test.ts b/packages/apps/tests/server/accessors/SettingsExtend.test.ts deleted file mode 100644 index 944ad5ed8cfc0..0000000000000 --- a/packages/apps/tests/server/accessors/SettingsExtend.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; -import { SettingType } from '@rocket.chat/apps-engine/definition/settings'; - -import type { ProxiedApp } from '../../../src/server/ProxiedApp'; -import { SettingsExtend } from '../../../src/server/accessors'; -import type { IAppStorageItem } from '../../../src/server/storage'; - -describe('SettingsExtend', () => { - it('basicSettingsExtend', () => { - assert.doesNotThrow(() => new SettingsExtend({} as ProxiedApp)); - }); - - it('provideSettingToSettingsExtend', async () => { - const mockedStorageItem: IAppStorageItem = { - settings: {}, - } as IAppStorageItem; - - const mockedApp: ProxiedApp = { - getStorageItem: function _getStorageItem() { - return mockedStorageItem; - }, - } as ProxiedApp; - const se = new SettingsExtend(mockedApp); - - const setting: ISetting = { - id: 'testing', - type: SettingType.STRING, - packageValue: 'thing', - required: false, - public: false, - i18nLabel: 'Testing_Settings', - }; - - await assert.doesNotReject(() => se.provideSetting(setting)); - assert.ok(Object.keys(mockedStorageItem.settings).length > 0); - - const settingModified: ISetting = { - id: 'testing', - type: SettingType.STRING, - packageValue: 'thing', - required: false, - public: false, - i18nLabel: 'Testing_Thing', - value: 'dont-use-me', - }; - await assert.doesNotReject(() => se.provideSetting(settingModified)); - assert.ok(mockedStorageItem.settings.testing !== undefined); - assert.ok(mockedStorageItem.settings.testing.value === undefined); - assert.strictEqual(mockedStorageItem.settings.testing.i18nLabel, 'Testing_Thing'); - }); -}); diff --git a/packages/apps/tests/server/accessors/SlashCommandsExtend.test.ts b/packages/apps/tests/server/accessors/SlashCommandsExtend.test.ts deleted file mode 100644 index fec22df9093c9..0000000000000 --- a/packages/apps/tests/server/accessors/SlashCommandsExtend.test.ts +++ /dev/null @@ -1,47 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { ISlashCommand } from '@rocket.chat/apps-engine/definition/slashcommands'; - -import { SlashCommandsExtend } from '../../../src/server/accessors'; -import { CommandAlreadyExistsError } from '../../../src/server/errors'; -import type { AppSlashCommandManager } from '../../../src/server/managers'; - -describe('SlashCommandsExtend', () => { - it('basicSlashCommandsExtend', () => { - assert.doesNotThrow(() => new SlashCommandsExtend({} as AppSlashCommandManager, 'testing')); - }); - - it('provideCommandToCommandsExtend', async () => { - const commands = new Map>(); - const mockManager: AppSlashCommandManager = { - addCommand(appId: string, command: ISlashCommand) { - if (commands.has(appId)) { - const cmds = commands.get(appId); - if (cmds.find((v) => v.command === command.command)) { - throw new CommandAlreadyExistsError(command.command); - } - - cmds.push(command); - return; - } - - commands.set(appId, Array.from([command])); - }, - } as AppSlashCommandManager; - - const se = new SlashCommandsExtend(mockManager, 'testing'); - - const mockCommand: ISlashCommand = { - command: 'mock', - i18nDescription: 'Thing', - } as ISlashCommand; - - await assert.doesNotReject(() => se.provideSlashCommand(mockCommand)); - assert.strictEqual(commands.size, 1); - await assert.rejects(() => se.provideSlashCommand(mockCommand), { - name: 'CommandAlreadyExists', - message: 'The command "mock" already exists in the system.', - }); - }); -}); diff --git a/packages/apps/tests/server/accessors/SlashCommandsModify.test.ts b/packages/apps/tests/server/accessors/SlashCommandsModify.test.ts deleted file mode 100644 index 7202f688a3cdf..0000000000000 --- a/packages/apps/tests/server/accessors/SlashCommandsModify.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it, mock } from 'node:test'; - -import type { ISlashCommand } from '@rocket.chat/apps-engine/definition/slashcommands'; - -import { SlashCommandsModify } from '../../../src/server/accessors'; -import type { AppSlashCommandManager } from '../../../src/server/managers'; -import { TestData } from '../../test-data/utilities'; - -describe('SlashCommandsModify', () => { - it('useSlashCommandsModify', async () => { - const cmd = TestData.getSlashCommand(); - const mockAppId = 'testing-app'; - const mockCmdManager = { - modifyCommand(appId: string, command: ISlashCommand): void {}, - disableCommand(appId: string, command: string): void {}, - enableCommand(appId: string, command: string): void {}, - } as AppSlashCommandManager; - - assert.doesNotThrow(() => new SlashCommandsModify(mockCmdManager, mockAppId)); - - const modifySpy = mock.method(mockCmdManager, 'modifyCommand'); - const disableSpy = mock.method(mockCmdManager, 'disableCommand'); - const enableSpy = mock.method(mockCmdManager, 'enableCommand'); - - const scm = new SlashCommandsModify(mockCmdManager, mockAppId); - - assert.ok((await scm.modifySlashCommand(cmd)) === undefined); - assert.strictEqual(modifySpy.mock.calls.length, 1); - assert.deepStrictEqual(modifySpy.mock.calls[0].arguments, [mockAppId, cmd]); - - assert.ok((await scm.disableSlashCommand('testing-cmd')) === undefined); - assert.strictEqual(disableSpy.mock.calls.length, 1); - assert.deepStrictEqual(disableSpy.mock.calls[0].arguments, [mockAppId, 'testing-cmd']); - - assert.ok((await scm.enableSlashCommand('testing-cmd')) === undefined); - assert.strictEqual(enableSpy.mock.calls.length, 1); - assert.deepStrictEqual(enableSpy.mock.calls[0].arguments, [mockAppId, 'testing-cmd']); - }); -}); diff --git a/packages/apps/tests/server/accessors/UserBuilder.test.ts b/packages/apps/tests/server/accessors/UserBuilder.test.ts deleted file mode 100644 index 028fff0d7f802..0000000000000 --- a/packages/apps/tests/server/accessors/UserBuilder.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { IUser, IUserEmail } from '@rocket.chat/apps-engine/definition/users'; - -import { UserBuilder } from '../../../src/server/accessors'; - -describe('UserBuilder', () => { - it('basicUserBuilder', () => { - assert.doesNotThrow(() => new UserBuilder()); - }); - - it('settingOnUserBuilder', () => { - const ubOnce = new UserBuilder(); - assert.strictEqual(ubOnce.setData({ name: 'Test User', email: 'testuser@gmail.com', username: 'testuser' } as Partial), ubOnce); - assert.strictEqual((ubOnce as any).user.name, 'Test User'); - assert.strictEqual((ubOnce as any).user.username, 'testuser'); - assert.strictEqual((ubOnce as any).user.email, 'testuser@gmail.com'); - - const user: Partial = {} as Partial; - const ub = new UserBuilder(user); - - assert.strictEqual( - ub.setEmails([ - { - address: 'testuser@gmail.com', - verified: false, - } as IUserEmail, - ]), - ub, - ); - assert.deepStrictEqual(user.emails, [ - { - address: 'testuser@gmail.com', - verified: false, - } as IUserEmail, - ]); - assert.deepStrictEqual(ub.getEmails(), [ - { - address: 'testuser@gmail.com', - verified: false, - } as IUserEmail, - ]); - - assert.strictEqual(ub.setDisplayName('Test User'), ub); - assert.deepStrictEqual(user.name, 'Test User'); - assert.deepStrictEqual(ub.getDisplayName(), 'Test User'); - - assert.strictEqual(ub.setUsername('testuser'), ub); - assert.deepStrictEqual(user.username, 'testuser'); - assert.deepStrictEqual(ub.getUsername(), 'testuser'); - - assert.strictEqual(ub.setRoles(['bot']), ub); - assert.deepStrictEqual(user.roles, ['bot']); - assert.deepStrictEqual(ub.getRoles(), ['bot']); - - assert.strictEqual(ub.getUser(), user); - }); -}); diff --git a/packages/apps/tests/server/accessors/UserRead.test.ts b/packages/apps/tests/server/accessors/UserRead.test.ts deleted file mode 100644 index 276e293fa5179..0000000000000 --- a/packages/apps/tests/server/accessors/UserRead.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { IUser } from '@rocket.chat/apps-engine/definition/users'; - -import { UserRead } from '../../../src/server/accessors'; -import type { UserBridge } from '../../../src/server/bridges'; -import { TestData } from '../../test-data/utilities'; - -describe('UserRead', () => { - const user = TestData.getUser(); - const roomIds = ['room-1', 'room-2']; - const mockAppId = 'test-appId'; - - const mockUserBridge = { - doGetById(id: string, appId: string): Promise { - return Promise.resolve(user); - }, - doGetByUsername(id: string, appId: string): Promise { - return Promise.resolve(user); - }, - doGetAppUser(appId?: string): Promise { - return Promise.resolve(user); - }, - doGetUserRoomIds(userId: string): Promise> { - return Promise.resolve(roomIds); - }, - } as unknown as UserBridge; - - it('expectDataFromUserRead', async () => { - assert.doesNotThrow(() => new UserRead(mockUserBridge, 'testing-app')); - - const ur = new UserRead(mockUserBridge, 'testing-app'); - - assert.ok((await ur.getById('fake')) !== undefined); - assert.deepStrictEqual(await ur.getById('fake'), user); - - assert.ok((await ur.getByUsername('username')) !== undefined); - assert.deepStrictEqual(await ur.getByUsername('username'), user); - - assert.ok((await ur.getAppUser(mockAppId)) !== undefined); - assert.deepStrictEqual(await ur.getAppUser(mockAppId), user); - assert.deepStrictEqual(await ur.getAppUser(), user); - assert.deepStrictEqual(await ur.getUserRoomIds(user.id), roomIds); - }); -}); diff --git a/packages/apps/tests/server/accessors/VideoConfProviderExtend.test.ts b/packages/apps/tests/server/accessors/VideoConfProviderExtend.test.ts deleted file mode 100644 index 4a4077b7a8fb9..0000000000000 --- a/packages/apps/tests/server/accessors/VideoConfProviderExtend.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { IVideoConfProvider } from '@rocket.chat/apps-engine/definition/videoConfProviders'; - -import { VideoConfProviderExtend } from '../../../src/server/accessors'; -import type { AppVideoConfProviderManager } from '../../../src/server/managers'; - -describe('VideoConfProviderExtend', () => { - it('basicVideoConfProviderExtend', () => { - assert.doesNotThrow(() => new VideoConfProviderExtend({} as AppVideoConfProviderManager, 'testing')); - }); - - it('provideProviderToVideoConfProviderExtend', async () => { - let providerAdded: IVideoConfProvider | undefined; - const mockManager: AppVideoConfProviderManager = { - addProvider(appId: string, provider: IVideoConfProvider) { - providerAdded = provider; - }, - } as AppVideoConfProviderManager; - - const se = new VideoConfProviderExtend(mockManager, 'testing'); - - const mockProvider: IVideoConfProvider = { - name: 'test', - - async generateUrl(): Promise { - return ''; - }, - async customizeUrl(): Promise { - return ''; - }, - } as IVideoConfProvider; - - await assert.doesNotReject(() => se.provideVideoConfProvider(mockProvider)); - assert.strictEqual(providerAdded, mockProvider); - }); -}); diff --git a/packages/apps/tests/server/accessors/VideoConferenceBuilder.test.ts b/packages/apps/tests/server/accessors/VideoConferenceBuilder.test.ts deleted file mode 100644 index 1d8bb9f8323ac..0000000000000 --- a/packages/apps/tests/server/accessors/VideoConferenceBuilder.test.ts +++ /dev/null @@ -1,101 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { AppVideoConference } from '@rocket.chat/apps-engine/definition/videoConferences'; - -import { VideoConferenceBuilder } from '../../../src/server/accessors'; -import { TestData } from '../../test-data/utilities'; - -describe('VideoConferenceBuilder', () => { - it('basicVideoConferenceBuilderBuilder', () => { - assert.doesNotThrow(() => new VideoConferenceBuilder()); - assert.doesNotThrow(() => new VideoConferenceBuilder(TestData.getAppVideoConference())); - }); - - it('setData', () => { - const builder = new VideoConferenceBuilder(); - - assert.strictEqual(builder.setData({ providerName: 'test-provider' } as AppVideoConference), builder); - assert.strictEqual(((builder as any).call as AppVideoConference).providerName, 'test-provider'); - }); - - it('setRoomId', () => { - const call = {} as AppVideoConference; - const builder = new VideoConferenceBuilder(call); - - assert.strictEqual(builder.setRoomId('roomId'), builder); - assert.strictEqual(call.rid, 'roomId'); - assert.strictEqual(builder.getRoomId(), 'roomId'); - - assert.strictEqual(builder.getVideoConference(), call); - }); - - it('setCreatedBy', () => { - const call = {} as AppVideoConference; - const builder = new VideoConferenceBuilder(call); - - assert.strictEqual(builder.setCreatedBy('userId'), builder); - assert.strictEqual(call.createdBy, 'userId'); - assert.strictEqual(builder.getCreatedBy(), 'userId'); - - assert.strictEqual(builder.getVideoConference(), call); - }); - - it('setProviderName', () => { - const call = {} as AppVideoConference; - const builder = new VideoConferenceBuilder(call); - - assert.strictEqual(builder.setProviderName('test'), builder); - assert.strictEqual(call.providerName, 'test'); - assert.strictEqual(builder.getProviderName(), 'test'); - - assert.strictEqual(builder.getVideoConference(), call); - }); - - it('setProviderData', () => { - const call = {} as AppVideoConference; - const builder = new VideoConferenceBuilder(call); - - assert.strictEqual(builder.setProviderData({ custom: true }), builder); - assert.deepStrictEqual(call.providerData, { custom: true }); - assert.deepStrictEqual(builder.getProviderData(), { custom: true }); - - assert.strictEqual(builder.getVideoConference(), call); - }); - - it('setTitle', () => { - const call = {} as AppVideoConference; - const builder = new VideoConferenceBuilder(call); - - assert.strictEqual(builder.setTitle('Video Conference'), builder); - assert.strictEqual(call.title, 'Video Conference'); - assert.strictEqual(builder.getTitle(), 'Video Conference'); - - assert.strictEqual(builder.getVideoConference(), call); - }); - - it('setDiscussionRid', () => { - const call = {} as AppVideoConference; - const builder = new VideoConferenceBuilder(call); - - assert.strictEqual(builder.setDiscussionRid('testId'), builder); - assert.strictEqual(call.discussionRid, 'testId'); - assert.strictEqual(builder.getDiscussionRid(), 'testId'); - - assert.strictEqual(builder.getVideoConference(), call); - }); - - it('initialData', () => { - const call = { providerName: 'test' } as AppVideoConference; - const builder = new VideoConferenceBuilder(call); - - assert.strictEqual(call.providerName, 'test'); - assert.strictEqual(builder.getProviderName(), 'test'); - - assert.strictEqual(builder.setProviderName('test2'), builder); - assert.strictEqual(call.providerName, 'test2'); - assert.strictEqual(builder.getProviderName(), 'test2'); - - assert.strictEqual(builder.getVideoConference(), call); - }); -}); diff --git a/packages/apps/tests/server/accessors/VideoConferenceExtend.test.ts b/packages/apps/tests/server/accessors/VideoConferenceExtend.test.ts deleted file mode 100644 index 20e317c2ae6d5..0000000000000 --- a/packages/apps/tests/server/accessors/VideoConferenceExtend.test.ts +++ /dev/null @@ -1,76 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { VideoConference } from '@rocket.chat/apps-engine/definition/videoConferences'; - -import { VideoConferenceExtender } from '../../../src/server/accessors'; -import { TestData } from '../../test-data/utilities'; - -describe('VideoConferenceExtend', () => { - it('basicVideoConferenceExtend', () => { - assert.doesNotThrow(() => new VideoConferenceExtender({} as VideoConference)); - assert.doesNotThrow(() => new VideoConferenceExtender(TestData.getVideoConference())); - }); - - it('setProviderData', () => { - const call = {} as VideoConference; - const extend = new VideoConferenceExtender(call); - - assert.strictEqual(call.providerData, undefined); - assert.strictEqual(extend.setProviderData({ key: 'test' }), extend); - assert.ok(call.providerData !== undefined); - assert.strictEqual(call.providerData.key, 'test'); - - assert.notStrictEqual(extend.getVideoConference(), call); - assert.deepStrictEqual(extend.getVideoConference(), call); - }); - - it('setStatus', () => { - const call = { status: 0 } as VideoConference; - const extend = new VideoConferenceExtender(call); - - assert.strictEqual(call.status, 0); - assert.strictEqual(extend.setStatus(1), extend); - assert.strictEqual(call.status, 1); - }); - - it('setEndedBy', () => { - const call = {} as VideoConference; - const extend = new VideoConferenceExtender(call); - - assert.strictEqual(call.endedBy, undefined); - assert.strictEqual(extend.setEndedBy('userId'), extend); - assert.ok(call.endedBy !== undefined); - assert.strictEqual(call.endedBy._id, 'userId'); - }); - - it('setEndedAt', () => { - const call = {} as VideoConference; - const extend = new VideoConferenceExtender(call); - - const date = new Date(); - - assert.strictEqual(call.endedAt, undefined); - assert.strictEqual(extend.setEndedAt(date), extend); - assert.strictEqual(call.endedAt, date); - }); - - it('setDiscussionRid', () => { - const call = {} as VideoConference; - const extend = new VideoConferenceExtender(call); - - assert.strictEqual(call.discussionRid, undefined); - assert.strictEqual(extend.setDiscussionRid('testId'), extend); - assert.strictEqual(call.discussionRid, 'testId'); - }); - - it('addUser', () => { - const call = { users: [] } as VideoConference; - const extend = new VideoConferenceExtender(call); - - assert.strictEqual(call.users.length, 0); - assert.strictEqual(extend.addUser('userId'), extend); - assert.ok(call.users.length > 0); - assert.strictEqual(call.users[0]._id, 'userId'); - }); -}); diff --git a/packages/apps/tests/server/accessors/VideoConferenceRead.test.ts b/packages/apps/tests/server/accessors/VideoConferenceRead.test.ts deleted file mode 100644 index 478e92a1df91b..0000000000000 --- a/packages/apps/tests/server/accessors/VideoConferenceRead.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it } from 'node:test'; - -import type { VideoConference } from '@rocket.chat/apps-engine/definition/videoConferences'; - -import { VideoConferenceRead } from '../../../src/server/accessors'; -import type { VideoConferenceBridge } from '../../../src/server/bridges'; -import { TestData } from '../../test-data/utilities'; - -describe('VideoConferenceRead', () => { - it('expectDataFromVideoConferenceRead', async () => { - const videoConference = TestData.getVideoConference(); - - const call = videoConference; - const mockVideoConfBridge = { - doGetById(id, appId): Promise { - return Promise.resolve(call); - }, - } as VideoConferenceBridge; - - assert.doesNotThrow(() => new VideoConferenceRead(mockVideoConfBridge, 'testing-app')); - - const read = new VideoConferenceRead(mockVideoConfBridge, 'testing-app'); - - assert.ok((await read.getById('fake')) !== undefined); - assert.strictEqual(await read.getById('fake'), videoConference); - }); -}); diff --git a/packages/apps/tests/server/managers/AppAccessorManager.test.ts b/packages/apps/tests/server/managers/AppAccessorManager.test.ts deleted file mode 100644 index ba98152dd2f8a..0000000000000 --- a/packages/apps/tests/server/managers/AppAccessorManager.test.ts +++ /dev/null @@ -1,174 +0,0 @@ -import * as assert from 'node:assert'; -import { describe, it, beforeEach, afterEach, mock } from 'node:test'; - -import type { AppManager } from '../../../src/server/AppManager'; -import type { ProxiedApp } from '../../../src/server/ProxiedApp'; -import type { AppBridges } from '../../../src/server/bridges'; -import type { - AppApiManager, - AppExternalComponentManager, - AppSchedulerManager, - AppSlashCommandManager, - AppVideoConfProviderManager, -} from '../../../src/server/managers'; -import { AppAccessorManager } from '../../../src/server/managers'; -import type { AppOutboundCommunicationProviderManager } from '../../../src/server/managers/AppOutboundCommunicationProviderManager'; -import type { UIActionButtonManager } from '../../../src/server/managers/UIActionButtonManager'; -import { TestsAppBridges } from '../../test-data/bridges/appBridges'; - -describe('AppAccessorManager', () => { - let bridges: AppBridges; - let manager: AppManager; - let spies: { - getServerSettingBridge: any; - getEnvironmentalVariableBridge: any; - getMessageBridge: any; - getPersistenceBridge: any; - getRoomBridge: any; - getUserBridge: any; - getBridges: any; - getCommandManager: any; - getExternalComponentManager: any; - getApiManager: any; - }; - - beforeEach(() => { - bridges = new TestsAppBridges(); - - const brds = bridges; - manager = { - getBridges() { - return brds; - }, - getCommandManager() { - return {} as AppSlashCommandManager; - }, - getExternalComponentManager() { - return {} as AppExternalComponentManager; - }, - getApiManager() { - return {} as AppApiManager; - }, - getOneById(appId: string): ProxiedApp { - return appId === 'testing' ? ({} as ProxiedApp) : undefined; - }, - getSchedulerManager() { - return {} as AppSchedulerManager; - }, - getUIActionButtonManager() { - return {} as UIActionButtonManager; - }, - getVideoConfProviderManager() { - return {} as AppVideoConfProviderManager; - }, - getOutboundCommunicationProviderManager() { - return {} as AppOutboundCommunicationProviderManager; - }, - } as unknown as AppManager; - - // Set up spies before each test - spies = { - getServerSettingBridge: mock.method(bridges, 'getServerSettingBridge'), - getEnvironmentalVariableBridge: mock.method(bridges, 'getEnvironmentalVariableBridge'), - getMessageBridge: mock.method(bridges, 'getMessageBridge'), - getPersistenceBridge: mock.method(bridges, 'getPersistenceBridge'), - getRoomBridge: mock.method(bridges, 'getRoomBridge'), - getUserBridge: mock.method(bridges, 'getUserBridge'), - getBridges: mock.method(manager, 'getBridges'), - getCommandManager: mock.method(manager, 'getCommandManager'), - getExternalComponentManager: mock.method(manager, 'getExternalComponentManager'), - getApiManager: mock.method(manager, 'getApiManager'), - }; - }); - - afterEach(() => { - mock.restoreAll(); - }); - - it('basicAppAccessorManager', () => { - assert.doesNotThrow(() => new AppAccessorManager(manager)); - assert.doesNotThrow(() => new AppAccessorManager(manager).purifyApp('testing')); - }); - - it('configurationExtend', () => { - const acm = new AppAccessorManager(manager); - - assert.ok(acm.getConfigurationExtend('testing')); - assert.throws(() => acm.getConfigurationExtend('fake'), { - name: 'Error', - message: 'No App found by the provided id: fake', - }); - assert.ok(acm.getConfigurationExtend('testing')); - - assert.strictEqual(spies.getExternalComponentManager.mock.calls.length, 1); - assert.strictEqual(spies.getCommandManager.mock.calls.length, 1); - assert.strictEqual(spies.getApiManager.mock.calls.length, 1); - }); - - it('environmentRead', () => { - const acm = new AppAccessorManager(manager); - - assert.ok(acm.getEnvironmentRead('testing')); - assert.throws(() => acm.getEnvironmentRead('fake'), { - name: 'Error', - message: 'No App found by the provided id: fake', - }); - assert.ok(acm.getEnvironmentRead('testing')); - - assert.strictEqual(spies.getServerSettingBridge.mock.calls.length, 1); - assert.strictEqual(spies.getEnvironmentalVariableBridge.mock.calls.length, 1); - }); - - it('configurationModify', () => { - const acm = new AppAccessorManager(manager); - - assert.ok(acm.getConfigurationModify('testing')); - assert.ok(acm.getConfigurationModify('testing')); - - assert.strictEqual(spies.getServerSettingBridge.mock.calls.length, 1); - assert.strictEqual(spies.getCommandManager.mock.calls.length, 1); - }); - - it('reader', () => { - const acm = new AppAccessorManager(manager); - - assert.ok(acm.getReader('testing')); - assert.ok(acm.getReader('testing')); - - assert.strictEqual(spies.getServerSettingBridge.mock.calls.length, 1); - assert.strictEqual(spies.getEnvironmentalVariableBridge.mock.calls.length, 1); - assert.strictEqual(spies.getPersistenceBridge.mock.calls.length, 1); - assert.strictEqual(spies.getRoomBridge.mock.calls.length, 1); - assert.strictEqual(spies.getUserBridge.mock.calls.length, 2); - assert.strictEqual(spies.getMessageBridge.mock.calls.length, 2); - }); - - it('modifier', () => { - const acm = new AppAccessorManager(manager); - - assert.ok(acm.getModifier('testing')); - assert.ok(acm.getModifier('testing')); - - assert.strictEqual(spies.getBridges.mock.calls.length, 1); - assert.strictEqual(spies.getMessageBridge.mock.calls.length, 1); - }); - - it('persistence', () => { - const acm = new AppAccessorManager(manager); - - assert.ok(acm.getPersistence('testing')); - assert.ok(acm.getPersistence('testing')); - - assert.strictEqual(spies.getPersistenceBridge.mock.calls.length, 1); - }); - - it('http', () => { - const acm = new AppAccessorManager(manager); - - assert.ok(acm.getHttp('testing')); - assert.ok(acm.getHttp('testing')); - - (acm as any).https.delete('testing'); - assert.ok(acm.getHttp('testing')); - }); -}); diff --git a/packages/apps/tests/server/managers/AppApiManager.test.ts b/packages/apps/tests/server/managers/AppApiManager.test.ts index 9437a6ffea674..0e3d15513fd34 100644 --- a/packages/apps/tests/server/managers/AppApiManager.test.ts +++ b/packages/apps/tests/server/managers/AppApiManager.test.ts @@ -13,7 +13,7 @@ import type { AppSlashCommandManager, AppVideoConfProviderManager, } from '../../../src/server/managers'; -import { AppAccessorManager, AppApiManager } from '../../../src/server/managers'; +import { AppApiManager } from '../../../src/server/managers'; import { AppApi } from '../../../src/server/managers/AppApi'; import type { UIActionButtonManager } from '../../../src/server/managers/UIActionButtonManager'; import type { AppLogStorage, IAppStorageItem } from '../../../src/server/storage'; @@ -24,7 +24,6 @@ import { TestData } from '../../test-data/utilities'; describe('AppApiManager', () => { let mockBridges: TestsAppBridges; let mockApp: ProxiedApp; - let mockAccessors: AppAccessorManager; let mockManager: AppManager; beforeEach(() => { @@ -63,12 +62,6 @@ describe('AppApiManager', () => { return {} as AppVideoConfProviderManager; }, } as AppManager; - - mockAccessors = new AppAccessorManager(mockManager); - const ac = mockAccessors; - mockManager.getAccessorManager = function _getAccessorManager(): AppAccessorManager { - return ac; - }; }); afterEach(() => { @@ -82,7 +75,6 @@ describe('AppApiManager', () => { const ascm = new AppApiManager(mockManager); assert.strictEqual((ascm as any).manager, mockManager); assert.strictEqual((ascm as any).bridge, mockBridges.getApiBridge()); - assert.strictEqual((ascm as any).accessors, mockManager.getAccessorManager()); assert.ok((ascm as any).providedApis !== undefined); assert.strictEqual((ascm as any).providedApis.size, 0); }); diff --git a/packages/apps/tests/server/managers/AppListenerManager.test.ts b/packages/apps/tests/server/managers/AppListenerManager.test.ts index 6bb43f31d4262..1ab2198342eff 100644 --- a/packages/apps/tests/server/managers/AppListenerManager.test.ts +++ b/packages/apps/tests/server/managers/AppListenerManager.test.ts @@ -20,7 +20,6 @@ describe('AppListenerManager', () => { } as ProxiedApp; const mockManager = { - getAccessorManager() {}, getOneById(appId: string) { return mockApp; }, diff --git a/packages/apps/tests/server/managers/AppOutboundCommunicationProviderManager.test.ts b/packages/apps/tests/server/managers/AppOutboundCommunicationProviderManager.test.ts index a025ab297c9b7..424b44f905a0b 100644 --- a/packages/apps/tests/server/managers/AppOutboundCommunicationProviderManager.test.ts +++ b/packages/apps/tests/server/managers/AppOutboundCommunicationProviderManager.test.ts @@ -5,7 +5,7 @@ import type { AppManager } from '../../../src/server/AppManager'; import type { ProxiedApp } from '../../../src/server/ProxiedApp'; import type { AppBridges } from '../../../src/server/bridges'; import type { AppApiManager, AppExternalComponentManager, AppSchedulerManager, AppSlashCommandManager } from '../../../src/server/managers'; -import { AppAccessorManager, AppOutboundCommunicationProviderManager } from '../../../src/server/managers'; +import { AppOutboundCommunicationProviderManager } from '../../../src/server/managers'; import { OutboundMessageProvider } from '../../../src/server/managers/AppOutboundCommunicationProvider'; import { AppPermissionManager } from '../../../src/server/managers/AppPermissionManager'; import type { UIActionButtonManager } from '../../../src/server/managers/UIActionButtonManager'; @@ -17,7 +17,6 @@ import { TestData } from '../../test-data/utilities'; describe('AppOutboundCommunicationProviderManager', () => { let mockBridges: TestsAppBridges; let mockApp: ProxiedApp; - let mockAccessors: AppAccessorManager; let mockManager: AppManager; let hasPermissionSpy: ReturnType; @@ -59,12 +58,6 @@ describe('AppOutboundCommunicationProviderManager', () => { }, } as AppManager; - mockAccessors = new AppAccessorManager(mockManager); - const ac = mockAccessors; - mockManager.getAccessorManager = function _getAccessorManager(): AppAccessorManager { - return ac; - }; - hasPermissionSpy = mock.method(AppPermissionManager, 'hasPermission', () => true); }); @@ -78,7 +71,6 @@ describe('AppOutboundCommunicationProviderManager', () => { const manager = new AppOutboundCommunicationProviderManager(mockManager); assert.strictEqual((manager as any).manager, mockManager); - assert.strictEqual((manager as any).accessors, mockManager.getAccessorManager()); assert.ok((manager as any).outboundMessageProviders !== undefined); assert.strictEqual((manager as any).outboundMessageProviders.size, 0); }); diff --git a/packages/apps/tests/server/managers/AppSettingsManager.test.ts b/packages/apps/tests/server/managers/AppSettingsManager.test.ts index 83f2fd28b53dc..9bb2c5a589cca 100644 --- a/packages/apps/tests/server/managers/AppSettingsManager.test.ts +++ b/packages/apps/tests/server/managers/AppSettingsManager.test.ts @@ -14,7 +14,7 @@ import type { AppSlashCommandManager, AppVideoConfProviderManager, } from '../../../src/server/managers'; -import { AppAccessorManager, AppSettingsManager } from '../../../src/server/managers'; +import { AppSettingsManager } from '../../../src/server/managers'; import type { UIActionButtonManager } from '../../../src/server/managers/UIActionButtonManager'; import type { AppMetadataStorage, IAppStorageItem } from '../../../src/server/storage'; import { TestsAppBridges } from '../../test-data/bridges/appBridges'; @@ -24,7 +24,6 @@ describe('AppSettingsManager', () => { let mockStorageItem: IAppStorageItem; let mockApp: ProxiedApp; let mockBridges: AppBridges; - let mockAccessors: AppAccessorManager; let mockStorage: AppMetadataStorage; let mockManager: AppManager; @@ -90,12 +89,6 @@ describe('AppSettingsManager', () => { return {} as AppVideoConfProviderManager; }, } as AppManager; - - mockAccessors = new AppAccessorManager(mockManager); - const ac = mockAccessors; - mockManager.getAccessorManager = function _getAccessorManager(): AppAccessorManager { - return ac; - }; }); afterEach(() => { diff --git a/packages/apps/tests/server/managers/AppSlashCommandManager.test.ts b/packages/apps/tests/server/managers/AppSlashCommandManager.test.ts index 53f3086db4f5b..8de894ab4b492 100644 --- a/packages/apps/tests/server/managers/AppSlashCommandManager.test.ts +++ b/packages/apps/tests/server/managers/AppSlashCommandManager.test.ts @@ -13,7 +13,7 @@ import type { AppSchedulerManager, AppVideoConfProviderManager, } from '../../../src/server/managers'; -import { AppAccessorManager, AppSlashCommandManager } from '../../../src/server/managers'; +import { AppSlashCommandManager } from '../../../src/server/managers'; import { AppSlashCommand } from '../../../src/server/managers/AppSlashCommand'; import type { UIActionButtonManager } from '../../../src/server/managers/UIActionButtonManager'; import { Room } from '../../../src/server/rooms/Room'; @@ -25,7 +25,6 @@ import { TestData } from '../../test-data/utilities'; describe('AppSlashCommandManager', () => { let mockBridges: TestsAppBridges; let mockApp: ProxiedApp; - let mockAccessors: AppAccessorManager; let mockManager: AppManager; function setupMocks() { @@ -78,12 +77,6 @@ describe('AppSlashCommandManager', () => { return {} as AppVideoConfProviderManager; }, } as AppManager; - - mockAccessors = new AppAccessorManager(mockManager); - const ac = mockAccessors; - mockManager.getAccessorManager = function _getAccessorManager(): AppAccessorManager { - return ac; - }; }); afterEach(() => { @@ -98,7 +91,6 @@ describe('AppSlashCommandManager', () => { const ascm = new AppSlashCommandManager(mockManager); assert.strictEqual((ascm as any).manager, mockManager); assert.strictEqual((ascm as any).bridge, mockBridges.getCommandBridge()); - assert.strictEqual((ascm as any).accessors, mockManager.getAccessorManager()); assert.ok((ascm as any).providedCommands !== undefined); assert.strictEqual((ascm as any).providedCommands.size, 0); assert.ok((ascm as any).modifiedCommands !== undefined); diff --git a/packages/apps/tests/server/managers/AppVideoConfProviderManager.test.ts b/packages/apps/tests/server/managers/AppVideoConfProviderManager.test.ts index 16265aaa07ffd..a803b54172c37 100644 --- a/packages/apps/tests/server/managers/AppVideoConfProviderManager.test.ts +++ b/packages/apps/tests/server/managers/AppVideoConfProviderManager.test.ts @@ -5,7 +5,7 @@ import type { AppManager } from '../../../src/server/AppManager'; import type { ProxiedApp } from '../../../src/server/ProxiedApp'; import type { AppBridges } from '../../../src/server/bridges'; import type { AppApiManager, AppExternalComponentManager, AppSchedulerManager, AppSlashCommandManager } from '../../../src/server/managers'; -import { AppAccessorManager, AppVideoConfProviderManager } from '../../../src/server/managers'; +import { AppVideoConfProviderManager } from '../../../src/server/managers'; import { AppVideoConfProvider } from '../../../src/server/managers/AppVideoConfProvider'; import type { UIActionButtonManager } from '../../../src/server/managers/UIActionButtonManager'; import type { AppLogStorage, IAppStorageItem } from '../../../src/server/storage'; @@ -16,7 +16,6 @@ import { TestData } from '../../test-data/utilities'; describe('AppVideoConfProviderManager', () => { let mockBridges: TestsAppBridges; let mockApp: ProxiedApp; - let mockAccessors: AppAccessorManager; let mockManager: AppManager; beforeEach(() => { @@ -55,12 +54,6 @@ describe('AppVideoConfProviderManager', () => { return {} as AppVideoConfProviderManager; }, } as AppManager; - - mockAccessors = new AppAccessorManager(mockManager); - const ac = mockAccessors; - mockManager.getAccessorManager = function _getAccessorManager(): AppAccessorManager { - return ac; - }; }); afterEach(() => { @@ -73,7 +66,6 @@ describe('AppVideoConfProviderManager', () => { const manager = new AppVideoConfProviderManager(mockManager); assert.strictEqual((manager as any).manager, mockManager); - assert.strictEqual((manager as any).accessors, mockManager.getAccessorManager()); assert.ok((manager as any).videoConfProviders !== undefined); assert.strictEqual((manager as any).videoConfProviders.size, 0); }); diff --git a/packages/apps/tests/server/runtime/DenoRuntimeSubprocessController.test.ts b/packages/apps/tests/server/runtime/DenoRuntimeSubprocessController.test.ts index d569ca5627d65..2a80dbb553886 100644 --- a/packages/apps/tests/server/runtime/DenoRuntimeSubprocessController.test.ts +++ b/packages/apps/tests/server/runtime/DenoRuntimeSubprocessController.test.ts @@ -6,12 +6,11 @@ import * as path from 'node:path'; import { describe, it, afterEach, mock, before, after } from 'node:test'; import { AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus'; -import { UserStatusConnection, UserType } from '@rocket.chat/apps-engine/definition/users'; import { type RpcStatusType, SuccessObject } from 'jsonrpc-lite'; import type { AppManager } from '../../../src/server/AppManager'; import type { IParseAppPackageResult } from '../../../src/server/compiler'; -import { AppAccessorManager, AppApiManager } from '../../../src/server/managers'; +import { AppApiManager } from '../../../src/server/managers'; import { DenoRuntimeSubprocessController } from '../../../src/server/runtime/deno/AppsEngineDenoRuntime'; import type { IAppStorageItem } from '../../../src/server/storage'; import { TestInfastructureSetup } from '../../test-data/utilities'; @@ -29,9 +28,6 @@ describe('DenoRuntimeSubprocessController', () => { const infrastructure = new TestInfastructureSetup(); manager = infrastructure.getMockManager(); - const accessors = new AppAccessorManager(manager); - manager.getAccessorManager = () => accessors; - const api = new AppApiManager(manager); manager.getApiManager = () => api; @@ -65,138 +61,6 @@ describe('DenoRuntimeSubprocessController', () => { { timeout: 30_000 }, ); - it('correctly identifies a call to the HTTP accessor', { timeout: 15_000 }, async () => { - const httpBridge = manager.getBridges().getHttpBridge(); - const doCallSpy = mock.method(httpBridge, 'doCall'); - - const r = await controller['handleAccessorMessage']({ - type: rpcTypeRequest, - payload: { - jsonrpc: '2.0', - id: 'test', - method: 'accessor:getHttp:get', - params: ['https://google.com', { content: "{ test: 'test' }" }], - serialize: () => '', - }, - }); - - assert.strictEqual(doCallSpy.mock.calls.length, 1, 'doCallSpy.mock.calls.length'); - const callArgs = doCallSpy.mock.calls[0].arguments; - assert.partialDeepStrictEqual( - callArgs[0], - { - appId: '9c1d62ca-e40f-456f-8601-17c823a16c68', - method: 'get', - url: 'https://google.com', - }, - 'callArgs[0]', - ); - - assert.deepStrictEqual( - r.result, - { - method: 'get', - url: 'https://google.com', - content: "{ test: 'test' }", - statusCode: 200, - headers: {}, - }, - 'r.result', - ); - }); - - it('correctly identifies a call to the IRead accessor', { timeout: 15_000 }, async () => { - const userBridge = manager.getBridges().getUserBridge(); - const doGetByUsernameSpy = mock.method(userBridge, 'doGetByUsername', () => - Promise.resolve({ - id: 'id', - username: 'rocket.cat', - isEnabled: true, - emails: [], - name: 'name', - roles: [], - type: UserType.USER, - active: true, - utcOffset: 0, - status: 'offline', - statusConnection: UserStatusConnection.OFFLINE, - lastLoginAt: new Date(), - createdAt: new Date(), - updatedAt: new Date(), - }), - ); - - const { id, result } = await controller['handleAccessorMessage']({ - type: rpcTypeRequest, - payload: { - jsonrpc: '2.0', - id: 'test', - method: 'accessor:getReader:getUserReader:getByUsername', - params: ['rocket.cat'], - serialize: () => '', - }, - }); - - assert.strictEqual(doGetByUsernameSpy.mock.calls.length, 1); - assert.deepStrictEqual(doGetByUsernameSpy.mock.calls[0].arguments, ['rocket.cat', '9c1d62ca-e40f-456f-8601-17c823a16c68']); - - assert.strictEqual(id, 'test'); - assert.partialDeepStrictEqual(result, { username: 'rocket.cat' }); - }); - - it('correctly identifies a call to the IEnvironmentReader accessor via IRead', { timeout: 15_000 }, async () => { - const { id, result } = await controller['handleAccessorMessage']({ - type: rpcTypeRequest, - payload: { - jsonrpc: '2.0', - id: 'requestId', - method: 'accessor:getReader:getEnvironmentReader:getServerSettings:getOneById', - params: ['setting test id'], - serialize: () => '', - }, - }); - - assert.strictEqual(id, 'requestId'); - assert.partialDeepStrictEqual(result, { id: 'setting test id' }); - }); - - it('correctly identifies a call to create a visitor via the LivechatCreator', { timeout: 15_000 }, async () => { - const livechatBridge = manager.getBridges().getLivechatBridge(); - const doCreateVisitorSpy = mock.method(livechatBridge, 'doCreateVisitor', () => Promise.resolve('random id')); - - const { id, result } = await controller['handleAccessorMessage']({ - type: rpcTypeRequest, - payload: { - jsonrpc: '2.0', - id: 'requestId', - method: 'accessor:getModifier:getCreator:getLivechatCreator:createVisitor', - params: [ - { - id: 'random id', - token: 'random token', - username: 'random username for visitor', - name: 'Random Visitor', - }, - ], - serialize: () => '', - }, - }); - - assert.strictEqual(doCreateVisitorSpy.mock.calls.length, 1); - assert.deepStrictEqual(doCreateVisitorSpy.mock.calls[0].arguments, [ - { - id: 'random id', - token: 'random token', - username: 'random username for visitor', - name: 'Random Visitor', - }, - '9c1d62ca-e40f-456f-8601-17c823a16c68', - ]); - - assert.strictEqual(id, 'requestId'); - assert.strictEqual(result, 'random id'); - }); - it('correctly identifies a call to the message bridge', { timeout: 15_000 }, async () => { const messageBridge = manager.getBridges().getMessageBridge(); const doCreateSpy = mock.method(messageBridge, 'doCreate', () => Promise.resolve('random-message-id')); diff --git a/packages/apps/tests/server/runtime/SecureFieldsCodecCompatibility.test.ts b/packages/apps/tests/server/runtime/SecureFieldsCodecCompatibility.test.ts index 869442e4121d4..cde673951c2ad 100644 --- a/packages/apps/tests/server/runtime/SecureFieldsCodecCompatibility.test.ts +++ b/packages/apps/tests/server/runtime/SecureFieldsCodecCompatibility.test.ts @@ -10,7 +10,7 @@ import { RoomType } from '@rocket.chat/apps-engine/definition/rooms'; import { kSecureFields } from '../../../src/lib/SecureFields'; import type { AppManager } from '../../../src/server/AppManager'; import type { IParseAppPackageResult } from '../../../src/server/compiler'; -import { AppAccessorManager, AppApiManager } from '../../../src/server/managers'; +import { AppApiManager } from '../../../src/server/managers'; import { DenoRuntimeSubprocessController } from '../../../src/server/runtime/deno/AppsEngineDenoRuntime'; import type { IAppStorageItem } from '../../../src/server/storage'; import { TestInfastructureSetup } from '../../test-data/utilities'; @@ -75,9 +75,6 @@ describe('@@SecureFields codec compatibility (Node → Deno)', () => { const infrastructure = new TestInfastructureSetup(); const manager = infrastructure.getMockManager(); - const accessors = new AppAccessorManager(manager); - manager.getAccessorManager = () => accessors; - const api = new AppApiManager(manager); manager.getApiManager = () => api;