NodeBB/NodeBB

View on GitHub
src/cli/reset.js

Summary

Maintainability
A
1 hr
Test Coverage
'use strict';

const path = require('path');
const winston = require('winston');
const fs = require('fs');
const chalk = require('chalk');
const nconf = require('nconf');

const db = require('../database');
const events = require('../events');
const meta = require('../meta');
const plugins = require('../plugins');
const widgets = require('../widgets');
const privileges = require('../privileges');
const { paths, pluginNamePattern, themeNamePattern } = require('../constants');

exports.reset = async function (options) {
    const map = {
        theme: async function () {
            let themeId = options.theme;
            if (themeId === true) {
                await resetThemes();
            } else {
                if (!themeNamePattern.test(themeId)) {
                    // Allow omission of `nodebb-theme-`
                    themeId = `nodebb-theme-${themeId}`;
                }

                themeId = await plugins.autocomplete(themeId);
                await resetTheme(themeId);
            }
        },
        plugin: async function () {
            let pluginId = options.plugin;
            if (pluginId === true) {
                await resetPlugins();
            } else {
                if (!pluginNamePattern.test(pluginId)) {
                    // Allow omission of `nodebb-plugin-`
                    pluginId = `nodebb-plugin-${pluginId}`;
                }

                pluginId = await plugins.autocomplete(pluginId);
                await resetPlugin(pluginId);
            }
        },
        widgets: resetWidgets,
        settings: resetSettings,
        all: async function () {
            await resetWidgets();
            await resetThemes();
            await resetPlugin();
            await resetSettings();
        },
    };

    const tasks = Object.keys(map).filter(x => options[x]).map(x => map[x]);

    if (!tasks.length) {
        console.log([
            chalk.yellow('No arguments passed in, so nothing was reset.\n'),
            `Use ./nodebb reset ${chalk.red('{-t|-p|-w|-s|-a}')}`,
            '    -t\tthemes',
            '    -p\tplugins',
            '    -w\twidgets',
            '    -s\tsettings',
            '    -a\tall of the above',
            '',
            'Plugin and theme reset flags (-p & -t) can take a single argument',
            '    e.g. ./nodebb reset -p nodebb-plugin-mentions, ./nodebb reset -t nodebb-theme-harmony',
            '         Prefix is optional, e.g. ./nodebb reset -p markdown, ./nodebb reset -t harmony',
        ].join('\n'));

        process.exit(0);
    }

    try {
        await db.init();
        for (const task of tasks) {
            /* eslint-disable no-await-in-loop */
            await task();
        }
        winston.info('[reset] Reset complete. Please run `./nodebb build` to rebuild assets.');
        process.exit(0);
    } catch (err) {
        winston.error(`[reset] Errors were encountered during reset -- ${err.message}`);
        process.exit(1);
    }
};

async function resetSettings() {
    await privileges.global.give(['groups:local:login'], 'registered-users');
    winston.info('[reset] registered-users given login privilege');
    winston.info('[reset] Settings reset to default');
}

async function resetTheme(themeId) {
    try {
        await fs.promises.access(path.join(paths.nodeModules, themeId, 'package.json'));
    } catch (err) {
        winston.warn('[reset] Theme `%s` is not installed on this forum', themeId);
        throw new Error('theme-not-found');
    }
    await resetThemeTo(themeId);
}

async function resetThemes() {
    await resetThemeTo('nodebb-theme-harmony');
}

async function resetThemeTo(themeId) {
    await meta.themes.set({
        type: 'local',
        id: themeId,
    });
    await meta.configs.set('bootswatchSkin', '');
    winston.info(`[reset] Theme reset to ${themeId} and default skin`);
}

async function resetPlugin(pluginId) {
    try {
        if (nconf.get('plugins:active')) {
            winston.error('Cannot reset plugins while plugin state is set in the configuration (config.json, environmental variables or terminal arguments), please modify the configuration instead');
            process.exit(1);
        }
        const isActive = await db.isSortedSetMember('plugins:active', pluginId);
        if (isActive) {
            await db.sortedSetRemove('plugins:active', pluginId);
            await events.log({
                type: 'plugin-deactivate',
                text: pluginId,
            });
            winston.info('[reset] Plugin `%s` disabled', pluginId);
        } else {
            winston.warn('[reset] Plugin `%s` was not active on this forum', pluginId);
            winston.info('[reset] No action taken.');
        }
    } catch (err) {
        winston.error(`[reset] Could not disable plugin: ${pluginId} encountered error %s\n${err.stack}`);
        throw err;
    }
}

async function resetPlugins() {
    if (nconf.get('plugins:active')) {
        winston.error('Cannot reset plugins while plugin state is set in the configuration (config.json, environmental variables or terminal arguments), please modify the configuration instead');
        process.exit(1);
    }
    await db.delete('plugins:active');
    winston.info('[reset] All Plugins De-activated');
}

async function resetWidgets() {
    await plugins.reload();
    await widgets.reset();
    winston.info('[reset] All Widgets moved to Draft Zone');
}