Skip to content

Commit

Permalink
refactor: Rooms model 1/2 (#28694)
Browse files Browse the repository at this point in the history
  • Loading branch information
KevLehman committed Mar 30, 2023
1 parent 151323a commit 35499f5
Show file tree
Hide file tree
Showing 22 changed files with 153 additions and 277 deletions.
14 changes: 7 additions & 7 deletions apps/meteor/app/apps/server/bridges/rooms.ts
Expand Up @@ -5,10 +5,10 @@ import type { IUser } from '@rocket.chat/apps-engine/definition/users';
import type { IMessage } from '@rocket.chat/apps-engine/definition/messages';
import { Meteor } from 'meteor/meteor';
import type { ISubscription, IUser as ICoreUser } from '@rocket.chat/core-typings';
import { Subscriptions } from '@rocket.chat/models';
import { Subscriptions, Rooms } from '@rocket.chat/models';

import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator';
import { Rooms, Users } from '../../../models/server';
import { Users } from '../../../models/server';
import { addUserToRoom } from '../../../lib/server/functions/addUserToRoom';
import { deleteRoom } from '../../../lib/server/functions/deleteRoom';

Expand Down Expand Up @@ -72,7 +72,7 @@ export class AppRoomBridge extends RoomBridge {
protected async getCreatorById(roomId: string, appId: string): Promise<IUser | undefined> {
this.orch.debugLog(`The App ${appId} is getting the room's creator by id: "${roomId}"`);

const room = Rooms.findOneById(roomId);
const room = await Rooms.findOneById(roomId);

if (!room || !room.u || !room.u._id) {
return undefined;
Expand All @@ -84,7 +84,7 @@ export class AppRoomBridge extends RoomBridge {
protected async getCreatorByName(roomName: string, appId: string): Promise<IUser | undefined> {
this.orch.debugLog(`The App ${appId} is getting the room's creator by name: "${roomName}"`);

const room = Rooms.findOneByName(roomName, {});
const room = await Rooms.findOneByName(roomName, {});

if (!room || !room.u || !room.u._id) {
return undefined;
Expand All @@ -111,13 +111,13 @@ export class AppRoomBridge extends RoomBridge {
protected async update(room: IRoom, members: Array<string> = [], appId: string): Promise<void> {
this.orch.debugLog(`The App ${appId} is updating a room.`);

if (!room.id || !Rooms.findOneById(room.id)) {
if (!room.id || !(await Rooms.findOneById(room.id))) {
throw new Error('A room must exist to update.');
}

const rm = await this.orch.getConverters()?.get('rooms').convertAppRoom(room);

Rooms.update(rm._id, rm);
await Rooms.updateOne({ _id: rm._id }, { $set: rm });

for await (const username of members) {
const member = Users.findOneByUsername(username, {});
Expand Down Expand Up @@ -151,7 +151,7 @@ export class AppRoomBridge extends RoomBridge {
rcMessage = this.orch.getConverters()?.get('messages').convertAppMessage(parentMessage);
}

if (!rcRoom.prid || !Rooms.findOneById(rcRoom.prid)) {
if (!rcRoom.prid || !(await Rooms.findOneById(rcRoom.prid))) {
throw new Error('There must be a parent room to create a discussion.');
}

Expand Down
Expand Up @@ -13,7 +13,7 @@ const updateFName = async (rid, displayName) => {
};

const updateRoomName = async (rid, displayName) => {
const slugifiedRoomName = getValidRoomName(displayName, rid);
const slugifiedRoomName = await getValidRoomName(displayName, rid);

// Check if the username is available
if (!(await checkUsernameAvailability(slugifiedRoomName))) {
Expand Down
55 changes: 32 additions & 23 deletions apps/meteor/app/importer/server/classes/ImportDataConverter.ts
Expand Up @@ -21,6 +21,7 @@ import { Users, Rooms, Subscriptions } from '../../../models/server';
import { generateUsernameSuggestion, insertMessage, saveUserIdentity, addUserToDefaultChannels } from '../../../lib/server';
import { setUserActiveStatus } from '../../../lib/server/functions/setUserActiveStatus';
import type { Logger } from '../../../../server/lib/logger/Logger';
import { getValidRoomName } from '../../../utils/server/lib/getValidRoomName';

type IRoom = Record<string, any>;
type IMessage = Record<string, any>;
Expand Down Expand Up @@ -494,10 +495,10 @@ export class ImportDataConverter {
return result;
}

getMentionedChannelData(importId: string): IMentionedChannel | undefined {
async getMentionedChannelData(importId: string): Promise<IMentionedChannel | undefined> {
// loading the name will also store the id on the cache if it's missing, so this won't run two queries
const name = this.findImportedRoomName(importId);
const _id = this.findImportedRoomId(importId);
const name = await this.findImportedRoomName(importId);
const _id = await this.findImportedRoomId(importId);

if (name && _id) {
return {
Expand All @@ -507,8 +508,9 @@ export class ImportDataConverter {
}

// If the importId was not found, check if we have a room with that name
const room = Rooms.findOneByNonValidatedName(importId, { fields: { name: 1 } });
if (room) {
const roomName = await getValidRoomName(importId.trim(), undefined, { allowDuplicates: true });
const room = await RoomsRaw.findOneByNonValidatedName(roomName, { projection: { name: 1 } });
if (room?.name) {
this.addRoomToCache(importId, room._id);
this.addRoomNameToCache(importId, room.name);

Expand All @@ -519,15 +521,15 @@ export class ImportDataConverter {
}
}

convertMessageChannels(message: IImportMessage): Array<IMentionedChannel> | undefined {
async convertMessageChannels(message: IImportMessage): Promise<IMentionedChannel[] | undefined> {
const { channels } = message;
if (!channels) {
return;
}

const result: Array<IMentionedChannel> = [];
for (const importId of channels) {
const { name, _id } = this.getMentionedChannelData(importId) || {};
for await (const importId of channels) {
const { name, _id } = (await this.getMentionedChannelData(importId)) || {};

if (!_id || !name) {
this._logger.warn(`Mentioned room not found: ${importId}`);
Expand Down Expand Up @@ -570,7 +572,7 @@ export class ImportDataConverter {
throw new Error('importer-message-unknown-user');
}

const rid = this.findImportedRoomId(data.rid);
const rid = await this.findImportedRoomId(data.rid);
if (!rid) {
throw new Error('importer-message-unknown-room');
}
Expand All @@ -580,7 +582,7 @@ export class ImportDataConverter {

// Convert the mentions and channels first because these conversions can also modify the msg in the message object
const mentions = data.mentions && this.convertMessageMentions(data);
const channels = data.channels && this.convertMessageChannels(data);
const channels = data.channels && (await this.convertMessageChannels(data));

const msgObj: IMessage = {
rid,
Expand Down Expand Up @@ -617,7 +619,7 @@ export class ImportDataConverter {
}

try {
insertMessage(creator, msgObj, rid, true);
await insertMessage(creator, msgObj, rid, true);
} catch (e) {
this._logger.warn(`Failed to import message with timestamp ${String(msgObj.ts)} to room ${rid}`);
this._logger.error(e);
Expand Down Expand Up @@ -661,43 +663,45 @@ export class ImportDataConverter {
}
}

findImportedRoomId(importId: string): string | null {
async findImportedRoomId(importId: string): Promise<string | null> {
if (this._roomCache.has(importId)) {
return this._roomCache.get(importId) as string;
}

const options = {
fields: {
projection: {
_id: 1,
},
};

const room = Rooms.findOneByImportId(importId, options);
const room = await RoomsRaw.findOneByImportId(importId, options);
if (room) {
return this.addRoomToCache(importId, room._id);
}

return null;
}

findImportedRoomName(importId: string): string | undefined {
async findImportedRoomName(importId: string): Promise<string | undefined> {
if (this._roomNameCache.has(importId)) {
return this._roomNameCache.get(importId) as string;
}

const options = {
fields: {
projection: {
_id: 1,
name: 1,
},
};

const room = Rooms.findOneByImportId(importId, options);
const room = await RoomsRaw.findOneByImportId(importId, options);
if (room) {
if (!this._roomCache.has(importId)) {
this.addRoomToCache(importId, room._id);
}
return this.addRoomNameToCache(importId, room.name);
if (room?.name) {
return this.addRoomNameToCache(importId, room.name);
}
}
}

Expand Down Expand Up @@ -874,9 +878,9 @@ export class ImportDataConverter {
.filter((user) => user);
}

findExistingRoom(data: IImportChannel): IRoom {
async findExistingRoom(data: IImportChannel): Promise<IRoom | null> {
if (data._id && data._id.toUpperCase() === 'GENERAL') {
const room = Rooms.findOneById('GENERAL', {});
const room = await RoomsRaw.findOneById('GENERAL', {});
// Prevent the importer from trying to create a new general
if (!room) {
throw new Error('importer-channel-general-not-found');
Expand All @@ -891,10 +895,15 @@ export class ImportDataConverter {
throw new Error('importer-channel-missing-users');
}

return Rooms.findDirectRoomContainingAllUsernames(users, {});
return RoomsRaw.findDirectRoomContainingAllUsernames(users, {});
}

if (!data.name) {
return null;
}

return Rooms.findOneByNonValidatedName(data.name, {});
const roomName = await getValidRoomName(data.name.trim(), undefined, { allowDuplicates: true });
return RoomsRaw.findOneByNonValidatedName(roomName, {});
}

protected async getChannelsToImport(): Promise<Array<IImportChannelRecord>> {
Expand All @@ -921,7 +930,7 @@ export class ImportDataConverter {
throw new Error('importer-channel-missing-import-id');
}

const existingRoom = this.findExistingRoom(data);
const existingRoom = await this.findExistingRoom(data);

if (existingRoom) {
this.updateRoom(existingRoom, data, startedByUserId);
Expand Down
@@ -1,4 +1,6 @@
import { Users, Rooms } from '../../../../models/server';
import { Rooms } from '@rocket.chat/models';

import { Users } from '../../../../models/server';
import { sendMessage, createDirectRoom } from '../../../../lib/server';
/*
*
Expand All @@ -10,7 +12,7 @@ const getDirectRoom = async (source, target) => {
const uids = [source._id, target._id];
const { _id, ...extraData } = await createDirectRoom([source, target]);

const room = Rooms.findOneDirectRoomContainingAllUserIDs(uids);
const room = await Rooms.findOneDirectRoomContainingAllUserIDs(uids);
if (room) {
return {
t: 'd',
Expand All @@ -37,7 +39,7 @@ export default async function handleSentMessage(args) {
let room;

if (args.roomName) {
room = Rooms.findOneByName(args.roomName);
room = await Rooms.findOneByName(args.roomName);
} else {
const recipientUser = Users.findOne({
'profile.irc.nick': args.recipientNick,
Expand Down
@@ -1,15 +1,14 @@
import type { IUser } from '@rocket.chat/core-typings';
import { Subscriptions } from '@rocket.chat/models';
import { Subscriptions, Rooms } from '@rocket.chat/models';
import { Message } from '@rocket.chat/core-services';

import { Rooms } from '../../../models/server';
import { callbacks } from '../../../../lib/callbacks';

export const addUserToDefaultChannels = async function (user: IUser, silenced?: boolean): Promise<void> {
callbacks.run('beforeJoinDefaultChannels', user);
const defaultRooms = Rooms.findByDefaultAndTypes(true, ['c', 'p'], {
fields: { usernames: 0 },
}).fetch();
const defaultRooms = await Rooms.findByDefaultAndTypes(true, ['c', 'p'], {
projection: { usernames: 0 },
}).toArray();
for await (const room of defaultRooms) {
if (!(await Subscriptions.findOneByRoomIdAndUserId(room._id, user._id, { projection: { _id: 1 } }))) {
// Add a subscription to this user
Expand Down
17 changes: 10 additions & 7 deletions apps/meteor/app/lib/server/functions/createDirectRoom.ts
Expand Up @@ -2,11 +2,11 @@ import { AppsEngineException } from '@rocket.chat/apps-engine/definition/excepti
import { Meteor } from 'meteor/meteor';
import { Random } from '@rocket.chat/random';
import type { ICreatedRoom, ISubscription, IUser } from '@rocket.chat/core-typings';
import { Subscriptions } from '@rocket.chat/models';
import { Subscriptions, Rooms } from '@rocket.chat/models';
import type { MatchKeysAndValues } from 'mongodb';
import type { ISubscriptionExtraData } from '@rocket.chat/core-services';

import { Users, Rooms } from '../../../models/server';
import { Users } from '../../../models/server';
import { Apps } from '../../../../ee/server/apps';
import { callbacks } from '../../../../lib/callbacks';
import { settings } from '../../../settings/server';
Expand Down Expand Up @@ -71,8 +71,8 @@ export async function createDirectRoom(
// Deprecated: using users' _id to compose the room _id is deprecated
const room =
uids.length === 2
? Rooms.findOneById(uids.join(''), { fields: { _id: 1 } })
: Rooms.findOneDirectRoomContainingAllUserIDs(uids, { fields: { _id: 1 } });
? await Rooms.findOneById(uids.join(''), { projection: { _id: 1 } })
: await Rooms.findOneDirectRoomContainingAllUserIDs(uids, { projection: { _id: 1 } });

const isNewRoom = !room;

Expand Down Expand Up @@ -114,7 +114,8 @@ export async function createDirectRoom(
delete tmpRoom._USERNAMES;
}

const rid = room?._id || Rooms.insert(roomInfo);
// @ts-expect-error - TODO: room expects `u` to be passed, but it's not part of the original object in here
const rid = room?._id || (await Rooms.insertOne(roomInfo)).insertedId;

if (roomMembers.length === 1) {
// dm to yourself
Expand Down Expand Up @@ -154,18 +155,20 @@ export async function createDirectRoom(

// If the room is new, run a callback
if (isNewRoom) {
const insertedRoom = Rooms.findOneById(rid);
const insertedRoom = await Rooms.findOneById(rid);

callbacks.run('afterCreateDirectRoom', insertedRoom, { members: roomMembers, creatorId: options?.creator });

void Apps.triggerEvent('IPostRoomCreate', insertedRoom);
}

return {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
...room!,
_id: String(rid),
usernames,
t: 'd',
rid,
inserted: isNewRoom,
...room,
};
}
2 changes: 1 addition & 1 deletion apps/meteor/app/lib/server/functions/createRoom.ts
Expand Up @@ -72,7 +72,7 @@ export const createRoom = async <T extends RoomType>(
fname: name,
_updatedAt: now,
...extraData,
name: getValidRoomName(name.trim(), undefined, {
name: await getValidRoomName(name.trim(), undefined, {
...(options?.nameValidationRegex && { nameValidationRegex: options.nameValidationRegex }),
}),
t: type,
Expand Down
10 changes: 6 additions & 4 deletions apps/meteor/app/lib/server/functions/insertMessage.js
@@ -1,8 +1,10 @@
import { Messages, Rooms } from '../../../models/server';
import { Rooms } from '@rocket.chat/models';

import { Messages } from '../../../models/server';
import { validateMessage, prepareMessageObject } from './sendMessage';
import { parseUrlsInMessage } from './parseUrlsInMessage';

export const insertMessage = function (user, message, rid, upsert = false) {
export const insertMessage = async function (user, message, rid, upsert = false) {
if (!user || !message || !rid) {
return false;
}
Expand All @@ -23,12 +25,12 @@ export const insertMessage = function (user, message, rid, upsert = false) {
message,
);
if (!existingMessage) {
Rooms.incMsgCountById(rid, 1);
await Rooms.incMsgCountById(rid, 1);
}
message._id = _id;
} else {
message._id = Messages.insert(message);
Rooms.incMsgCountById(rid, 1);
await Rooms.incMsgCountById(rid, 1);
}

return message;
Expand Down

0 comments on commit 35499f5

Please sign in to comment.