RocketChat/Rocket.Chat

View on GitHub
apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/User.ts

Summary

Maintainability
B
5 hrs
Test Coverage
import type { IUser } from '@rocket.chat/core-typings';
import { Users, MatrixBridgedUser } from '@rocket.chat/models';

import { _setRealName as setRealName } from '../../../../../../app/lib/server/functions/setRealName';
import { setUserAvatar } from '../../../../../../app/lib/server/functions/setUserAvatar';
import { FederatedUser } from '../../../domain/FederatedUser';
import { extractServerNameFromExternalIdentifier } from '../../matrix/converters/room/RoomReceiver';

const createFederatedUserInstance = (externalUserId: string, user: IUser, remote = true): FederatedUser => {
    const federatedUser = FederatedUser.createWithInternalReference(externalUserId, !remote, user);

    return federatedUser;
};

export const getFederatedUserByInternalUsername = async (username: string): Promise<FederatedUser | undefined> => {
    const user = await Users.findOneByUsername(username);
    if (!user) {
        return;
    }
    const internalBridgedUser = await MatrixBridgedUser.getBridgedUserByLocalId(user._id);
    if (!internalBridgedUser) {
        return;
    }
    const { mui: externalUserId, remote } = internalBridgedUser;

    return createFederatedUserInstance(externalUserId, user, remote);
};

export class RocketChatUserAdapter {
    public async getFederatedUserByExternalId(externalUserId: string): Promise<FederatedUser | undefined> {
        const internalBridgedUser = await MatrixBridgedUser.getBridgedUserByExternalUserId(externalUserId);
        if (!internalBridgedUser) {
            return;
        }

        const user = await Users.findOneById(internalBridgedUser.uid);

        if (user) {
            return createFederatedUserInstance(externalUserId, user, internalBridgedUser.remote);
        }
    }

    public async getFederatedUsersByExternalIds(externalUserIds: string[]): Promise<FederatedUser[]> {
        const internalBridgedUsers = await MatrixBridgedUser.getLocalUsersByExternalIds(externalUserIds);
        if (internalBridgedUsers.length === 0) {
            return [];
        }
        const internalUserIds = internalBridgedUsers.map((bridgedUser) => bridgedUser.uid);
        const internalUserIdsMap: Record<string, Record<string, any>> = internalBridgedUsers.reduce(
            (acc, bridgedUser) => ({ ...acc, [bridgedUser.uid]: { mui: bridgedUser.mui, remote: bridgedUser.remote } }),
            {},
        );
        const users = await Users.findByIds(internalUserIds).toArray();

        if (users.length === 0) {
            return [];
        }
        return users.map((user) => createFederatedUserInstance(internalUserIdsMap[user._id].mui, user, internalUserIdsMap[user._id].remote));
    }

    public async getFederatedUserByInternalId(internalUserId: string): Promise<FederatedUser | undefined> {
        const internalBridgedUser = await MatrixBridgedUser.getBridgedUserByLocalId(internalUserId);
        if (!internalBridgedUser) {
            return;
        }
        const { uid: userId, mui: externalUserId, remote } = internalBridgedUser;
        const user = await Users.findOneById(userId);

        if (user) {
            return createFederatedUserInstance(externalUserId, user, remote);
        }
    }

    public async getFederatedUserByInternalUsername(username: string): Promise<FederatedUser | undefined> {
        const user = await Users.findOneByUsername(username);
        if (!user) {
            return;
        }
        const internalBridgedUser = await MatrixBridgedUser.getBridgedUserByLocalId(user._id);
        if (!internalBridgedUser) {
            return;
        }
        const { mui: externalUserId, remote } = internalBridgedUser;

        return createFederatedUserInstance(externalUserId, user, remote);
    }

    public async getInternalUserById(userId: string): Promise<IUser> {
        const user = await Users.findOneById(userId);
        if (!user?.username) {
            throw new Error(`User with internalId ${userId} not found`);
        }
        return user;
    }

    public async getInternalUserByUsername(username: string): Promise<IUser | undefined> {
        return Users.findOneByUsername(username);
    }

    public async createFederatedUser(federatedUser: FederatedUser): Promise<void> {
        const existingLocalUser = federatedUser.getUsername() && (await Users.findOneByUsername(federatedUser.getUsername() as string));
        if (existingLocalUser) {
            return MatrixBridgedUser.createOrUpdateByLocalId(
                existingLocalUser._id,
                federatedUser.getExternalId(),
                federatedUser.isRemote(),
                extractServerNameFromExternalIdentifier(federatedUser.getExternalId()),
            );
        }
        const { insertedId } = await Users.insertOne(federatedUser.getStorageRepresentation());
        return MatrixBridgedUser.createOrUpdateByLocalId(
            insertedId,
            federatedUser.getExternalId(),
            federatedUser.isRemote(),
            extractServerNameFromExternalIdentifier(federatedUser.getExternalId()),
        );
    }

    public async setAvatar(federatedUser: FederatedUser, avatarUrl: string): Promise<void> {
        await setUserAvatar(federatedUser.getInternalReference(), avatarUrl, 'image/jpeg', 'url'); // this mimetype is fixed here, but the function when called with a url as source don't use that mimetype
    }

    public async updateFederationAvatar(internalUserId: string, externalAvatarUrl: string): Promise<void> {
        await Users.setFederationAvatarUrlById(internalUserId, externalAvatarUrl);
    }

    public async updateRealName(internalUser: IUser, name: string): Promise<void> {
        await setRealName(internalUser._id, name, internalUser);
    }
}