import { Message, Room } from '@rocket.chat/core-services'; import type { IUser } from '@rocket.chat/core-typings'; import { isRoomNativeFederated } from '@rocket.chat/core-typings'; import { Integrations, Rooms, Subscriptions } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; import type { Document, UpdateResult } from 'mongodb'; import { callbacks } from '../../callbacks'; import { notifyOnIntegrationChangedByChannels, notifyOnSubscriptionChangedByRoomId } from '../../notifyListener'; import { checkUsernameAvailability } from '../../users/checkUsernameAvailability'; import { getValidRoomName } from '../../utils/lib/getValidRoomName'; import { roomCoordinator } from '../roomCoordinator'; const updateFName = async (rid: string, displayName: string): Promise<(UpdateResult | Document)[]> => { const responses = await Promise.all([Rooms.setFnameById(rid, displayName), Subscriptions.updateFnameByRoomId(rid, displayName)]); if (responses[1]?.modifiedCount) { void notifyOnSubscriptionChangedByRoomId(rid); } return responses; }; const updateRoomName = async (rid: string, displayName: string, slugifiedRoomName: string) => { // Check if the name is available if (!(await checkUsernameAvailability(slugifiedRoomName, 'room'))) { throw new Meteor.Error('error-duplicate-handle', `A room, team or user with name '${slugifiedRoomName}' already exists`, { function: 'RocketChat.updateRoomName', handle: slugifiedRoomName, }); } const responses = await Promise.all([ Rooms.setNameById(rid, slugifiedRoomName, displayName), Subscriptions.updateNameAndAlertByRoomId(rid, slugifiedRoomName, displayName), ]); if (responses[1]?.modifiedCount) { void notifyOnSubscriptionChangedByRoomId(rid); } return responses; }; export async function saveRoomName( rid: string, displayName: string | undefined, user: IUser, sendMessage = true, ): Promise { const room = await Rooms.findOneById(rid); if (!room) { throw new Meteor.Error('error-invalid-room', 'Invalid room', { function: 'RocketChat.saveRoomdisplayName', }); } if (roomCoordinator.getRoomDirectives(room.t).preventRenaming()) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { function: 'RocketChat.saveRoomdisplayName', }); } await Room.beforeNameChange(room); if (isRoomNativeFederated(room)) { displayName = `${displayName}:${room.federation.mrid.split(':').pop()}`; } if (displayName === room.name) { return; } if (!displayName?.trim()) { return; } const isDiscussion = Boolean(room?.prid); const slugifiedRoomName = isDiscussion || isRoomNativeFederated(room) ? displayName : await getValidRoomName(displayName, rid); let update; if (isDiscussion || isRoomNativeFederated(room)) { update = await updateFName(rid, displayName); } else { update = await updateRoomName(rid, displayName, slugifiedRoomName); } if (!update) { return; } if (room.name && !isDiscussion) { await Integrations.updateRoomName(room.name, slugifiedRoomName); void notifyOnIntegrationChangedByChannels([slugifiedRoomName]); } if (sendMessage) { await Message.saveSystemMessage('r', rid, displayName, user); } await callbacks.run('afterRoomNameChange', { room, name: displayName, oldName: room.name, user }); return displayName; }