diff --git a/public/language/bg/admin/settings/advanced.json b/public/language/bg/admin/settings/advanced.json index 32caf79de0..7992505008 100644 --- a/public/language/bg/admin/settings/advanced.json +++ b/public/language/bg/admin/settings/advanced.json @@ -21,7 +21,7 @@ "headers.coop": "Cross-Origin-Opener-Policy", "headers.corp": "Cross-Origin-Resource-Policy", "headers.permissions-policy": "Permissions-Policy", - "headers.permissions-policy-help": "Allows setting permissions policy header, for example \"geolocation=*, camera=()\", see this for more info.", + "headers.permissions-policy-help": "Позволява задаването на стойност в заглавката „permissions-policy“ (политика за разрешенията), като например „geolocation=*, camera=()“. Вижте тук за повече информация.", "hsts": "Стриктна транспортна сигурност", "hsts.enabled": "Включване на HSTS (препоръчително)", "hsts.maxAge": "Максимална възраст на HSTS", diff --git a/public/src/admin/settings.js b/public/src/admin/settings.js index 2436a45950..26a2f53545 100644 --- a/public/src/admin/settings.js +++ b/public/src/admin/settings.js @@ -1,7 +1,7 @@ 'use strict'; -define('admin/settings', ['uploader', 'mousetrap', 'hooks', 'alerts'], function (uploader, mousetrap, hooks, alerts) { +define('admin/settings', ['uploader', 'mousetrap', 'hooks', 'alerts', 'settings'], function (uploader, mousetrap, hooks, alerts, settings) { const Settings = {}; Settings.populateTOC = function () { @@ -65,6 +65,11 @@ define('admin/settings', ['uploader', 'mousetrap', 'hooks', 'alerts'], function saveBtn.off('click').on('click', function (e) { e.preventDefault(); + const ok = settings.check(document.querySelectorAll('#content [data-field]')); + if (!ok) { + return; + } + saveFields(fields, function onFieldsSaved(err) { if (err) { return alerts.alert({ diff --git a/public/src/modules/settings.js b/public/src/modules/settings.js index 7e5d8088a8..c098897f77 100644 --- a/public/src/modules/settings.js +++ b/public/src/modules/settings.js @@ -514,6 +514,13 @@ define('settings', ['hooks', 'alerts'], function (hooks, alerts) { save: function (hash, formEl, callback) { formEl = $(formEl); + const controls = formEl.get(0).elements; + console.log(controls); + const ok = Settings.check(controls); + if (!ok) { + return; + } + if (formEl.length) { const values = helper.serializeForm(formEl); @@ -556,6 +563,26 @@ define('settings', ['hooks', 'alerts'], function (hooks, alerts) { }); } }, + check: function (controls) { + const onTrigger = (e) => { + const wrapper = e.target.closest('.form-group'); + if (wrapper) { + wrapper.classList.add('has-error'); + } + + e.target.removeEventListener('invalid', onTrigger); + }; + + return Array.prototype.map.call(controls, (controlEl) => { + const wrapper = controlEl.closest('.form-group'); + if (wrapper) { + wrapper.classList.remove('has-error'); + } + + controlEl.addEventListener('invalid', onTrigger); + return controlEl.reportValidity(); + }).every(Boolean); + }, }; diff --git a/src/cli/index.js b/src/cli/index.js index f72860e5d6..39bca2dfcb 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -176,11 +176,16 @@ program }); program - .command('install') - .description('Launch the NodeBB web installer for configuration setup') - .action(() => { - require('./setup').webInstall(); + .command('install [plugin]') + .description('Launch the NodeBB web installer for configuration setup or install a plugin') + .action((plugin) => { + if (plugin) { + require('./manage').install(plugin); + } else { + require('./setup').webInstall(); + } }); + program .command('build [targets...]') .description(`Compile static assets ${chalk.red('(JS, CSS, templates, languages)')}`) diff --git a/src/cli/manage.js b/src/cli/manage.js index 24052e21f6..45480e735f 100644 --- a/src/cli/manage.js +++ b/src/cli/manage.js @@ -12,7 +12,36 @@ const plugins = require('../plugins'); const events = require('../events'); const analytics = require('../analytics'); const reset = require('./reset'); -const { pluginNamePattern, themeNamePattern } = require('../constants'); +const { pluginNamePattern, themeNamePattern, paths } = require('../constants'); + +async function install(plugin) { + try { + await db.init(); + if (!pluginNamePattern.test(plugin)) { + // Allow omission of `nodebb-plugin-` + plugin = `nodebb-plugin-${plugin}`; + } + + plugin = await plugins.autocomplete(plugin); + + const isInstalled = await plugins.isInstalled(plugin); + if (isInstalled) { + throw new Error('plugin already installed'); + } + const nbbVersion = require(paths.currentPackage).version; + const suggested = await plugins.suggest(plugin, nbbVersion); + if (!suggested.version) { + throw new Error(suggested.message); + } + winston.info('Installing Plugin `%s@%s`', plugin, suggested.version); + await plugins.toggleInstall(plugin, suggested.version); + + process.exit(0); + } catch (err) { + winston.error(`An error occurred during plugin installation\n${err.stack}`); + process.exit(1); + } +} async function activate(plugin) { if (themeNamePattern.test(plugin)) { @@ -166,6 +195,7 @@ async function buildWrapper(targets, options) { } exports.build = buildWrapper; +exports.install = install; exports.activate = activate; exports.listPlugins = listPlugins; exports.listEvents = listEvents; diff --git a/src/plugins/install.js b/src/plugins/install.js index 3784df09a0..d358c917a5 100644 --- a/src/plugins/install.js +++ b/src/plugins/install.js @@ -87,6 +87,15 @@ module.exports = function (Plugins) { throw new Error('[[error:plugin-not-whitelisted]]'); }; + Plugins.suggest = async function (pluginId, nbbVersion) { + const body = await request({ + method: 'GET', + url: `https://packages.nodebb.org/api/v1/suggest?package=${encodeURIComponent(pluginId)}&version=${encodeURIComponent(nbbVersion)}`, + json: true, + }); + return body; + }; + Plugins.toggleInstall = async function (id, version) { pubsub.publish('plugins:toggleInstall', { hostname: os.hostname(), id: id, version: version }); return await toggleInstall(id, version); diff --git a/src/views/admin/partials/api/sorted-list/form.tpl b/src/views/admin/partials/api/sorted-list/form.tpl index 1ce54cf56a..2f129b43e4 100644 --- a/src/views/admin/partials/api/sorted-list/form.tpl +++ b/src/views/admin/partials/api/sorted-list/form.tpl @@ -3,7 +3,7 @@
- +

[[admin/settings/api:uid-help-text]]