Ctrl K
ComunidadGuías…

server/controllers/demo.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import type express from 'express';
import { translate as $t, assert, asyncErr, KError } from '../helpers';
import { getTranslator } from '../lib/translator';
import { Access, Budget, Category, Setting } from '../models';
import DefaultCategories from '../shared/default-categories.json';
import { DEMO_MODE } from '../shared/settings';
import {
    type CreateAndRetrieveDataResult,
    createAndRetrieveData as createAndRetrieveAccessData,
    destroyWithData as destroyAccessWithData,
} from './accesses';
import { isDemoEnabled, isDemoForced } from './instance';
import type { IdentifiedRequest } from './routes';

export async function setupDemoMode(userId: number): Promise<CreateAndRetrieveDataResult> {
    const i18n = await getTranslator(userId);

    // Create default categories, unless they already existed.
    const existingCategories = new Set((await Category.all(userId)).map(cat => cat.label));
    for (const category of DefaultCategories) {
        if (existingCategories.has($t(i18n, category.label))) {
            continue;
        }
        await Category.create(userId, {
            label: $t(i18n, category.label),
            color: category.color,
        });
    }

    const response = await createAndRetrieveAccessData(userId, {
        vendorId: 'demo',
        fields: [
            { name: 'login', value: 'mylogin' },
            { name: 'password', value: 'couldnotcareless' },
        ],
        customLabel: 'Demo bank',
    });

    assert(response.kind === 'value', "demo account shouldn't require a user action");

    const data = response.value;

    // Set the demo mode to true only if other actions succeeded.
    const isEnabled = await Setting.findOrCreateByKey(userId, DEMO_MODE, 'true');
    if (isEnabled.value !== 'true') {
        // The setting already existed and has the wrong value.
        await Setting.updateByKey(userId, DEMO_MODE, 'true');
    }

    return data;
}

export async function enable(req: IdentifiedRequest<any>, res: express.Response) {
    try {
        const { id: userId } = req.user;

        const isEnabled = await isDemoEnabled(userId);
        if (isEnabled) {
            throw new KError('Demo mode is already enabled, not enabling it.', 400);
        }

        const accesses = await Access.all(userId);
        if (accesses.length > 0) {
            throw new KError('Demo mode cannot be enabled if there already are accesses', 400);
        }

        const data = await setupDemoMode(userId);

        res.status(201).json(data);
    } catch (err) {
        asyncErr(res, err, 'when enabling demo mode');
    }
}

export async function disable(req: IdentifiedRequest<any>, res: express.Response) {
    try {
        const { id: userId } = req.user;

        if (isDemoForced()) {
            throw new KError('Demo mode is forced at the server level, not disabling it.', 400);
        }

        const isEnabled = await isDemoEnabled(userId);
        if (!isEnabled) {
            throw new KError('Demo mode was not enabled, not disabling it.', 400);
        }

        const accesses = await Access.all(userId);
        for (const acc of accesses) {
            await destroyAccessWithData(userId, acc);
        }

        // Keep the categories (and rules), in case the user created
        // interesting ones. Delete all the budgets, though.
        await Budget.destroyAll(userId);

        // Only reset the setting value if all the destroy actions succeeded.
        await Setting.updateByKey(userId, DEMO_MODE, 'false');

        res.status(200).end();
    } catch (err) {
        asyncErr(res, err, 'when disabling demo mode');
    }
}