diff --git a/src/apps.js b/src/apps.js index 4225837f4..b83f1e026 100644 --- a/src/apps.js +++ b/src/apps.js @@ -2556,7 +2556,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`); + 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 }); continue; } diff --git a/src/cloudron.js b/src/cloudron.js index d4ff341bf..a49ac977a 100644 --- a/src/cloudron.js +++ b/src/cloudron.js @@ -193,13 +193,13 @@ async function runSystemChecks() { async function checkMailStatus() { const message = await mail.checkConfiguration(); - await notifications.alert(notifications.ALERT_MAIL_STATUS, 'Email is not configured properly', message); + await notifications.alert(notifications.ALERT_MAIL_STATUS, 'Email is not configured properly', message, { persist: true }); } async function checkRebootRequired() { const rebootRequired = await isRebootRequired(); if (rebootRequired) { - await notifications.alert(notifications.ALERT_REBOOT, 'Reboot Required', 'To finish ubuntu security updates, a reboot is necessary.'); + await notifications.alert(notifications.ALERT_REBOOT, 'Reboot Required', 'To finish ubuntu security updates, a reboot is necessary.', { persist: true }); } else { await notifications.clearAlert(notifications.ALERT_REBOOT, 'Reboot Required'); } @@ -209,7 +209,7 @@ async function checkUbuntuVersion() { const isXenial = fs.readFileSync('/etc/lsb-release', 'utf-8').includes('16.04'); if (!isXenial) return; - await notifications.alert(notifications.ALERT_UPDATE_UBUNTU, 'Ubuntu upgrade required', 'Ubuntu 16.04 has reached end of life and will not receive security and maintenance updates. Please follow https://docs.cloudron.io/guides/upgrade-ubuntu-18/ to upgrade to Ubuntu 18 at the earliest.'); + await notifications.alert(notifications.ALERT_UPDATE_UBUNTU, 'Ubuntu upgrade required', 'Ubuntu 16.04 has reached end of life and will not receive security and maintenance updates. Please follow https://docs.cloudron.io/guides/upgrade-ubuntu-18/ to upgrade to Ubuntu 18 at the earliest.', { persist: true }); } async function getLogs(unit, options) { diff --git a/src/notifications.js b/src/notifications.js index 7fe663e1c..d5ef3a7cc 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -225,25 +225,26 @@ async function backupFailed(eventId, taskId, errorMessage) { } // id is unused but nice to search code -async function alert(id, title, message) { +async function alert(id, title, message, options) { assert.strictEqual(typeof id, 'string'); assert.strictEqual(typeof title, 'string'); assert.strictEqual(typeof message, 'string'); + assert.strictEqual(typeof options, 'object'); const result = await getByTitle(title); - if (!result) { - return await add(title, message, { eventId: null }); - } else { - await update(result, { - eventId: null, - title, - message, - acknowledged: false, - creationTime: new Date() - }); - return result.id; - } + if (!result) return await add(title, message, { eventId: null }); + if (!options.persist) return result.id; + + await update(result, { + id: result.id, + eventId: null, + title, + message, + acknowledged: false, + creationTime: new Date() + }); + return result.id; } // id is unused but nice to search code diff --git a/src/routes/test/notifications-test.js b/src/routes/test/notifications-test.js index 4f56a7838..0923e9698 100644 --- a/src/routes/test/notifications-test.js +++ b/src/routes/test/notifications-test.js @@ -19,7 +19,7 @@ describe('Notifications API', function () { it('can add notifications', async function () { for (let i = 0; i < 3; i++) { - const id = await notifications._add(null, `title ${i}`, `message ${i}`); + const id = await notifications._add(`title ${i}`, `message ${i}`, { eventId: null }); notificationIds.push(id); } }); diff --git a/src/system.js b/src/system.js index 757ab91e2..2cd6b4275 100644 --- a/src/system.js +++ b/src/system.js @@ -169,7 +169,7 @@ async function checkDiskSpace() { if (markdownMessage) markdownMessage = `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', markdownMessage); + await notifications.alert(notifications.ALERT_DISK_SPACE, 'Server is running out of disk space', markdownMessage, { persist: true }); } async function getSwapSize() { diff --git a/src/test/eventlog-test.js b/src/test/eventlog-test.js index 240f91268..6bd5a4223 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(eventId, 'title', 'some message'); + await notifications._add('title', 'some message', { eventId }); } await delay(3000); diff --git a/src/test/notifications-test.js b/src/test/notifications-test.js index 05ae8dc1d..1d60c5372 100644 --- a/src/test/notifications-test.js +++ b/src/test/notifications-test.js @@ -30,7 +30,7 @@ describe('Notifications', function () { it('can add notifications', async function () { for (let i = 0; i < 3; i++) { - const [error, id] = await safe(notifications._add(EVENT_0.id, `title ${i}`, `message ${i}`)); + const [error, id] = await safe(notifications._add(`title ${i}`, `message ${i}`, { eventId: EVENT_0.id })); expect(error).to.equal(null); expect(id).to.be.a('string'); notificationIds.push(id); @@ -85,7 +85,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'); + alertId = await notifications.alert(notifications.ALERT_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'); @@ -93,10 +93,10 @@ describe('Notifications', function () { expect(result.acknowledged).to.be(false); }); - it('can update the alert', async 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'); + const id = await notifications.alert(notifications.ALERT_BOX_UPDATE, 'Cloudron xx is available', 'Awesome new changelog', { persist: true }); expect(id).to.be(alertId); const result = await notifications.get(alertId); @@ -105,6 +105,18 @@ describe('Notifications', function () { expect(result.acknowledged).to.be(false); // notification resurfaces }); + 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 }); + expect(id).to.be(alertId); + + const result = await notifications.get(alertId); + expect(result.title).to.be('Cloudron xx is available'); + expect(result.message).to.be('Awesome new changelog'); + expect(result.acknowledged).to.be(true); // notification does not resurface + }); + it('can clear the alert', async function () { const id = await notifications.clearAlert(notifications.ALERT_BOX_UPDATE, 'Cloudron xx is available'); expect(id).to.be(null); diff --git a/src/updatechecker.js b/src/updatechecker.js index 0cbb0a65b..fad1713df 100644 --- a/src/updatechecker.js +++ b/src/updatechecker.js @@ -85,7 +85,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); + await notifications.alert(notifications.ALERT_BOX_UPDATE, `Cloudron v${updateInfo.version} is available`, message, { persist: false }); state.box = updateInfo; setUpdateInfo(state);