Skip to content

Commit ae5faa7

Browse files
committed
backend test
1 parent b6dbb68 commit ae5faa7

File tree

3 files changed

+100
-45
lines changed

3 files changed

+100
-45
lines changed

backend/routes/main.js

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,31 @@ import schemaRoutes from "./schema.js";
1414
import settingsRoutes from "./settings.js";
1515
import tokensRoutes from "./tokens.js";
1616
import usersRoutes from "./users.js";
17+
import versionRoutes from "./version.js";
1718

1819
const router = express.Router({
19-
caseSensitive: true,
20-
strict: true,
21-
mergeParams: true,
20+
caseSensitive: true,
21+
strict: true,
22+
mergeParams: true,
2223
});
2324

2425
/**
2526
* Health Check
2627
* GET /api
2728
*/
2829
router.get("/", async (_, res /*, next*/) => {
29-
const version = pjson.version.split("-").shift().split(".");
30-
const setup = await isSetup();
30+
const version = pjson.version.split("-").shift().split(".");
31+
const setup = await isSetup();
3132

32-
res.status(200).send({
33-
status: "OK",
34-
setup,
35-
version: {
36-
major: Number.parseInt(version.shift(), 10),
37-
minor: Number.parseInt(version.shift(), 10),
38-
revision: Number.parseInt(version.shift(), 10),
39-
},
40-
});
33+
res.status(200).send({
34+
status: "OK",
35+
setup,
36+
version: {
37+
major: Number.parseInt(version.shift(), 10),
38+
minor: Number.parseInt(version.shift(), 10),
39+
revision: Number.parseInt(version.shift(), 10),
40+
},
41+
});
4142
});
4243

4344
router.use("/schema", schemaRoutes);
@@ -46,6 +47,7 @@ router.use("/users", usersRoutes);
4647
router.use("/audit-log", auditLogRoutes);
4748
router.use("/reports", reportsRoutes);
4849
router.use("/settings", settingsRoutes);
50+
router.use("/version", versionRoutes);
4951
router.use("/nginx/proxy-hosts", proxyHostsRoutes);
5052
router.use("/nginx/redirection-hosts", redirectionHostsRoutes);
5153
router.use("/nginx/dead-hosts", deadHostsRoutes);
@@ -59,8 +61,8 @@ router.use("/nginx/certificates", certificatesHostsRoutes);
5961
* ALL /api/*
6062
*/
6163
router.all(/(.+)/, (req, _, next) => {
62-
req.params.page = req.params["0"];
63-
next(new errs.ItemNotFoundError(req.params.page));
64+
req.params.page = req.params["0"];
65+
next(new errs.ItemNotFoundError(req.params.page));
6466
});
6567

66-
export default router;
68+
export default router;

backend/routes/version.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import express from "express";
2+
import { debug, express as logger } from "../logger.js";
3+
import pjson from "../package.json" with { type: "json" };
4+
5+
const router = express.Router({
6+
caseSensitive: true,
7+
strict: true,
8+
mergeParams: true,
9+
});
10+
11+
/**
12+
* /api/version/check
13+
*/
14+
router
15+
.route("/check")
16+
.options((_, res) => {
17+
res.sendStatus(204);
18+
})
19+
20+
/**
21+
* GET /api/version/check
22+
*
23+
* Check for available updates
24+
*/
25+
.get(async (req, res, next) => {
26+
try {
27+
const response = await fetch(
28+
"https://api.github.com/repos/NginxProxyManager/nginx-proxy-manager/releases/latest"
29+
);
30+
31+
if (!response.ok) {
32+
throw new Error(`GitHub API returned ${response.status}`);
33+
}
34+
35+
const data = await response.json();
36+
const latestVersion = data.tag_name;
37+
38+
const version = pjson.version.split("-").shift().split(".");
39+
const currentVersion = `v${version[0]}.${version[1]}.${version[2]}`;
40+
41+
res.status(200).send({
42+
current: currentVersion,
43+
latest: latestVersion,
44+
updateAvailable: compareVersions(currentVersion, latestVersion),
45+
});
46+
} catch (error) {
47+
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${error}`);
48+
res.status(200).send({
49+
current: null,
50+
latest: null,
51+
updateAvailable: false,
52+
});
53+
}
54+
});
55+
56+
/**
57+
* Compare two version strings
58+
*
59+
*/
60+
function compareVersions(current, latest) {
61+
const cleanCurrent = current.replace(/^v/, "");
62+
const cleanLatest = latest.replace(/^v/, "");
63+
64+
const currentParts = cleanCurrent.split(".").map(Number);
65+
const latestParts = cleanLatest.split(".").map(Number);
66+
67+
for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {
68+
const curr = currentParts[i] || 0;
69+
const lat = latestParts[i] || 0;
70+
71+
if (lat > curr) return true;
72+
if (lat < curr) return false;
73+
}
74+
return false;
75+
}
76+
77+
export default router;

frontend/src/components/SiteFooter.tsx

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,6 @@ import { useCallback, useEffect, useState } from "react";
22
import { useHealth } from "src/hooks";
33
import { T } from "src/locale";
44

5-
const compareVersions = (current: string, latest: string): boolean => {
6-
const cleanCurrent = current.replace(/^v/, "");
7-
const cleanLatest = latest.replace(/^v/, "");
8-
9-
const currentParts = cleanCurrent.split(".").map(Number);
10-
const latestParts = cleanLatest.split(".").map(Number);
11-
12-
for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {
13-
const curr = currentParts[i] || 0;
14-
const lat = latestParts[i] || 0;
15-
16-
if (lat > curr) return true;
17-
if (lat < curr) return false;
18-
}
19-
return false;
20-
};
21-
225
export function SiteFooter() {
236
const health = useHealth();
247
const [latestVersion, setLatestVersion] = useState<string | null>(null);
@@ -35,18 +18,11 @@ export function SiteFooter() {
3518
useEffect(() => {
3619
const checkForUpdates = async () => {
3720
try {
38-
const response = await fetch(
39-
"https://api.github.com/repos/NginxProxyManager/nginx-proxy-manager/releases/latest"
40-
);
21+
const response = await fetch("/api/version/check");
4122
if (response.ok) {
4223
const data = await response.json();
43-
const latest = data.tag_name;
44-
setLatestVersion(latest);
45-
46-
const currentVersion = getVersion();
47-
if (currentVersion && compareVersions(currentVersion, latest)) {
48-
setIsNewVersionAvailable(true);
49-
}
24+
setLatestVersion(data.latest);
25+
setIsNewVersionAvailable(data.updateAvailable);
5026
}
5127
} catch (error) {
5228
console.debug("Could not check for updates:", error);
@@ -56,7 +32,7 @@ export function SiteFooter() {
5632
if (health.data) {
5733
checkForUpdates();
5834
}
59-
}, [health.data, getVersion]);
35+
}, [health.data]);
6036

6137
return (
6238
<footer className="footer d-print-none py-3">

0 commit comments

Comments
 (0)