diff --git a/.changeset/hungry-news-travel.md b/.changeset/hungry-news-travel.md new file mode 100644 index 0000000000000..43f7e2f4b8dab --- /dev/null +++ b/.changeset/hungry-news-travel.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': major +--- + +fix realtime user statusText update diff --git a/apps/meteor/app/api/server/v1/users.ts b/apps/meteor/app/api/server/v1/users.ts index a065cc47407c7..f3bff95366196 100644 --- a/apps/meteor/app/api/server/v1/users.ts +++ b/apps/meteor/app/api/server/v1/users.ts @@ -54,7 +54,7 @@ import { generateUsernameSuggestion } from '../../../lib/server/functions/getUse import { saveCustomFields } from '../../../lib/server/functions/saveCustomFields'; import { saveCustomFieldsWithoutValidation } from '../../../lib/server/functions/saveCustomFieldsWithoutValidation'; import { saveUser } from '../../../lib/server/functions/saveUser'; -import { setStatusText } from '../../../lib/server/functions/setStatusText'; +import { getNewStatusText } from '../../../lib/server/functions/setStatusText'; import { setUserAvatar } from '../../../lib/server/functions/setUserAvatar'; import { setUsernameWithValidation } from '../../../lib/server/functions/setUsername'; import { validateCustomFields } from '../../../lib/server/functions/validateCustomFields'; @@ -1313,10 +1313,12 @@ API.v1.addRoute( return API.v1.forbidden(); } - // TODO refactor to not update the user twice (one inside of `setStatusText` and then later just the status + statusDefault) - + const updateFields: Record = {}; if (this.bodyParams.message || this.bodyParams.message === '') { - await setStatusText(user._id, this.bodyParams.message); + const statusText = getNewStatusText(user.statusText, this.bodyParams.message); + if (statusText) { + updateFields.statusText = statusText; + } } if (this.bodyParams.status) { const validStatus = ['online', 'away', 'offline', 'busy']; @@ -1328,29 +1330,29 @@ API.v1.addRoute( method: 'users.setStatus', }); } + updateFields.status = status; + updateFields.statusDefault = status; + } + } + if (Object.keys(updateFields).length > 0) { + await Users.updateOne( + { _id: user._id }, + { + $set: updateFields, + }, + ); - await Users.updateOne( - { _id: user._id }, - { - $set: { - status, - statusDefault: status, - }, - }, - ); - - const { _id, username, statusText, roles, name } = user; - void api.broadcast('presence.status', { - user: { status, _id, username, statusText, roles, name }, - previousStatus: user.status, - }); + const { _id, username, statusText, roles, name, status } = { ...user, ...updateFields }; + void api.broadcast('presence.status', { + user: { status, _id, username, statusText, roles, name }, + previousStatus: user.status, + }); - void wrapExceptions(() => Calendar.cancelUpcomingStatusChanges(user._id)).suppress(); - } else { - throw new Meteor.Error('error-invalid-status', 'Valid status types include online, away, offline, and busy.', { - method: 'users.setStatus', - }); - } + void wrapExceptions(() => Calendar.cancelUpcomingStatusChanges(user._id)).suppress(); + } else { + throw new Meteor.Error('error-invalid-status', 'Valid status types include online, away, offline, and busy.', { + method: 'users.setStatus', + }); } return API.v1.success(); diff --git a/apps/meteor/app/lib/server/functions/setStatusText.ts b/apps/meteor/app/lib/server/functions/setStatusText.ts index 7c81bae0112ed..36f9cb6d12b68 100644 --- a/apps/meteor/app/lib/server/functions/setStatusText.ts +++ b/apps/meteor/app/lib/server/functions/setStatusText.ts @@ -9,13 +9,16 @@ import { onceTransactionCommitedSuccessfully } from '../../../../server/database import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { RateLimiter } from '../lib'; +export const getNewStatusText = (previousStatusText: string | undefined, newStatusText: string) => { + const statusText = newStatusText.trim().substr(0, 120); + return previousStatusText === statusText ? '' : statusText; +}; + async function _setStatusText(userId: string, statusText: string, updater?: Updater, session?: ClientSession): Promise { if (!userId) { return false; } - statusText = statusText.trim().substr(0, 120); - const user = await Users.findOneById>(userId, { projection: { username: 1, name: 1, status: 1, roles: 1, statusText: 1 }, session, @@ -25,7 +28,9 @@ async function _setStatusText(userId: string, statusText: string, updater?: Upda return false; } - if (user.statusText === statusText) { + statusText = getNewStatusText(user.statusText, statusText); + + if (!statusText) { return true; }