From 10ba9789cb81bb43133bcb873c6b37f857b0c887 Mon Sep 17 00:00:00 2001 From: Ricardo Garim Date: Sat, 25 May 2024 11:36:41 -0300 Subject: [PATCH 1/3] refactor: adds listener calls on IntegrationHistory features --- .../integrations/server/lib/updateHistory.ts | 21 ++++++--- .../server/methods/clearIntegrationHistory.ts | 1 + .../outgoing/deleteOutgoingIntegration.ts | 1 + .../app/lib/server/lib/notifyListener.ts | 43 ++++++++++++++++++- .../server/models/raw/IntegrationHistory.ts | 15 ++++++- .../src/models/IIntegrationHistoryModel.ts | 8 +++- 6 files changed, 80 insertions(+), 9 deletions(-) diff --git a/apps/meteor/app/integrations/server/lib/updateHistory.ts b/apps/meteor/app/integrations/server/lib/updateHistory.ts index ed304403e8c7..e8068ad82ac1 100644 --- a/apps/meteor/app/integrations/server/lib/updateHistory.ts +++ b/apps/meteor/app/integrations/server/lib/updateHistory.ts @@ -1,8 +1,8 @@ import type { IIntegrationHistory, OutgoingIntegrationEvent, IIntegration, IMessage, AtLeast } from '@rocket.chat/core-typings'; import { IntegrationHistory } from '@rocket.chat/models'; -import { Random } from '@rocket.chat/random'; import { omit } from '../../../../lib/utils/omit'; +import { notifyOnIntegrationHistoryChangedById, notifyOnIntegrationHistoryChanged } from '../../../lib/server/lib/notifyListener'; export const updateHistory = async ({ historyId, @@ -77,7 +77,12 @@ export const updateHistory = async ({ }; if (historyId) { - await IntegrationHistory.updateOne({ _id: historyId }, { $set: history }); + // Projecting just integration field to comply with existing listener behaviour + const integrationHistory = await IntegrationHistory.updateById(historyId, history, { projection: { 'integration._id': 1 } }); + if (!integrationHistory) { + throw new Error('error-updating-integration-history'); + } + void notifyOnIntegrationHistoryChanged(integrationHistory, 'updated', history); return historyId; } @@ -86,11 +91,15 @@ export const updateHistory = async ({ throw new Error('error-invalid-integration'); } - history._createdAt = new Date(); + // TODO: Had to force type cast here because of function's signature + // It would be easier if we separate into create and update functions + const { insertedId } = await IntegrationHistory.create(history as IIntegrationHistory); - const _id = Random.id(); + if (!insertedId) { + throw new Error('error-creating-integration-history'); + } - await IntegrationHistory.insertOne({ _id, ...history } as IIntegrationHistory); + void notifyOnIntegrationHistoryChangedById(insertedId, 'inserted'); - return _id; + return insertedId; }; diff --git a/apps/meteor/app/integrations/server/methods/clearIntegrationHistory.ts b/apps/meteor/app/integrations/server/methods/clearIntegrationHistory.ts index 2447683bd291..5b8f13ef1a3a 100644 --- a/apps/meteor/app/integrations/server/methods/clearIntegrationHistory.ts +++ b/apps/meteor/app/integrations/server/methods/clearIntegrationHistory.ts @@ -41,6 +41,7 @@ Meteor.methods({ }); } + // Don't sending to IntegrationHistory listener since it don't waits for 'removed' events. await IntegrationHistory.removeByIntegrationId(integrationId); notifications.streamIntegrationHistory.emit(integrationId, { type: 'removed', id: integrationId }); diff --git a/apps/meteor/app/integrations/server/methods/outgoing/deleteOutgoingIntegration.ts b/apps/meteor/app/integrations/server/methods/outgoing/deleteOutgoingIntegration.ts index cc3d138c554a..c9f2211d835b 100644 --- a/apps/meteor/app/integrations/server/methods/outgoing/deleteOutgoingIntegration.ts +++ b/apps/meteor/app/integrations/server/methods/outgoing/deleteOutgoingIntegration.ts @@ -41,6 +41,7 @@ export const deleteOutgoingIntegration = async (integrationId: string, userId: s } await Integrations.removeById(integrationId); + // Don't sending to IntegrationHistory listener since it don't waits for 'removed' events. await IntegrationHistory.removeByIntegrationId(integrationId); void notifyOnIntegrationChangedById(integrationId, 'removed'); }; diff --git a/apps/meteor/app/lib/server/lib/notifyListener.ts b/apps/meteor/app/lib/server/lib/notifyListener.ts index c019eba0db7a..df0073423642 100644 --- a/apps/meteor/app/lib/server/lib/notifyListener.ts +++ b/apps/meteor/app/lib/server/lib/notifyListener.ts @@ -10,8 +10,19 @@ import type { IPbxEvent, LoginServiceConfiguration as LoginServiceConfigurationData, ILivechatPriority, + IIntegrationHistory, + AtLeast, } from '@rocket.chat/core-typings'; -import { Rooms, Permissions, Settings, PbxEvents, Roles, Integrations, LoginServiceConfiguration } from '@rocket.chat/models'; +import { + Rooms, + Permissions, + Settings, + PbxEvents, + Roles, + Integrations, + LoginServiceConfiguration, + IntegrationHistory, +} from '@rocket.chat/models'; type ClientAction = 'inserted' | 'updated' | 'removed'; @@ -254,3 +265,33 @@ export async function notifyOnIntegrationChangedByChannels( + data: AtLeast, + clientAction: ClientAction = 'updated', + diff: Partial = {}, +): Promise { + if (!dbWatchersDisabled) { + return; + } + + void api.broadcast('watch.integrationHistory', { clientAction, id: data._id, data, diff }); +} + +export async function notifyOnIntegrationHistoryChangedById( + id: T['_id'], + clientAction: ClientAction = 'updated', + diff: Partial = {}, +): Promise { + if (!dbWatchersDisabled) { + return; + } + + const item = await IntegrationHistory.findOneById(id); + + if (!item) { + return; + } + + void api.broadcast('watch.integrationHistory', { clientAction, id: item._id, data: item, diff }); +} diff --git a/apps/meteor/server/models/raw/IntegrationHistory.ts b/apps/meteor/server/models/raw/IntegrationHistory.ts index 611c7ca095f1..bf2310a67d0a 100644 --- a/apps/meteor/server/models/raw/IntegrationHistory.ts +++ b/apps/meteor/server/models/raw/IntegrationHistory.ts @@ -1,6 +1,6 @@ import type { IIntegrationHistory } from '@rocket.chat/core-typings'; import type { IIntegrationHistoryModel } from '@rocket.chat/model-typings'; -import type { Db, IndexDescription } from 'mongodb'; +import type { Db, IndexDescription, InsertOneResult, FindOneAndUpdateOptions } from 'mongodb'; import { BaseRaw } from './BaseRaw'; @@ -23,4 +23,17 @@ export class IntegrationHistoryRaw extends BaseRaw implemen findOneByIntegrationIdAndHistoryId(integrationId: string, historyId: string): Promise { return this.findOne({ 'integration._id': integrationId, '_id': historyId }); } + + async create(integrationHistory: IIntegrationHistory): Promise> { + return this.insertOne(integrationHistory); + } + + async updateById( + _id: IIntegrationHistory['_id'], + data: Partial, + options?: FindOneAndUpdateOptions, + ): Promise { + const response = await this.findOneAndUpdate({ _id }, { $set: data }, { returnDocument: 'after', ...options }); + return response.value; + } } diff --git a/packages/model-typings/src/models/IIntegrationHistoryModel.ts b/packages/model-typings/src/models/IIntegrationHistoryModel.ts index 86765893dd53..378142e7519a 100644 --- a/packages/model-typings/src/models/IIntegrationHistoryModel.ts +++ b/packages/model-typings/src/models/IIntegrationHistoryModel.ts @@ -1,9 +1,15 @@ import type { IIntegrationHistory } from '@rocket.chat/core-typings'; +import type { FindOneAndUpdateOptions, InsertOneResult } from 'mongodb'; import type { IBaseModel } from './IBaseModel'; export interface IIntegrationHistoryModel extends IBaseModel { removeByIntegrationId(integrationId: string): ReturnType['deleteMany']>; - findOneByIntegrationIdAndHistoryId(integrationId: string, historyId: string): Promise; + create(integrationHistory: IIntegrationHistory): Promise>; + updateById( + _id: IIntegrationHistory['_id'], + data: Partial, + options?: FindOneAndUpdateOptions, + ): Promise; } From 4e90ee7c18da441744289a385c5c5a09d3170e82 Mon Sep 17 00:00:00 2001 From: Ricardo Garim Date: Sat, 25 May 2024 11:47:06 -0300 Subject: [PATCH 2/3] refactor: adds IntegrationHistory entity on dbWatchersDisabled validation when starting db watcher --- apps/meteor/server/database/watchCollections.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/server/database/watchCollections.ts b/apps/meteor/server/database/watchCollections.ts index 244159cb3e20..1f3628615ebe 100644 --- a/apps/meteor/server/database/watchCollections.ts +++ b/apps/meteor/server/database/watchCollections.ts @@ -34,7 +34,6 @@ export function getWatchCollections(): string[] { LivechatInquiry.getCollectionName(), LivechatDepartmentAgents.getCollectionName(), InstanceStatus.getCollectionName(), - IntegrationHistory.getCollectionName(), EmailInbox.getCollectionName(), Settings.getCollectionName(), Subscriptions.getCollectionName(), @@ -50,6 +49,7 @@ export function getWatchCollections(): string[] { collections.push(Permissions.getCollectionName()); collections.push(LivechatPriority.getCollectionName()); collections.push(LoginServiceConfiguration.getCollectionName()); + collections.push(IntegrationHistory.getCollectionName()); } if (onlyCollections.length > 0) { From a2ea38300468a8e36ad74bc535bf9aacb59055b5 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 27 May 2024 18:10:32 -0300 Subject: [PATCH 3/3] fix: add _createdAt --- apps/meteor/server/models/raw/IntegrationHistory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/server/models/raw/IntegrationHistory.ts b/apps/meteor/server/models/raw/IntegrationHistory.ts index bf2310a67d0a..317bdf41caf0 100644 --- a/apps/meteor/server/models/raw/IntegrationHistory.ts +++ b/apps/meteor/server/models/raw/IntegrationHistory.ts @@ -25,7 +25,7 @@ export class IntegrationHistoryRaw extends BaseRaw implemen } async create(integrationHistory: IIntegrationHistory): Promise> { - return this.insertOne(integrationHistory); + return this.insertOne({ ...integrationHistory, _createdAt: new Date() }); } async updateById(