RocketChat/Rocket.Chat

View on GitHub
apps/meteor/app/importer/server/classes/VirtualDataConverter.ts

Summary

Maintainability
A
3 hrs
Test Coverage
import type {
    IImportUser,
    IImportUserRecord,
    IImportChannelRecord,
    IImportMessageRecord,
    IImportRecord,
    IImportRecordType,
    IImportData,
    IImportChannel,
} from '@rocket.chat/core-typings';
import { Random } from '@rocket.chat/random';

import { ImportDataConverter } from './ImportDataConverter';
import type { IConverterOptions } from './ImportDataConverter';

export class VirtualDataConverter extends ImportDataConverter {
    protected _userRecords: Array<IImportUserRecord>;

    protected _channelRecords: Array<IImportChannelRecord>;

    protected _messageRecords: Array<IImportMessageRecord>;

    protected useVirtual: boolean;

    constructor(virtual = true, options?: IConverterOptions) {
        super(options);

        this.useVirtual = virtual;
        if (virtual) {
            this.clearVirtualData();
        }
    }

    public async clearImportData(): Promise<void> {
        if (!this.useVirtual) {
            return super.clearImportData();
        }

        this.clearVirtualData();
    }

    public async clearSuccessfullyImportedData(): Promise<void> {
        if (!this.useVirtual) {
            return super.clearSuccessfullyImportedData();
        }

        this.clearVirtualData();
    }

    public async findDMForImportedUsers(...users: Array<string>): Promise<IImportChannel | undefined> {
        if (!this.useVirtual) {
            return super.findDMForImportedUsers(...users);
        }

        // The original method is only used by the hipchat importer so we probably don't need to implement this on the virtual converter.
        return undefined;
    }

    public addUserSync(data: IImportUser, options?: Record<string, any>): void {
        return this.addObjectSync('user', data, options);
    }

    protected async addObject(type: IImportRecordType, data: IImportData, options: Record<string, any> = {}): Promise<void> {
        if (!this.useVirtual) {
            return super.addObject(type, data, options);
        }

        this.addObjectSync(type, data, options);
    }

    protected addObjectSync(type: IImportRecordType, data: IImportData, options: Record<string, any> = {}): void {
        if (!this.useVirtual) {
            throw new Error('Sync operations can only be used on virtual converter');
        }

        const list = this.getObjectList(type);

        list.push({
            _id: Random.id(),
            data,
            dataType: type,
            options,
        });
    }

    protected async getUsersToImport(): Promise<Array<IImportUserRecord>> {
        if (!this.useVirtual) {
            return super.getUsersToImport();
        }

        return this._userRecords;
    }

    protected async saveError(importId: string, error: Error): Promise<void> {
        if (!this.useVirtual) {
            return super.saveError(importId, error);
        }

        const record = this.getVirtualRecordById(importId);

        if (!record) {
            return;
        }

        if (!record.errors) {
            record.errors = [];
        }

        record.errors.push({
            message: error.message,
            stack: error.stack,
        });
    }

    protected async skipRecord(_id: string): Promise<void> {
        if (!this.useVirtual) {
            return super.skipRecord(_id);
        }

        const record = this.getVirtualRecordById(_id);

        if (record) {
            record.skipped = true;
        }
    }

    protected async getMessagesToImport(): Promise<IImportMessageRecord[]> {
        if (!this.useVirtual) {
            return super.getMessagesToImport();
        }

        return this._messageRecords;
    }

    protected async getChannelsToImport(): Promise<IImportChannelRecord[]> {
        if (!this.useVirtual) {
            return super.getChannelsToImport();
        }

        return this._channelRecords;
    }

    private clearVirtualData(): void {
        this._userRecords = [];
        this._channelRecords = [];
        this._messageRecords = [];
    }

    private getObjectList(type: IImportRecordType): Array<IImportRecord> {
        switch (type) {
            case 'user':
                return this._userRecords;
            case 'channel':
                return this._channelRecords;
            case 'message':
                return this._messageRecords;
        }
    }

    private getVirtualRecordById(id: string): IImportRecord | undefined {
        for (const store of [this._userRecords, this._channelRecords, this._messageRecords]) {
            for (const record of store) {
                if (record._id === id) {
                    return record;
                }
            }
        }
    }
}