diff --git a/dashboard/public/js/client.js b/dashboard/public/js/client.js index ef258710a..672b4ddbf 100644 --- a/dashboard/public/js/client.js +++ b/dashboard/public/js/client.js @@ -4,20 +4,20 @@ // keep in sync with box/src/notfications.js const NOTIFICATION_TYPES = { - ALERT_CLOUDRON_INSTALLED: 'cloudronInstalled', - ALERT_CLOUDRON_UPDATED: 'cloudronUpdated', - ALERT_CLOUDRON_UPDATE_FAILED: 'cloudronUpdateFailed', - ALERT_CERTIFICATE_RENEWAL_FAILED: 'certificateRenewalFailed', - ALERT_BACKUP_CONFIG: 'backupConfig', - ALERT_DISK_SPACE: 'diskSpace', - ALERT_MAIL_STATUS: 'mailStatus', - ALERT_REBOOT: 'reboot', - ALERT_BOX_UPDATE: 'boxUpdate', - ALERT_UPDATE_UBUNTU: 'ubuntuUpdate', - ALERT_MANUAL_APP_UPDATE: 'manualAppUpdate', - ALERT_APP_OOM: 'appOutOfMemory', - ALERT_APP_UPDATED: 'appUpdated', - ALERT_BACKUP_FAILED: 'backupFailed', + CLOUDRON_INSTALLED: 'cloudronInstalled', + CLOUDRON_UPDATED: 'cloudronUpdated', + CLOUDRON_UPDATE_FAILED: 'cloudronUpdateFailed', + CERTIFICATE_RENEWAL_FAILED: 'certificateRenewalFailed', + BACKUP_CONFIG: 'backupConfig', + DISK_SPACE: 'diskSpace', + MAIL_STATUS: 'mailStatus', + REBOOT: 'reboot', + BOX_UPDATE: 'boxUpdate', + UPDATE_UBUNTU: 'ubuntuUpdate', + MANUAL_APP_UPDATE: 'manualAppUpdate', + APP_OOM: 'appOutOfMemory', + APP_UPDATED: 'appUpdated', + BACKUP_FAILED: 'backupFailed', }; // keep in sync with box/src/apps.js diff --git a/dashboard/public/js/index.js b/dashboard/public/js/index.js index 19e508e6d..7a4f144d4 100644 --- a/dashboard/public/js/index.js +++ b/dashboard/public/js/index.js @@ -120,16 +120,16 @@ app.config(['$routeProvider', function ($routeProvider) { app.filter('notificationTypeToColor', function () { return function (n) { switch (n.type) { - case NOTIFICATION_TYPES.ALERT_REBOOT: - case NOTIFICATION_TYPES.ALERT_APP_OOM: - case NOTIFICATION_TYPES.ALERT_MAIL_STATUS: - case NOTIFICATION_TYPES.ALERT_CERTIFICATE_RENEWAL_FAILED: - case NOTIFICATION_TYPES.ALERT_DISK_SPACE: - case NOTIFICATION_TYPES.ALERT_BACKUP_CONFIG: - case NOTIFICATION_TYPES.ALERT_BACKUP_FAILED: + case NOTIFICATION_TYPES.REBOOT: + case NOTIFICATION_TYPES.APP_OOM: + case NOTIFICATION_TYPES.MAIL_STATUS: + case NOTIFICATION_TYPES.CERTIFICATE_RENEWAL_FAILED: + case NOTIFICATION_TYPES.DISK_SPACE: + case NOTIFICATION_TYPES.BACKUP_CONFIG: + case NOTIFICATION_TYPES.BACKUP_FAILED: return '#ff4c4c'; - case NOTIFICATION_TYPES.ALERT_BOX_UPDATE: - case NOTIFICATION_TYPES.ALERT_MANUAL_APP_UPDATE: + case NOTIFICATION_TYPES.BOX_UPDATE: + case NOTIFICATION_TYPES.MANUAL_APP_UPDATE: return '#f0ad4e'; default: return '#2196f3'; diff --git a/src/apps.js b/src/apps.js index b86d45e1c..da4d78f50 100644 --- a/src/apps.js +++ b/src/apps.js @@ -2786,7 +2786,7 @@ async function autoupdateApps(updateInfo, auditSource) { // updateInfo is { appI if (!canAutoupdateApp(app, updateInfo[appId])) { debug(`app ${app.fqdn} requires manual update`); - notifications.alert(notifications.ALERT_MANUAL_APP_UPDATE, `${app.manifest.title} at ${app.fqdn} requires manual update to version ${updateInfo[appId].manifest.version}`, `Changelog:\n${updateInfo[appId].manifest.changelog}\n`, { persist: false }); + notifications.alert(notifications.TYPE_MANUAL_APP_UPDATE_NEEDED, `${app.manifest.title} at ${app.fqdn} requires manual update to version ${updateInfo[appId].manifest.version}`, `Changelog:\n${updateInfo[appId].manifest.changelog}\n`, { persist: false }); continue; } diff --git a/src/mail.js b/src/mail.js index 79b7d2f8d..a26f89383 100644 --- a/src/mail.js +++ b/src/mail.js @@ -1210,8 +1210,8 @@ async function resolveList(listName, listDomain) { async function checkStatus() { const result = await checkConfiguration(); if (result.status) { - await notifications.clearAlert(notifications.ALERT_MAIL_STATUS, 'Email is not configured properly'); + await notifications.clearAlert(notifications.TYPE_MAIL_STATUS, 'Email is not configured properly'); } else { - await notifications.alert(notifications.ALERT_MAIL_STATUS, 'Email is not configured properly', result.message, { persist: true }); + await notifications.alert(notifications.TYPE_MAIL_STATUS, 'Email is not configured properly', result.message, { persist: true }); } } diff --git a/src/notifications.js b/src/notifications.js index 1efb0bb2a..b13f7ac98 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -9,20 +9,20 @@ exports = module.exports = { onEvent, // these are notification types, keep in sync with client.js - ALERT_CLOUDRON_INSTALLED: 'cloudronInstalled', - ALERT_CLOUDRON_UPDATED: 'cloudronUpdated', - ALERT_CLOUDRON_UPDATE_FAILED: 'cloudronUpdateFailed', - ALERT_CERTIFICATE_RENEWAL_FAILED: 'certificateRenewalFailed', - ALERT_BACKUP_CONFIG: 'backupConfig', - ALERT_DISK_SPACE: 'diskSpace', - ALERT_MAIL_STATUS: 'mailStatus', - ALERT_REBOOT: 'reboot', - ALERT_BOX_UPDATE: 'boxUpdate', - ALERT_UPDATE_UBUNTU: 'ubuntuUpdate', - ALERT_MANUAL_APP_UPDATE: 'manualAppUpdate', - ALERT_APP_OOM: 'appOutOfMemory', - ALERT_APP_UPDATED: 'appUpdated', - ALERT_BACKUP_FAILED: 'backupFailed', + TYPE_CLOUDRON_INSTALLED: 'cloudronInstalled', + TYPE_CLOUDRON_UPDATED: 'cloudronUpdated', + TYPE_CLOUDRON_UPDATE_FAILED: 'cloudronUpdateFailed', + TYPE_CERTIFICATE_RENEWAL_FAILED: 'certificateRenewalFailed', + TYPE_BACKUP_CONFIG: 'backupConfig', + TYPE_DISK_SPACE: 'diskSpace', + TYPE_MAIL_STATUS: 'mailStatus', + TYPE_REBOOT: 'reboot', + TYPE_BOX_UPDATE: 'boxUpdate', + TYPE_UPDATE_UBUNTU: 'ubuntuUpdate', + TYPE_MANUAL_APP_UPDATE_NEEDED: 'manualAppUpdate', + TYPE_APP_OOM: 'appOutOfMemory', + TYPE_APP_UPDATED: 'appUpdated', + TYPE_BACKUP_FAILED: 'backupFailed', alert, clearAlert, @@ -152,7 +152,7 @@ async function oomEvent(eventId, containerId, app, addonName /*, event*/) { message = `The app has been restarted automatically. If you see this notification often, consider increasing the [memory limit](https://${dashboardFqdn}/#/app/${app.id}/resources)`; } - await add(exports.ALERT_APP_OOM, title, message, { eventId }); + await add(exports.TYPE_APP_OOM, title, message, { eventId }); } async function appUpdated(eventId, app, fromManifest, toManifest) { @@ -168,7 +168,7 @@ async function appUpdated(eventId, app, fromManifest, toManifest) { const title = upstreamVersion ? `${toManifest.title} at ${app.fqdn} updated to ${upstreamVersion} (package version ${toManifest.version})` : `${toManifest.title} at ${app.fqdn} updated to package version ${toManifest.version}`; - await add(exports.ALERT_APP_UPDATED, title, `The application installed at https://${app.fqdn} was updated.\n\nChangelog:\n${toManifest.changelog}\n`, { eventId }); + await add(exports.TYPE_APP_UPDATED, title, `The application installed at https://${app.fqdn} was updated.\n\nChangelog:\n${toManifest.changelog}\n`, { eventId }); } async function boxInstalled(eventId, version) { @@ -178,7 +178,7 @@ async function boxInstalled(eventId, version) { const changes = changelog.getChanges(version.replace(/\.([^.]*)$/, '.0')); // last .0 release const changelogMarkdown = changes.map((m) => `* ${m}\n`).join(''); - await add(exports.ALERT_CLOUDRON_INSTALLED, `Cloudron v${version} installed`, `Cloudron v${version} was installed.\n\nPlease join our community at ${constants.FORUM_URL} .\n\nChangelog:\n${changelogMarkdown}\n`, { eventId }); + await add(exports.TYPE_CLOUDRON_INSTALLED, `Cloudron v${version} installed`, `Cloudron v${version} was installed.\n\nPlease join our community at ${constants.FORUM_URL} .\n\nChangelog:\n${changelogMarkdown}\n`, { eventId }); } async function boxUpdated(eventId, oldVersion, newVersion) { @@ -189,14 +189,14 @@ async function boxUpdated(eventId, oldVersion, newVersion) { const changes = changelog.getChanges(newVersion); const changelogMarkdown = changes.map((m) => `* ${m}\n`).join(''); - await add(exports.ALERT_CLOUDRON_UPDATED, `Cloudron updated to v${newVersion}`, `Cloudron was updated from v${oldVersion} to v${newVersion}.\n\nChangelog:\n${changelogMarkdown}\n`, { eventId }); + await add(exports.TYPE_CLOUDRON_UPDATED, `Cloudron updated to v${newVersion}`, `Cloudron was updated from v${oldVersion} to v${newVersion}.\n\nChangelog:\n${changelogMarkdown}\n`, { eventId }); } async function boxUpdateError(eventId, errorMessage) { assert.strictEqual(typeof eventId, 'string'); assert.strictEqual(typeof errorMessage, 'string'); - await add(exports.ALERT_CLOUDRON_UPDATE_FAILED, 'Cloudron update failed', `Failed to update Cloudron: ${errorMessage}.`, { eventId }); + await add(exports.TYPE_CLOUDRON_UPDATE_FAILED, 'Cloudron update failed', `Failed to update Cloudron: ${errorMessage}.`, { eventId }); } async function certificateRenewalError(eventId, fqdn, errorMessage) { @@ -204,7 +204,7 @@ async function certificateRenewalError(eventId, fqdn, errorMessage) { assert.strictEqual(typeof fqdn, 'string'); assert.strictEqual(typeof errorMessage, 'string'); - await add(exports.ALERT_CERTIFICATE_RENEWAL_FAILED, `Certificate renewal of ${fqdn} failed`, `Failed to renew certs of ${fqdn}: ${errorMessage}. Renewal will be retried in 12 hours.`, { eventId }); + await add(exports.TYPE_CERTIFICATE_RENEWAL_FAILED, `Certificate renewal of ${fqdn} failed`, `Failed to renew certs of ${fqdn}: ${errorMessage}. Renewal will be retried in 12 hours.`, { eventId }); const admins = await users.getAdmins(); for (const admin of admins) { @@ -217,7 +217,7 @@ async function backupFailed(eventId, taskId, errorMessage) { assert.strictEqual(typeof taskId, 'string'); assert.strictEqual(typeof errorMessage, 'string'); - await add(exports.ALERT_BACKUP_FAILED, 'Backup failed', `Backup failed: ${errorMessage}. Logs are available [here](/logs.html?taskId=${taskId}).`, { eventId }); + await add(exports.TYPE_BACKUP_FAILED, 'Backup failed', `Backup failed: ${errorMessage}. Logs are available [here](/logs.html?taskId=${taskId}).`, { eventId }); // only send mail if the past 3 automated backups failed const backupEvents = await eventlog.listPaged([eventlog.ACTION_BACKUP_FINISH], null /* search */, 1, 20); @@ -235,7 +235,7 @@ async function backupFailed(eventId, taskId, errorMessage) { } } -// type must be one of ALERT_* +// type must be one of TYPE_* async function alert(type, title, message, options) { assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof title, 'string'); diff --git a/src/routes/test/notifications-test.js b/src/routes/test/notifications-test.js index 5fc0bf967..46953b9a3 100644 --- a/src/routes/test/notifications-test.js +++ b/src/routes/test/notifications-test.js @@ -15,11 +15,11 @@ describe('Notifications API', function () { before(setup); after(cleanup); - let notificationIds = []; + const notificationIds = []; it('can add notifications', async function () { for (let i = 0; i < 3; i++) { - const id = await notifications._add(notifications.ALERT_APP_UPDATED, `title ${i}`, `message ${i}`, { eventId: null }); + const id = await notifications._add(notifications.TYPE_APP_UPDATED, `title ${i}`, `message ${i}`, { eventId: null }); notificationIds.push(id); } }); diff --git a/src/system.js b/src/system.js index 281f69a33..b06280e06 100644 --- a/src/system.js +++ b/src/system.js @@ -198,9 +198,9 @@ async function checkDiskSpace() { if (markdownMessage) { const finalMessage = `One or more file systems are running out of space. Please increase the disk size at the earliest.\n\n${markdownMessage}`; - await notifications.alert(notifications.ALERT_DISK_SPACE, 'Server is running out of disk space', finalMessage, { persist: true }); + await notifications.alert(notifications.TYPE_DISK_SPACE, 'Server is running out of disk space', finalMessage, { persist: true }); } else { - await notifications.clearAlert(notifications.ALERT_DISK_SPACE, 'Server is running out of disk space'); + await notifications.clearAlert(notifications.TYPE_DISK_SPACE, 'Server is running out of disk space'); } } @@ -275,7 +275,7 @@ async function updateDiskUsage(progressCallback) { } async function reboot() { - await notifications.clearAlert(notifications.ALERT_REBOOT, 'Reboot Required'); + await notifications.clearAlert(notifications.TYPE_REBOOT, 'Reboot Required'); const [error] = await safe(shell.promises.sudo([ REBOOT_CMD ], {})); if (error) debug('reboot: could not reboot. %o', error); @@ -349,9 +349,9 @@ async function getBlockDevices() { async function checkRebootRequired() { const { rebootRequired } = await getInfo(); if (rebootRequired) { - await notifications.alert(notifications.ALERT_REBOOT, 'Reboot Required', 'To finish ubuntu security updates, a reboot is necessary.', { persist: true }); + await notifications.alert(notifications.TYPE_REBOOT, 'Reboot Required', 'To finish ubuntu security updates, a reboot is necessary.', { persist: true }); } else { - await notifications.clearAlert(notifications.ALERT_REBOOT, 'Reboot Required'); + await notifications.clearAlert(notifications.TYPE_REBOOT, 'Reboot Required'); } } @@ -365,7 +365,7 @@ async function checkUbuntuVersion() { const isBionic = fs.readFileSync('/etc/lsb-release', 'utf-8').includes('18.04'); if (!isBionic) return; - await notifications.alert(notifications.ALERT_UPDATE_UBUNTU, 'Ubuntu upgrade required', 'Ubuntu 18.04 has reached end of life and will not receive security and maintenance updates. Please follow https://docs.cloudron.io/guides/upgrade-ubuntu-20/ to upgrade to Ubuntu 18 at the earliest.', { persist: true }); + await notifications.alert(notifications.TYPE_UPDATE_UBUNTU, 'Ubuntu upgrade required', 'Ubuntu 18.04 has reached end of life and will not receive security and maintenance updates. Please follow https://docs.cloudron.io/guides/upgrade-ubuntu-20/ to upgrade to Ubuntu 20 at the earliest.', { persist: true }); } async function runSystemChecks() { diff --git a/src/test/eventlog-test.js b/src/test/eventlog-test.js index 56b2d17d4..eb628260a 100644 --- a/src/test/eventlog-test.js +++ b/src/test/eventlog-test.js @@ -114,7 +114,7 @@ describe('Eventlog', function () { for (const e of [ eventlog.ACTION_USER_LOGIN, eventlog.ACTION_USER_LOGIN_GHOST, eventlog.ACTION_USER_LOGOUT, eventlog.ACTION_USER_LOGIN ]) { const eventId = await eventlog.add(e, { ip: '1.2.3.4' }, { appId: 'thatapp' }); - await notifications._add(notifications.ALERT_APP_UPDATED, 'title', 'some message', { eventId }); + await notifications._add(notifications.TYPE_APP_UPDATED, 'title', 'some message', { eventId }); } await timers.setTimeout(3000); diff --git a/src/test/notifications-test.js b/src/test/notifications-test.js index f3e98500a..c6ff3198e 100644 --- a/src/test/notifications-test.js +++ b/src/test/notifications-test.js @@ -26,11 +26,11 @@ describe('Notifications', function () { before(setup); after(cleanup); - let notificationIds = []; + const notificationIds = []; it('can add notifications', async function () { for (let i = 0; i < 3; i++) { - const [error, id] = await safe(notifications._add(notifications.ALERT_APP_UPDATED, `title ${i}`, `message ${i}`, { eventId: EVENT_0.id })); + const [error, id] = await safe(notifications._add(notifications.TYPE_APP_UPDATED, `title ${i}`, `message ${i}`, { eventId: EVENT_0.id })); expect(error).to.equal(null); expect(id).to.be.a('string'); notificationIds.push(id); @@ -42,7 +42,7 @@ describe('Notifications', function () { const [error, result] = await safe(notifications.get(notificationIds[0])); expect(error).to.be(null); expect(result.title).to.be('title 0'); - expect(result.type).to.be(notifications.ALERT_APP_UPDATED); + expect(result.type).to.be(notifications.TYPE_APP_UPDATED); expect(result.message).to.be('message 0'); expect(result.acknowledged).to.be(false); }); @@ -61,11 +61,11 @@ describe('Notifications', function () { }); it('can update notification', async function () { - await notifications.update({ id: notificationIds[0] }, { type: notifications.ALERT_APP_OOM, title: 'updated title 0', message: 'updated message 0', acknowledged: true }); + await notifications.update({ id: notificationIds[0] }, { type: notifications.TYPE_APP_OOM, title: 'updated title 0', message: 'updated message 0', acknowledged: true }); const result = await notifications.get(notificationIds[0]); expect(result.title).to.be('updated title 0'); - expect(result.type).to.be(notifications.ALERT_APP_OOM); + expect(result.type).to.be(notifications.TYPE_APP_OOM); expect(result.message).to.be('updated message 0'); expect(result.acknowledged).to.be(true); }); @@ -87,7 +87,7 @@ describe('Notifications', function () { let alertId; it('can add alert', async function () { - alertId = await notifications.alert(notifications.ALERT_BOX_UPDATE, 'Cloudron xx is available', 'Awesome changelog', { persist: true }); + alertId = await notifications.alert(notifications.TYPE_BOX_UPDATE, 'Cloudron xx is available', 'Awesome changelog', { persist: true }); const result = await notifications.get(alertId); expect(result.title).to.be('Cloudron xx is available'); @@ -98,7 +98,7 @@ describe('Notifications', function () { it('can update the alert (persist)', async function () { await notifications.update({ id: alertId }, { acknowledged: true }); // ack the alert - const id = await notifications.alert(notifications.ALERT_BOX_UPDATE, 'Cloudron xx is available', 'Awesome new changelog', { persist: true }); + const id = await notifications.alert(notifications.TYPE_BOX_UPDATE, 'Cloudron xx is available', 'Awesome new changelog', { persist: true }); expect(id).to.be(alertId); const result = await notifications.get(alertId); @@ -110,7 +110,7 @@ describe('Notifications', function () { it('can update the alert (non-persist)', async function () { await notifications.update({ id: alertId }, { acknowledged: true }); // ack the alert - const id = await notifications.alert(notifications.ALERT_BOX_UPDATE, 'Cloudron xx is available', 'Awesome new changelog', { persist: false }); + const id = await notifications.alert(notifications.TYPE_BOX_UPDATE, 'Cloudron xx is available', 'Awesome new changelog', { persist: false }); expect(id).to.be(alertId); const result = await notifications.get(alertId); @@ -120,7 +120,7 @@ describe('Notifications', function () { }); it('can clear the alert', async function () { - const id = await notifications.clearAlert(notifications.ALERT_BOX_UPDATE); + const id = await notifications.clearAlert(notifications.TYPE_BOX_UPDATE); expect(id).to.be(null); const result = await notifications.get(alertId); diff --git a/src/updatechecker.js b/src/updatechecker.js index 326adaaf4..7bc04d044 100644 --- a/src/updatechecker.js +++ b/src/updatechecker.js @@ -86,7 +86,7 @@ async function checkBoxUpdates(options) { const changelog = updateInfo.changelog.map((m) => `* ${m}\n`).join(''); const message = `Changelog:\n${changelog}\n\nGo to the Settings view to update.\n\n`; - await notifications.alert(notifications.ALERT_BOX_UPDATE, `Cloudron v${updateInfo.version} is available`, message, { persist: false }); + await notifications.alert(notifications.TYPE_BOX_UPDATE, `Cloudron v${updateInfo.version} is available`, message, { persist: false }); state.box = updateInfo; setUpdateInfo(state);