Merge pull request #3658 from thelounge/xpaw/version-notify
Display icon when update is available, check on server start
This commit is contained in:
commit
e8ba4f4fb9
@ -52,12 +52,22 @@
|
|||||||
aria-controls="settings"
|
aria-controls="settings"
|
||||||
:aria-selected="$route.name === 'Settings'"
|
:aria-selected="$route.name === 'Settings'"
|
||||||
/></span>
|
/></span>
|
||||||
<span class="tooltipped tooltipped-n tooltipped-no-touch" aria-label="Help"
|
<span
|
||||||
|
class="tooltipped tooltipped-n tooltipped-no-touch"
|
||||||
|
:aria-label="
|
||||||
|
$store.state.serverConfiguration.isUpdateAvailable
|
||||||
|
? 'Help\n(update available)'
|
||||||
|
: 'Help'
|
||||||
|
"
|
||||||
><router-link
|
><router-link
|
||||||
to="/help"
|
to="/help"
|
||||||
tag="button"
|
tag="button"
|
||||||
active-class="active"
|
active-class="active"
|
||||||
:class="['icon', 'help']"
|
:class="[
|
||||||
|
'icon',
|
||||||
|
'help',
|
||||||
|
{notified: $store.state.serverConfiguration.isUpdateAvailable},
|
||||||
|
]"
|
||||||
aria-label="Help"
|
aria-label="Help"
|
||||||
role="tab"
|
role="tab"
|
||||||
aria-controls="help"
|
aria-controls="help"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="version-checker" :class="[$store.state.versionStatus]">
|
<div id="version-checker" :class="[$store.state.versionStatus]">
|
||||||
<p v-if="$store.state.versionStatus === 'loading'">
|
<p v-if="$store.state.versionStatus === 'loading'">
|
||||||
Checking for updates...
|
Checking for updates…
|
||||||
</p>
|
</p>
|
||||||
<p v-if="$store.state.versionStatus === 'new-version'">
|
<p v-if="$store.state.versionStatus === 'new-version'">
|
||||||
The Lounge <b>{{ $store.state.versionData.latest.version }}</b>
|
The Lounge <b>{{ $store.state.versionData.latest.version }}</b>
|
||||||
@ -35,7 +35,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-if="$store.state.versionStatus === 'error'">
|
<template v-if="$store.state.versionStatus === 'error'">
|
||||||
<p>
|
<p>
|
||||||
Information about latest releases could not be retrieved.
|
Information about latest release could not be retrieved.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<button id="check-now" class="btn btn-small" @click="checkNow">Try again</button>
|
<button id="check-now" class="btn btn-small" @click="checkNow">Try again</button>
|
||||||
@ -48,11 +48,6 @@ import socket from "../js/socket";
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "VersionChecker",
|
name: "VersionChecker",
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
status: "loading",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
mounted() {
|
mounted() {
|
||||||
if (!this.$store.state.versionData) {
|
if (!this.$store.state.versionData) {
|
||||||
this.checkNow();
|
this.checkNow();
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
></div>
|
></div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<p>Unable to retrieve releases from GitHub.</p>
|
<p>Unable to retrieve changelog for current release from GitHub.</p>
|
||||||
<p>
|
<p>
|
||||||
<a
|
<a
|
||||||
:href="
|
:href="
|
||||||
|
@ -906,6 +906,18 @@ background on hover (unless active) */
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#footer .help.notified::after {
|
||||||
|
content: "\f021";
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
right: 7px;
|
||||||
|
padding: 2px;
|
||||||
|
font-size: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: var(--link-color);
|
||||||
|
background: var(--body-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
.window li,
|
.window li,
|
||||||
.window p,
|
.window p,
|
||||||
.window label,
|
.window label,
|
||||||
|
@ -24,6 +24,16 @@ socket.on("changelog", function(data) {
|
|||||||
// When there is a button to refresh the checker available, display it when
|
// When there is a button to refresh the checker available, display it when
|
||||||
// data is expired. Before that, server would return same information anyway.
|
// data is expired. Before that, server would return same information anyway.
|
||||||
if (data.expiresAt) {
|
if (data.expiresAt) {
|
||||||
setTimeout(() => store.commit("versionDataExpired", true), data.expiresAt - Date.now());
|
const expires = data.expiresAt - Date.now();
|
||||||
|
|
||||||
|
if (expires > 0) {
|
||||||
|
setTimeout(() => store.commit("versionDataExpired", true), expires);
|
||||||
|
} else {
|
||||||
|
store.commit("versionDataExpired", true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on("changelog:newversion", () => {
|
||||||
|
store.state.serverConfiguration.isUpdateAvailable = true;
|
||||||
|
});
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const got = require("got");
|
const got = require("got");
|
||||||
|
const colors = require("chalk");
|
||||||
const log = require("../log");
|
const log = require("../log");
|
||||||
const pkg = require("../../package.json");
|
const pkg = require("../../package.json");
|
||||||
|
|
||||||
const TIME_TO_LIVE = 15 * 60 * 1000; // 15 minutes, in milliseconds
|
const TIME_TO_LIVE = 15 * 60 * 1000; // 15 minutes, in milliseconds
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
isUpdateAvailable: false,
|
||||||
fetch,
|
fetch,
|
||||||
|
checkForUpdates,
|
||||||
};
|
};
|
||||||
|
|
||||||
const versions = {
|
const versions = {
|
||||||
@ -17,8 +20,10 @@ const versions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function fetch() {
|
async function fetch() {
|
||||||
|
const time = Date.now();
|
||||||
|
|
||||||
// Serving information from cache
|
// Serving information from cache
|
||||||
if (versions.current.changelog) {
|
if (versions.expiresAt > time) {
|
||||||
return versions;
|
return versions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,11 +41,8 @@ async function fetch() {
|
|||||||
|
|
||||||
updateVersions(response);
|
updateVersions(response);
|
||||||
|
|
||||||
// Emptying cached information after reaching said expiration date
|
// Add expiration date to the data to send to the client for later refresh
|
||||||
setTimeout(() => {
|
versions.expiresAt = time + TIME_TO_LIVE;
|
||||||
delete versions.current.changelog;
|
|
||||||
delete versions.latest;
|
|
||||||
}, TIME_TO_LIVE);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(`Failed to fetch changelog: ${error}`);
|
log.error(`Failed to fetch changelog: ${error}`);
|
||||||
}
|
}
|
||||||
@ -74,6 +76,8 @@ function updateVersions(response) {
|
|||||||
|
|
||||||
// Find latest release or pre-release if current version is also a pre-release
|
// Find latest release or pre-release if current version is also a pre-release
|
||||||
if (!release.prerelease || release.prerelease === prerelease) {
|
if (!release.prerelease || release.prerelease === prerelease) {
|
||||||
|
module.exports.isUpdateAvailable = true;
|
||||||
|
|
||||||
versions.latest = {
|
versions.latest = {
|
||||||
prerelease: release.prerelease,
|
prerelease: release.prerelease,
|
||||||
version: release.tag_name,
|
version: release.tag_name,
|
||||||
@ -84,7 +88,26 @@ function updateVersions(response) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Add expiration date to the data to send to the client for later refresh
|
|
||||||
versions.expiresAt = Date.now() + TIME_TO_LIVE;
|
function checkForUpdates(manager) {
|
||||||
|
fetch().then((versionData) => {
|
||||||
|
if (!module.exports.isUpdateAvailable) {
|
||||||
|
// Check for updates every 24 hours + random jitter of <3 hours
|
||||||
|
setTimeout(checkForUpdates, 24 * 3600 * 1000 + Math.floor(Math.random() * 10000000));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!versionData.latest) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
`The Lounge ${colors.green(
|
||||||
|
versionData.latest.version
|
||||||
|
)} is available. Read more on GitHub: ${versionData.latest.url}`
|
||||||
|
);
|
||||||
|
|
||||||
|
// Notify all connected clients about the new version
|
||||||
|
manager.clients.forEach((client) => client.emit("changelog:newversion"));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -239,6 +239,8 @@ module.exports = function(options = {}) {
|
|||||||
if (Helper.config.prefetchStorage) {
|
if (Helper.config.prefetchStorage) {
|
||||||
require("./plugins/storage").emptyDir();
|
require("./plugins/storage").emptyDir();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changelog.checkForUpdates(manager);
|
||||||
});
|
});
|
||||||
|
|
||||||
return server;
|
return server;
|
||||||
@ -703,6 +705,7 @@ function getClientConfiguration() {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config.isUpdateAvailable = changelog.isUpdateAvailable;
|
||||||
config.applicationServerKey = manager.webPush.vapidKeys.publicKey;
|
config.applicationServerKey = manager.webPush.vapidKeys.publicKey;
|
||||||
config.version = pkg.version;
|
config.version = pkg.version;
|
||||||
config.gitCommit = Helper.getGitCommit();
|
config.gitCommit = Helper.getGitCommit();
|
||||||
|
@ -129,12 +129,9 @@ describe("LDAP authentication plugin", function() {
|
|||||||
this.slow(200);
|
this.slow(200);
|
||||||
|
|
||||||
let server;
|
let server;
|
||||||
let originalLogInfo;
|
|
||||||
|
|
||||||
before(function(done) {
|
before(function(done) {
|
||||||
originalLogInfo = log.info;
|
stub(log, "info");
|
||||||
|
|
||||||
log.info = () => {};
|
|
||||||
|
|
||||||
server = startLdapServer(done);
|
server = startLdapServer(done);
|
||||||
});
|
});
|
||||||
@ -142,7 +139,7 @@ describe("LDAP authentication plugin", function() {
|
|||||||
after(function() {
|
after(function() {
|
||||||
server.close();
|
server.close();
|
||||||
|
|
||||||
log.info = originalLogInfo;
|
log.info.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
@ -3,28 +3,28 @@
|
|||||||
const log = require("../src/log");
|
const log = require("../src/log");
|
||||||
const Helper = require("../src/helper");
|
const Helper = require("../src/helper");
|
||||||
const expect = require("chai").expect;
|
const expect = require("chai").expect;
|
||||||
|
const stub = require("sinon").stub;
|
||||||
const got = require("got");
|
const got = require("got");
|
||||||
const io = require("socket.io-client");
|
const io = require("socket.io-client");
|
||||||
|
const changelog = require("../src/plugins/changelog");
|
||||||
|
|
||||||
describe("Server", function() {
|
describe("Server", function() {
|
||||||
// Increase timeout due to unpredictable I/O on CI services
|
// Increase timeout due to unpredictable I/O on CI services
|
||||||
this.timeout(process.env.CI ? 25000 : 5000);
|
this.timeout(process.env.CI ? 25000 : 5000);
|
||||||
|
|
||||||
let server;
|
let server;
|
||||||
let originalLogInfo;
|
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
originalLogInfo = log.info;
|
stub(log, "info");
|
||||||
|
stub(changelog, "checkForUpdates");
|
||||||
log.info = () => {};
|
|
||||||
|
|
||||||
server = require("../src/server")();
|
server = require("../src/server")();
|
||||||
});
|
});
|
||||||
|
|
||||||
after(function(done) {
|
after(function(done) {
|
||||||
server.close(done);
|
server.close(done);
|
||||||
|
log.info.restore();
|
||||||
log.info = originalLogInfo;
|
changelog.checkForUpdates.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
const webURL = `http://${Helper.config.host}:${Helper.config.port}/`;
|
const webURL = `http://${Helper.config.host}:${Helper.config.port}/`;
|
||||||
|
@ -248,9 +248,7 @@ describe("mergeConfig", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should only merge same type", function() {
|
it("should only merge same type", function() {
|
||||||
const originalLog = log.info;
|
stub(log, "warn");
|
||||||
|
|
||||||
log.warn = () => {};
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
mergeConfig(
|
mergeConfig(
|
||||||
@ -282,6 +280,6 @@ describe("mergeConfig", function() {
|
|||||||
shouldBeString: "string",
|
shouldBeString: "string",
|
||||||
});
|
});
|
||||||
|
|
||||||
log.warn = originalLog;
|
log.warn.restore();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user