diff --git a/setup/start/custom.yml b/setup/start/custom.yml index a00d17c76..1f13ac464 100644 --- a/setup/start/custom.yml +++ b/setup/start/custom.yml @@ -1,16 +1,19 @@ # add customizations here # after making changes run "sudo systemctl restart box" -# features: -# configureBackup: true +# backups: +# configurable: true +# +# domains: # dynamicDns: true -# subscription: true -# remoteSupport: true -# +# +# subscription: +# configurable: true +# # support: # email: support@cloudron.io -# +# remoteSupport: true +# # alerts: # email: support@cloudron.io # notifyCloudronAdmins: false - diff --git a/src/appstore.js b/src/appstore.js index 9559baa29..6cf87a502 100644 --- a/src/appstore.js +++ b/src/appstore.js @@ -446,7 +446,7 @@ function createTicket(info, callback) { let url = config.apiServerOrigin() + '/api/v1/ticket'; - info.supportEmail = custom.supportEmail(); // destination address for tickets + info.supportEmail = custom.spec().support.email; // destination address for tickets superagent.post(url).query({ accessToken: token }).send(info).timeout(10 * 1000).end(function (error, result) { if (error && !error.response) return callback(new AppstoreError(AppstoreError.EXTERNAL_ERROR, error.message)); diff --git a/src/cloudron.js b/src/cloudron.js index d69d82c4f..0a303c29f 100644 --- a/src/cloudron.js +++ b/src/cloudron.js @@ -174,8 +174,7 @@ function getConfig(callback) { memory: os.totalmem(), provider: config.provider(), cloudronName: allSettings[settings.CLOUDRON_NAME_KEY], - uiSpec: custom.uiSpec(), - supportEmail: custom.supportEmail() + uiSpec: custom.uiSpec() }); }); } diff --git a/src/custom.js b/src/custom.js index 985163142..db6532379 100644 --- a/src/custom.js +++ b/src/custom.js @@ -8,20 +8,22 @@ let debug = require('debug')('box:features'), exports = module.exports = { uiSpec: uiSpec, - supportEmail: supportEmail, - alertsEmail: alertsEmail, - sendAlertsToCloudronAdmins: sendAlertsToCloudronAdmins + spec: spec }; -const DEFAULT = { - features: { - configureBackup: true, - dynamicDns: true, - subscription: true, - remoteSupport: true +const DEFAULT_SPEC = { + backups: { + configurable: true + }, + domains: { + dynamicDns: true + }, + subscription: { + configurable: true }, support: { - email: 'support@cloudron.io' + email: 'support@cloudron.io', + remoteSupport: true }, alerts: { email: '', @@ -29,34 +31,22 @@ const DEFAULT = { } }; -const gCustom = (function () { +const gSpec = (function () { try { - if (!safe.fs.existsSync(paths.CUSTOM_FILE)) return DEFAULT; + if (!safe.fs.existsSync(paths.CUSTOM_FILE)) return DEFAULT_SPEC; const c = yaml.safeLoad(safe.fs.readFileSync(paths.CUSTOM_FILE, 'utf8')); - return lodash.merge({}, DEFAULT, c); + return lodash.merge({}, DEFAULT_SPEC, c); } catch (e) { debug(`Error loading features file from ${paths.CUSTOM_FILE} : ${e.message}`); - return DEFAULT; + return DEFAULT_SPEC; } })(); +// flags sent to the UI. this is separate because we have values that are secret to the backend function uiSpec() { - return { - dynamicDns: gCustom.features.dynamicDns, - remoteSupport: gCustom.features.remoteSupport, - subscription: gCustom.features.subscription, - configureBackup: gCustom.features.configureBackup - }; + return gSpec; } -function supportEmail() { - return gCustom.support.email; -} - -function alertsEmail() { - return gCustom.alerts.email; -} - -function sendAlertsToCloudronAdmins() { - return gCustom.alerts.notifyCloudronAdmins; -} +function spec() { + return gSpec; +} \ No newline at end of file diff --git a/src/mailer.js b/src/mailer.js index 1abb8b64e..36f263afc 100644 --- a/src/mailer.js +++ b/src/mailer.js @@ -289,7 +289,7 @@ function appDied(mailTo, app) { from: mailConfig.notificationFrom, to: mailTo, subject: util.format('[%s] App %s is down', mailConfig.cloudronName, app.fqdn), - text: render('app_down.ejs', { title: app.manifest.title, appFqdn: app.fqdn, supportEmail: custom.supportEmail(), format: 'text' }) + text: render('app_down.ejs', { title: app.manifest.title, appFqdn: app.fqdn, supportEmail: custom.spec().support.email, format: 'text' }) }; sendMail(mailOptions); diff --git a/src/notifications.js b/src/notifications.js index 0c7e4a93d..4813b37ef 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -193,8 +193,8 @@ function oomEvent(eventId, app, addon, containerId, event, callback) { message = 'The container has been restarted automatically. Consider increasing the [memory limit](https://docs.docker.com/v17.09/edge/engine/reference/commandline/update/#update-a-containers-kernel-memory-constraints)'; } - if (custom.alertsEmail()) mailer.oomEvent(custom.alertsEmail(), program, event); - if (!custom.sendAlertsToCloudronAdmins()) return callback(); + if (custom.spec().alerts.email) mailer.oomEvent(custom.spec().alerts.email, program, event); + if (!custom.spec().alerts.notifyCloudronAdmins) return callback(); actionForAllAdmins([], function (admin, done) { mailer.oomEvent(admin.email, program, event); @@ -208,8 +208,8 @@ function appUp(eventId, app, callback) { assert.strictEqual(typeof app, 'object'); assert.strictEqual(typeof callback, 'function'); - if (custom.alertsEmail()) mailer.appUp(custom.alertsEmail(), app); - if (!custom.sendAlertsToCloudronAdmins()) return callback(); + if (custom.spec().alerts.email) mailer.appUp(custom.spec().alerts.email, app); + if (!custom.spec().alerts.notifyCloudronAdmins) return callback(); actionForAllAdmins([], function (admin, done) { mailer.appUp(admin.email, app); @@ -222,8 +222,8 @@ function appDied(eventId, app, callback) { assert.strictEqual(typeof app, 'object'); assert.strictEqual(typeof callback, 'function'); - if (custom.alertsEmail()) mailer.appDied(custom.alertsEmail(), app); - if (!custom.sendAlertsToCloudronAdmins()) return callback(); + if (custom.spec().alerts.email) mailer.appDied(custom.spec().alerts.email, app); + if (!custom.spec().alerts.notifyCloudronAdmins) return callback(); actionForAllAdmins([], function (admin, callback) { mailer.appDied(admin.email, app); @@ -254,8 +254,8 @@ function certificateRenewalError(eventId, vhost, errorMessage, callback) { assert.strictEqual(typeof errorMessage, 'string'); assert.strictEqual(typeof callback, 'function'); - if (custom.alertsEmail()) mailer.certificateRenewalError(custom.alertsEmail(), vhost, errorMessage); - if (!custom.sendAlertsToCloudronAdmins()) return callback(); + if (custom.spec().alerts.email) mailer.certificateRenewalError(custom.spec().alerts.email, vhost, errorMessage); + if (!custom.spec().alerts.notifyCloudronAdmins) return callback(); actionForAllAdmins([], function (admin, callback) { mailer.certificateRenewalError(admin.email, vhost, errorMessage); @@ -269,8 +269,8 @@ function backupFailed(eventId, taskId, errorMessage, callback) { assert.strictEqual(typeof errorMessage, 'string'); assert.strictEqual(typeof callback, 'function'); - if (custom.alertsEmail()) mailer.backupFailed(custom.alertsEmail(), errorMessage, `${config.adminOrigin()}/logs.html?taskId=${taskId}`); - if (!custom.sendAlertsToCloudronAdmins()) return callback(); + if (custom.spec().alerts.email) mailer.backupFailed(custom.spec().alerts.email, errorMessage, `${config.adminOrigin()}/logs.html?taskId=${taskId}`); + if (!custom.spec().alerts.notifyCloudronAdmins) return callback(); actionForAllAdmins([], function (admin, callback) { mailer.backupFailed(admin.email, errorMessage, `${config.adminOrigin()}/logs.html?taskId=${taskId}`); diff --git a/src/routes/settings.js b/src/routes/settings.js index 3e6aaf1bc..97c2357da 100644 --- a/src/routes/settings.js +++ b/src/routes/settings.js @@ -131,8 +131,8 @@ function getBackupConfig(req, res, next) { settings.getBackupConfig(function (error, config) { if (error) return next(new HttpError(500, error)); - // used by the UI to figure if backups are disabled - if (!custom.features().configureBackup) { + // always send provider as it is used by the UI to figure if backups are disabled ('noop' backend) + if (!custom.spec().backups.configurable) { return next(new HttpSuccess(200, { provider: config.provider })); } @@ -143,7 +143,7 @@ function getBackupConfig(req, res, next) { function setBackupConfig(req, res, next) { assert.strictEqual(typeof req.body, 'object'); - if (!custom.features().configureBackup) return next(new HttpError(405, 'feature disabled by admin')); + if (!custom.spec().backups.configurable) return next(new HttpError(405, 'feature disabled by admin')); if (typeof req.body.provider !== 'string') return next(new HttpError(400, 'provider is required')); if (typeof req.body.retentionSecs !== 'number') return next(new HttpError(400, 'retentionSecs is required')); @@ -207,7 +207,7 @@ function getDynamicDnsConfig(req, res, next) { function setDynamicDnsConfig(req, res, next) { assert.strictEqual(typeof req.body, 'object'); - if (!custom.features().dynamicDns) return next(new HttpError(405, 'feature disabled by admin')); + if (!custom.spec().domains.dynamicDns) return next(new HttpError(405, 'feature disabled by admin')); if (typeof req.body.enabled !== 'boolean') return next(new HttpError(400, 'enabled boolean is required')); diff --git a/src/routes/support.js b/src/routes/support.js index 9acbbbbac..8a299356f 100644 --- a/src/routes/support.js +++ b/src/routes/support.js @@ -27,7 +27,7 @@ function createTicket(req, res, next) { if (req.body.appId && typeof req.body.appId !== 'string') return next(new HttpError(400, 'appId must be string')); appstore.createTicket(_.extend({ }, req.body, { email: req.user.email, displayName: req.user.displayName }), function (error) { - if (error) return next(new HttpError(503, `Error contacting cloudron.io: ${error.message}. Please email ${custom.supportEmail()}`)); + if (error) return next(new HttpError(503, `Error contacting cloudron.io: ${error.message}. Please email ${custom.spec().support.email}`)); next(new HttpSuccess(201, {})); }); @@ -36,7 +36,7 @@ function createTicket(req, res, next) { function enableRemoteSupport(req, res, next) { assert.strictEqual(typeof req.body, 'object'); - if (!custom.features().remoteSupport) return next(new HttpError(405, 'feature disabled by admin')); + if (!custom.spec().support.remoteSupport) return next(new HttpError(405, 'feature disabled by admin')); if (typeof req.body.enable !== 'boolean') return next(new HttpError(400, 'enabled is required'));