diff --git a/CHANGES b/CHANGES index a007f6cb1..2da47efeb 100644 --- a/CHANGES +++ b/CHANGES @@ -2462,4 +2462,5 @@ * support: add a separate system user named cloudron-support * sshfs: fix bug where sshfs mounts were generated without unbound dependancy * cloudron-setup: add --setup-token +* notifications: add installation event diff --git a/src/changelog.js b/src/changelog.js index 33cfe4438..9dae32ab8 100644 --- a/src/changelog.js +++ b/src/changelog.js @@ -1,6 +1,6 @@ 'use strict'; -let assert = require('assert'), +const assert = require('assert'), fs = require('fs'), path = require('path'); @@ -11,7 +11,7 @@ exports = module.exports = { function getChanges(version) { assert.strictEqual(typeof version, 'string'); - let changelog = [ ]; + const changelog = []; const lines = fs.readFileSync(path.join(__dirname, '../CHANGES'), 'utf8').split('\n'); version = version.replace(/[+-].*/, ''); // strip prerelease diff --git a/src/cloudron.js b/src/cloudron.js index b1cf567f4..e8295e0c2 100644 --- a/src/cloudron.js +++ b/src/cloudron.js @@ -90,10 +90,13 @@ async function notifyUpdate() { const version = safe.fs.readFileSync(paths.VERSION_FILE, 'utf8'); if (version === constants.VERSION) return; - await eventlog.add(eventlog.ACTION_UPDATE_FINISH, AuditSource.CRON, { errorMessage: '', oldVersion: version || 'dev', newVersion: constants.VERSION }); - - const [error] = await safe(tasks.setCompletedByType(tasks.TASK_UPDATE, { error: null })); - if (error && error.reason !== BoxError.NOT_FOUND) throw error; // when hotfixing, task may not exist + if (!version) { + await eventlog.add(eventlog.ACTION_INSTALL_FINISH, AuditSource.CRON, { version: constants.VERSION }); + } else { + await eventlog.add(eventlog.ACTION_UPDATE_FINISH, AuditSource.CRON, { errorMessage: '', oldVersion: version || 'dev', newVersion: constants.VERSION }); + const [error] = await safe(tasks.setCompletedByType(tasks.TASK_UPDATE, { error: null })); + if (error && error.reason !== BoxError.NOT_FOUND) throw error; // when hotfixing, task may not exist + } safe.fs.writeFileSync(paths.VERSION_FILE, constants.VERSION, 'utf8'); } diff --git a/src/constants.js b/src/constants.js index 8fd44feac..30f61f679 100644 --- a/src/constants.js +++ b/src/constants.js @@ -63,6 +63,8 @@ exports = module.exports = { PORT25_CHECK_SERVER: 'port25check.cloudron.io', + FORUM_URL: 'https://forum.cloudron.io', + SUPPORT_USERNAME: 'cloudron-support', SUPPORT_EMAIL: 'support@cloudron.io', diff --git a/src/eventlog.js b/src/eventlog.js index 3b79484d6..22197b707 100644 --- a/src/eventlog.js +++ b/src/eventlog.js @@ -44,6 +44,8 @@ exports = module.exports = { ACTION_DOMAIN_UPDATE: 'domain.update', ACTION_DOMAIN_REMOVE: 'domain.remove', + ACTION_INSTALL_FINISH: 'cloudron.install.finish', + ACTION_MAIL_LOCATION: 'mail.location', ACTION_MAIL_ENABLED: 'mail.enabled', ACTION_MAIL_DISABLED: 'mail.disabled', diff --git a/src/notifications.js b/src/notifications.js index f050749aa..0f0777f2f 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -25,6 +25,7 @@ const assert = require('assert'), AuditSource = require('./auditsource.js'), BoxError = require('./boxerror.js'), changelog = require('./changelog.js'), + constants = require('./constants.js'), database = require('./database.js'), eventlog = require('./eventlog.js'), mailer = require('./mailer.js'), @@ -160,6 +161,16 @@ async function appUpdated(eventId, app, fromManifest, toManifest) { await add(eventId, title, `The application installed at https://${app.fqdn} was updated.\n\nChangelog:\n${toManifest.changelog}\n`); } +async function boxInstalled(eventId, version) { + assert.strictEqual(typeof eventId, 'string'); + assert.strictEqual(typeof version, 'string'); + + const changes = changelog.getChanges(version.replace(/\.([^.]*)$/, '.0')); // last .0 release + const changelogMarkdown = changes.map((m) => `* ${m}\n`).join(''); + + await add(eventId, `Cloudron v${version} installed`, `Cloudron v${version} was installed.\n\nPlease join our community at ${constants.FORUM_URL} .\n\nChangelog:\n${changelogMarkdown}\n`); +} + async function boxUpdated(eventId, oldVersion, newVersion) { assert.strictEqual(typeof eventId, 'string'); assert.strictEqual(typeof oldVersion, 'string'); @@ -267,6 +278,9 @@ async function onEvent(id, action, source, data) { return await backupFailed(id, data.taskId, data.errorMessage); // only notify for automated backups or timedout + case eventlog.ACTION_INSTALL_FINISH: + return await boxInstalled(id, data.version); + case eventlog.ACTION_UPDATE_FINISH: if (!data.errorMessage) return await boxUpdated(id, data.oldVersion, data.newVersion); if (data.timedOut) return await boxUpdateError(id, data.errorMessage);