RocketChat/Rocket.Chat

View on GitHub
apps/meteor/app/integrations/server/methods/outgoing/updateOutgoingIntegration.ts

Summary

Maintainability
C
1 day
Test Coverage
import type { IIntegration, INewOutgoingIntegration, IUpdateOutgoingIntegration } from '@rocket.chat/core-typings';
import type { ServerMethods } from '@rocket.chat/ddp-client';
import { Integrations, Users } from '@rocket.chat/models';
import { wrapExceptions } from '@rocket.chat/tools';
import { Meteor } from 'meteor/meteor';

import { hasPermissionAsync } from '../../../../authorization/server/functions/hasPermission';
import { notifyOnIntegrationChanged } from '../../../../lib/server/lib/notifyListener';
import { validateOutgoingIntegration } from '../../lib/validateOutgoingIntegration';
import { isScriptEngineFrozen, validateScriptEngine } from '../../lib/validateScriptEngine';

declare module '@rocket.chat/ddp-client' {
    // eslint-disable-next-line @typescript-eslint/naming-convention
    interface ServerMethods {
        updateOutgoingIntegration(
            integrationId: string,
            integration: INewOutgoingIntegration | IUpdateOutgoingIntegration,
        ): IIntegration | null;
    }
}

Meteor.methods<ServerMethods>({
    async updateOutgoingIntegration(integrationId, _integration) {
        if (!this.userId) {
            throw new Meteor.Error('error-invalid-user', 'Invalid user', {
                method: 'updateOutgoingIntegration',
            });
        }

        const integration = await validateOutgoingIntegration(_integration, this.userId);

        if (!integration.token || integration.token.trim() === '') {
            throw new Meteor.Error('error-invalid-token', 'Invalid token', {
                method: 'updateOutgoingIntegration',
            });
        }

        let currentIntegration: IIntegration | null;

        if (await hasPermissionAsync(this.userId, 'manage-outgoing-integrations')) {
            currentIntegration = await Integrations.findOneById(integrationId);
        } else if (await hasPermissionAsync(this.userId, 'manage-own-outgoing-integrations')) {
            currentIntegration = await Integrations.findOne({
                '_id': integrationId,
                '_createdBy._id': this.userId,
            });
        } else {
            throw new Meteor.Error('not_authorized', 'Unauthorized', {
                method: 'updateOutgoingIntegration',
            });
        }

        if (!currentIntegration) {
            throw new Meteor.Error('invalid_integration', '[methods] updateOutgoingIntegration -> integration not found');
        }

        const oldScriptEngine = currentIntegration.scriptEngine ?? 'vm2';
        const scriptEngine = integration.scriptEngine ?? oldScriptEngine;
        if (
            integration.script?.trim() &&
            (scriptEngine !== oldScriptEngine || integration.script?.trim() !== currentIntegration.script?.trim())
        ) {
            wrapExceptions(() => validateScriptEngine(scriptEngine)).catch((e) => {
                throw new Meteor.Error(e.message);
            });
        }

        const isFrozen = isScriptEngineFrozen(scriptEngine);

        const updatedIntegration = await Integrations.findOneAndUpdate(
            { _id: integrationId },
            {
                $set: {
                    event: integration.event,
                    enabled: integration.enabled,
                    name: integration.name,
                    avatar: integration.avatar,
                    emoji: integration.emoji,
                    alias: integration.alias,
                    channel: typeof integration.channel === 'string' ? [integration.channel] : integration.channel,
                    targetRoom: integration.targetRoom,
                    impersonateUser: integration.impersonateUser,
                    username: integration.username,
                    userId: integration.userId,
                    urls: integration.urls,
                    token: integration.token,
                    ...(isFrozen
                        ? {}
                        : {
                                script: integration.script,
                                scriptEnabled: integration.scriptEnabled,
                                scriptEngine,
                                ...(integration.scriptCompiled ? { scriptCompiled: integration.scriptCompiled } : { scriptError: integration.scriptError }),
                          }),
                    triggerWords: integration.triggerWords,
                    retryFailedCalls: integration.retryFailedCalls,
                    retryCount: integration.retryCount,
                    retryDelay: integration.retryDelay,
                    triggerWordAnywhere: integration.triggerWordAnywhere,
                    runOnEdits: integration.runOnEdits,
                    _updatedAt: new Date(),
                    _updatedBy: await Users.findOne({ _id: this.userId }, { projection: { username: 1 } }),
                },
                ...(isFrozen
                    ? {}
                    : {
                            $unset: {
                                ...(integration.scriptCompiled ? { scriptError: 1 as const } : { scriptCompiled: 1 as const }),
                            },
                      }),
            },
        );

        if (updatedIntegration.value) {
            await notifyOnIntegrationChanged(updatedIntegration.value);
        }

        return updatedIntegration.value;
    },
});