diff --git a/CHANGES b/CHANGES index 35ca0c012..d6c867f2c 100644 --- a/CHANGES +++ b/CHANGES @@ -2240,4 +2240,5 @@ * Fix bug where renew certs button did not work * filemanager: various enhancements * sftp: fix rebuild condition +* app mailbox is now optional diff --git a/migrations/20210317014101-apps-add-enableMailbox.js b/migrations/20210317014101-apps-add-enableMailbox.js new file mode 100644 index 000000000..6f48a9bc4 --- /dev/null +++ b/migrations/20210317014101-apps-add-enableMailbox.js @@ -0,0 +1,16 @@ +'use strict'; + +exports.up = function(db, callback) { + db.runSql('ALTER TABLE apps ADD COLUMN enableMailbox BOOLEAN DEFAULT 1', function (error) { + if (error) console.error(error); + callback(error); + }); +}; + +exports.down = function(db, callback) { + db.runSql('ALTER TABLE apps DROP COLUMN enableMailbox', function (error) { + if (error) console.error(error); + callback(error); + }); +}; + diff --git a/migrations/schema.sql b/migrations/schema.sql index e53e2da0f..90a5f145a 100644 --- a/migrations/schema.sql +++ b/migrations/schema.sql @@ -79,6 +79,7 @@ CREATE TABLE IF NOT EXISTS apps( reverseProxyConfigJson TEXT, // { robotsTxt, csp } enableBackup BOOLEAN DEFAULT 1, // misnomer: controls automatic daily backups enableAutomaticUpdate BOOLEAN DEFAULT 1, + enableMailbox BOOLEAN DEFAULT 1, // whether sendmail addon is enabled mailboxName VARCHAR(128), // mailbox of this app mailboxDomain VARCHAR(128), // mailbox domain of this apps label VARCHAR(128), // display name diff --git a/src/appdb.js b/src/appdb.js index 78671f856..ac56ba646 100644 --- a/src/appdb.js +++ b/src/appdb.js @@ -42,7 +42,7 @@ const APPS_FIELDS_PREFIXED = [ 'apps.id', 'apps.appStoreId', 'apps.installationS 'apps.health', 'apps.containerId', 'apps.manifestJson', 'apps.accessRestrictionJson', 'apps.memoryLimit', 'apps.cpuShares', 'apps.label', 'apps.tagsJson', 'apps.taskId', 'apps.reverseProxyConfigJson', 'apps.servicesConfigJson', 'apps.sso', 'apps.debugModeJson', 'apps.enableBackup', 'apps.proxyAuth', 'apps.containerIp', - 'apps.creationTime', 'apps.updateTime', 'apps.mailboxName', 'apps.mailboxDomain', 'apps.enableAutomaticUpdate', + 'apps.creationTime', 'apps.updateTime', 'apps.enableMailbox', 'apps.mailboxName', 'apps.mailboxDomain', 'apps.enableAutomaticUpdate', 'apps.dataDir', 'apps.ts', 'apps.healthTime' ].join(','); const PORT_BINDINGS_FIELDS = [ 'hostPort', 'type', 'environmentVariable', 'appId' ].join(','); @@ -86,6 +86,7 @@ function postProcess(result) { result.sso = !!result.sso; // make it bool result.enableBackup = !!result.enableBackup; // make it bool result.enableAutomaticUpdate = !!result.enableAutomaticUpdate; // make it bool + result.enableMailbox = !!result.enableMailbox; // make it bool result.proxyAuth = !!result.proxyAuth; assert(result.debugModeJson === null || typeof result.debugModeJson === 'string'); diff --git a/src/apps.js b/src/apps.js index 807dbd8d1..5b2bd5fcb 100644 --- a/src/apps.js +++ b/src/apps.js @@ -411,7 +411,7 @@ function removeInternalFields(app) { 'location', 'domain', 'fqdn', 'mailboxName', 'mailboxDomain', 'accessRestriction', 'manifest', 'portBindings', 'iconUrl', 'memoryLimit', 'cpuShares', 'sso', 'debugMode', 'reverseProxyConfig', 'enableBackup', 'creationTime', 'updateTime', 'ts', 'tags', - 'label', 'alternateDomains', 'aliasDomains', 'env', 'enableAutomaticUpdate', 'dataDir', 'mounts'); + 'label', 'alternateDomains', 'aliasDomains', 'env', 'enableAutomaticUpdate', 'dataDir', 'mounts', 'enableMailbox'); } // non-admins can only see these @@ -1079,13 +1079,18 @@ function setDebugMode(app, debugMode, auditSource, callback) { }); } -function setMailbox(app, mailboxName, mailboxDomain, auditSource, callback) { +function setMailbox(app, data, auditSource, callback) { assert.strictEqual(typeof app, 'object'); - assert(mailboxName === null || typeof mailboxName === 'string'); - assert.strictEqual(typeof mailboxDomain, 'string'); + assert.strictEqual(typeof data, 'object'); assert.strictEqual(typeof auditSource, 'object'); assert.strictEqual(typeof callback, 'function'); + const { enable, mailboxDomain } = data; + let mailboxName = data.mailboxName; + assert.strictEqual(typeof enable, 'boolean'); + assert(mailboxName === null || typeof mailboxName === 'string'); + assert.strictEqual(typeof mailboxDomain, 'string'); + const appId = app.id; let error = checkAppState(app, exports.ISTATE_PENDING_RECREATE_CONTAINER); if (error) return callback(error); @@ -1104,7 +1109,7 @@ function setMailbox(app, mailboxName, mailboxDomain, auditSource, callback) { const task = { args: {}, - values: { mailboxName, mailboxDomain } + values: { enableMailbox: enable, mailboxName, mailboxDomain } }; addTask(appId, exports.ISTATE_PENDING_RECREATE_CONTAINER, task, function (error, result) { if (error) return callback(error); diff --git a/src/routes/apps.js b/src/routes/apps.js index 7c16b731a..1aabd3c3b 100644 --- a/src/routes/apps.js +++ b/src/routes/apps.js @@ -335,10 +335,13 @@ function setMailbox(req, res, next) { assert.strictEqual(typeof req.body, 'object'); assert.strictEqual(typeof req.resource, 'object'); - if (req.body.mailboxName !== null && typeof req.body.mailboxName !== 'string') return next(new HttpError(400, 'mailboxName must be a string')); - if (typeof req.body.mailboxDomain !== 'string') return next(new HttpError(400, 'mailboxDomain must be a string')); + if (typeof req.body.enable !== 'boolean') return next(new HttpError(400, 'enable must be a boolean')); + if (req.body.enable) { + if (req.body.mailboxName !== null && typeof req.body.mailboxName !== 'string') return next(new HttpError(400, 'mailboxName must be a string')); + if (typeof req.body.mailboxDomain !== 'string') return next(new HttpError(400, 'mailboxDomain must be a string')); + } - apps.setMailbox(req.resource, req.body.mailboxName, req.body.mailboxDomain, auditSource.fromRequest(req), function (error, result) { + apps.setMailbox(req.resource, req.body, auditSource.fromRequest(req), function (error, result) { if (error) return next(BoxError.toHttpError(error)); next(new HttpSuccess(202, { taskId: result.taskId })); diff --git a/src/services.js b/src/services.js index 55462cc20..0cffa84b0 100644 --- a/src/services.js +++ b/src/services.js @@ -1070,6 +1070,9 @@ function setupSendMail(app, options, callback) { debugApp(app, 'Setting up SendMail'); + const disabled = app.manifest.addons.sendmail.optional && !app.enableMailbox; + if (disabled) return appdb.setAddonConfig(app.id, 'sendmail', [], callback); + appdb.getAddonConfigByName(app.id, 'sendmail', '%MAIL_SMTP_PASSWORD', function (error, existingPassword) { if (error && error.reason !== BoxError.NOT_FOUND) return callback(error);