RocketChat/Rocket.Chat

View on GitHub
apps/meteor/server/methods/channelsList.ts

Summary

Maintainability
D
2 days
Test Coverage
import type { IRoom } from '@rocket.chat/core-typings';
import type { ServerMethods } from '@rocket.chat/ddp-client';
import { Rooms, Subscriptions, Users } from '@rocket.chat/models';
import { Match, check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';
import type { FindOptions } from 'mongodb';
import _ from 'underscore';

import { hasPermissionAsync } from '../../app/authorization/server/functions/hasPermission';
import { settings } from '../../app/settings/server';
import { getUserPreference } from '../../app/utils/server/lib/getUserPreference';
import { trim } from '../../lib/utils/stringUtils';

declare module '@rocket.chat/ddp-client' {
    // eslint-disable-next-line @typescript-eslint/naming-convention
    interface ServerMethods {
        channelsList(filter: string, channelType: string, limit?: number, sort?: string): { channels: IRoom[] };
    }
}

Meteor.methods<ServerMethods>({
    async channelsList(filter, channelType, limit, sort) {
        check(filter, String);
        check(channelType, String);
        check(limit, Match.Optional(Number));
        check(sort, Match.Optional(String));

        const userId = Meteor.userId();

        if (!userId) {
            throw new Meteor.Error('error-invalid-user', 'Invalid user', {
                method: 'channelsList',
            });
        }

        const options: FindOptions<IRoom> = {
            projection: {
                name: 1,
                t: 1,
            },
            sort: {
                msgs: -1,
            },
        };

        if (_.isNumber(limit)) {
            options.limit = limit;
        }

        if (trim(sort)) {
            switch (sort) {
                case 'name':
                    options.sort = {
                        name: 1,
                    };
                    break;
                case 'msgs':
                    options.sort = {
                        msgs: -1,
                    };
            }
        }

        let channels: IRoom[] = [];

        if (channelType !== 'private') {
            if (await hasPermissionAsync(userId, 'view-c-room')) {
                if (filter) {
                    channels = channels.concat(await Rooms.findByTypeAndNameContaining('c', filter, options).toArray());
                } else {
                    channels = channels.concat(await Rooms.findByType('c', options).toArray());
                }
            } else if (await hasPermissionAsync(userId, 'view-joined-room')) {
                const roomIds = (await Subscriptions.findByTypeAndUserId('c', userId, { projection: { rid: 1 } }).toArray()).map((s) => s.rid);
                if (filter) {
                    channels = channels.concat(await Rooms.findByTypeInIdsAndNameContaining('c', roomIds, filter, options).toArray());
                } else {
                    channels = channels.concat(await Rooms.findByTypeInIds('c', roomIds, options).toArray());
                }
            }
        }

        if (channelType !== 'public' && (await hasPermissionAsync(userId, 'view-p-room'))) {
            const user = await Users.findOne(userId, {
                projection: {
                    'username': 1,
                    'settings.preferences.sidebarGroupByType': 1,
                },
            });

            if (!user) {
                throw new Meteor.Error('error-invalid-user', 'Invalid user', {
                    method: 'channelsList',
                });
            }

            const userPref = await getUserPreference(user, 'sidebarGroupByType');
            // needs to negate globalPref because userPref represents its opposite
            const groupByType = userPref !== undefined ? userPref : settings.get('UI_Group_Channels_By_Type');

            if (!groupByType) {
                const roomIds = (await Subscriptions.findByTypeAndUserId('p', userId, { projection: { rid: 1 } }).toArray()).map((s) => s.rid);
                if (filter) {
                    channels = channels.concat(await Rooms.findByTypeInIdsAndNameContaining('p', roomIds, filter, options).toArray());
                } else {
                    channels = channels.concat(await Rooms.findByTypeInIds('p', roomIds, options).toArray());
                }
            }
        }

        return {
            channels,
        };
    },
});