From 603ade221c83b1fb31d8e300823782dca8949529 Mon Sep 17 00:00:00 2001 From: Rafael Tapia Date: Fri, 20 May 2022 13:47:17 -0400 Subject: [PATCH] [NEW] Add user events for apps (#25165) * Add user events for apps * Remove trycatch validation * Get the user entity after the update * Trigger events when the user updates his profile or deletes his account * Update Apps-Engine * Make update return doc after update * Find user after the update to trigger event with correct data * Change where clause to use userData instead of userId * Update apps-engine --- .../meteor/app/apps/server/bridges/listeners.js | 17 +++++++++++++++++ .../app/authentication/server/startup/index.js | 5 +++++ .../meteor/app/lib/server/functions/saveUser.js | 13 +++++++++++++ .../lib/server/methods/deleteUserOwnAccount.ts | 4 ++++ apps/meteor/server/methods/deleteUser.js | 4 ++++ apps/meteor/server/methods/saveUserProfile.js | 10 ++++++++++ yarn.lock | 6 +++--- 7 files changed, 56 insertions(+), 3 deletions(-) diff --git a/apps/meteor/app/apps/server/bridges/listeners.js b/apps/meteor/app/apps/server/bridges/listeners.js index 3528aeebe588..514ca2ff6c39 100644 --- a/apps/meteor/app/apps/server/bridges/listeners.js +++ b/apps/meteor/app/apps/server/bridges/listeners.js @@ -43,6 +43,10 @@ export class AppListenerBridge { case AppInterface.IPostLivechatGuestSaved: case AppInterface.IPostLivechatRoomSaved: return 'livechatEvent'; + case AppInterface.IPostUserCreated: + case AppInterface.IPostUserUpdated: + case AppInterface.IPostUserDeleted: + return 'userEvent'; default: return 'defaultEvent'; } @@ -134,4 +138,17 @@ export class AppListenerBridge { return this.orch.getManager().getListenerManager().executeListener(inte, room); } } + + async userEvent(inte, data) { + const context = { + user: this.orch.getConverters().get('users').convertToApp(data.user), + performedBy: this.orch.getConverters().get('users').convertToApp(data.performedBy), + }; + + if (inte === AppInterface.IPostUserUpdated) { + context.previousData = this.orch.getConverters().get('users').convertToApp(data.previousUser); + } + + return this.orch.getManager().getListenerManager().executeListener(inte, context); + } } diff --git a/apps/meteor/app/authentication/server/startup/index.js b/apps/meteor/app/authentication/server/startup/index.js index 557c6454fee0..b4d58c2fe572 100644 --- a/apps/meteor/app/authentication/server/startup/index.js +++ b/apps/meteor/app/authentication/server/startup/index.js @@ -17,6 +17,7 @@ import { isValidAttemptByUser, isValidLoginAttemptByIp } from '../lib/restrictLo import './settings'; import { getClientAddress } from '../../../../server/lib/getClientAddress'; import { getNewUserRoles } from '../../../../server/services/user/lib/getNewUserRoles'; +import { AppEvents, Apps } from '../../../apps/server/orchestrator'; Accounts.config({ forbidClientAccountCreation: true, @@ -210,6 +211,10 @@ Accounts.onCreateUser(function (options, user = {}) { } callbacks.run('onCreateUser', options, user); + + // App IPostUserCreated event hook + Promise.await(Apps.triggerEvent(AppEvents.IPostUserCreated, { user, performedBy: Meteor.user() })); + return user; }); diff --git a/apps/meteor/app/lib/server/functions/saveUser.js b/apps/meteor/app/lib/server/functions/saveUser.js index 787686ff72c3..40d96fcb4c06 100644 --- a/apps/meteor/app/lib/server/functions/saveUser.js +++ b/apps/meteor/app/lib/server/functions/saveUser.js @@ -14,6 +14,7 @@ import { saveUserIdentity } from './saveUserIdentity'; import { checkEmailAvailability, checkUsernameAvailability, setUserAvatar, setEmail, setStatusText } from '.'; import { Users } from '../../../models/server'; import { callbacks } from '../../../../lib/callbacks'; +import { AppEvents, Apps } from '../../../apps/server/orchestrator'; const MAX_BIO_LENGTH = 260; const MAX_NICKNAME_LENGTH = 120; @@ -346,6 +347,8 @@ export const saveUser = function (userId, userData) { validateUserEditing(userId, userData); + const oldUserData = Users.findOneById(userId); + // update user if (userData.hasOwnProperty('username') || userData.hasOwnProperty('name')) { if ( @@ -411,6 +414,16 @@ export const saveUser = function (userId, userData) { callbacks.run('afterSaveUser', userData); + // App IPostUserUpdated event hook + const userUpdated = Users.findOneById(userId); + Promise.await( + Apps.triggerEvent(AppEvents.IPostUserUpdated, { + user: userUpdated, + previousUser: oldUserData, + performedBy: Meteor.user(), + }), + ); + if (sendPassword) { _sendUserEmail(settings.get('Password_Changed_Email_Subject'), passwordChangedHtml, userData); } diff --git a/apps/meteor/app/lib/server/methods/deleteUserOwnAccount.ts b/apps/meteor/app/lib/server/methods/deleteUserOwnAccount.ts index cfdf804dbc39..6640f3cca105 100644 --- a/apps/meteor/app/lib/server/methods/deleteUserOwnAccount.ts +++ b/apps/meteor/app/lib/server/methods/deleteUserOwnAccount.ts @@ -7,6 +7,7 @@ import s from 'underscore.string'; import { settings } from '../../../settings/server'; import { Users } from '../../../models/server'; import { deleteUser } from '../functions'; +import { AppEvents, Apps } from '../../../apps/server/orchestrator'; Meteor.methods({ async deleteUserOwnAccount(password, confirmRelinquish) { @@ -51,6 +52,9 @@ Meteor.methods({ await deleteUser(uid, confirmRelinquish); + // App IPostUserDeleted event hook + Promise.await(Apps.triggerEvent(AppEvents.IPostUserDeleted, { user })); + return true; }, }); diff --git a/apps/meteor/server/methods/deleteUser.js b/apps/meteor/server/methods/deleteUser.js index e13dc83e6ca2..9e0b1f161439 100644 --- a/apps/meteor/server/methods/deleteUser.js +++ b/apps/meteor/server/methods/deleteUser.js @@ -5,6 +5,7 @@ import { Users } from '../../app/models'; import { hasPermission } from '../../app/authorization'; import { callbacks } from '../../lib/callbacks'; import { deleteUser } from '../../app/lib/server'; +import { AppEvents, Apps } from '../../app/apps/server/orchestrator'; Meteor.methods({ async deleteUser(userId, confirmRelinquish = false) { @@ -50,6 +51,9 @@ Meteor.methods({ callbacks.run('afterDeleteUser', user); + // App IPostUserDeleted event hook + Promise.await(Apps.triggerEvent(AppEvents.IPostUserDeleted, { user, performedBy: Meteor.user() })); + return true; }, }); diff --git a/apps/meteor/server/methods/saveUserProfile.js b/apps/meteor/server/methods/saveUserProfile.js index ac8ff588e0c0..6182688d3b74 100644 --- a/apps/meteor/server/methods/saveUserProfile.js +++ b/apps/meteor/server/methods/saveUserProfile.js @@ -10,6 +10,7 @@ import { twoFactorRequired } from '../../app/2fa/server/twoFactorRequired'; import { saveUserIdentity } from '../../app/lib/server/functions/saveUserIdentity'; import { compareUserPassword } from '../lib/compareUserPassword'; import { compareUserPasswordHistory } from '../lib/compareUserPasswordHistory'; +import { AppEvents, Apps } from '../../app/apps/server/orchestrator'; function saveUserProfile(settings, customFields) { if (!rcSettings.get('Accounts_AllowUserProfileChange')) { @@ -118,6 +119,15 @@ function saveUserProfile(settings, customFields) { saveCustomFields(this.userId, customFields); } + // App IPostUserUpdated event hook + const updatedUser = Users.findOneById(this.userId); + Promise.await( + Apps.triggerEvent(AppEvents.IPostUserUpdated, { + user: updatedUser, + previousUser: user, + }), + ); + return true; } diff --git a/yarn.lock b/yarn.lock index 9f2987fbf207..a69bc6cec69c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3601,8 +3601,8 @@ __metadata: linkType: hard "@rocket.chat/apps-engine@npm:alpha": - version: 1.31.0-alpha.6070 - resolution: "@rocket.chat/apps-engine@npm:1.31.0-alpha.6070" + version: 1.32.0-alpha.6099 + resolution: "@rocket.chat/apps-engine@npm:1.32.0-alpha.6099" dependencies: adm-zip: ^0.4.9 cryptiles: ^4.1.3 @@ -3610,7 +3610,7 @@ __metadata: semver: ^5.5.0 stack-trace: 0.0.10 uuid: ^3.2.1 - checksum: 98aad03f4b6758cc54923f59dc77df4aca2d70aae510b33d6a75d0db660329d4c9d926bcbc8768ce705479a797bf395d62789533f4289a1753c71bd393c8eb74 + checksum: 68ec386fc1a5daf80408c6a67f28bb19b7e5e4c6387b2e6c33aec9fc6dcc7f2412e738687f23b25af6f7864e648421568f372f76df7d3a06abb1b24d0c747c4b languageName: node linkType: hard