Fix: fix duplicati widget with no jobs (#7005)

This commit is contained in:
shamoon
2026-08-18 08:44:44 -07:00
committed by GitHub
parent d4fd14b724
commit dca0c9ab81
2 changed files with 39 additions and 2 deletions
+7 -2
View File
@@ -70,7 +70,7 @@ async function login(widget) {
return body.AccessToken;
}
async function apiGet(widget, endpoint, accessToken) {
async function apiGet(widget, endpoint, accessToken, { allow404 = false } = {}) {
const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget }));
const [status, , data] = await httpProxy(url, {
method: "GET",
@@ -79,6 +79,11 @@ async function apiGet(widget, endpoint, accessToken) {
},
});
// e.g. progressstate 404s until a job has run
if (status === 404 && allow404) {
return null;
}
if (status !== 200) {
throw new Error(`Duplicati request failed for ${endpoint}`);
}
@@ -108,7 +113,7 @@ export default async function duplicatiProxyHandler(req, res) {
apiGet(widget, "backups", accessToken),
apiGet(widget, "serverstate", accessToken),
apiGet(widget, "notifications", accessToken),
apiGet(widget, "progressstate", accessToken),
apiGet(widget, "progressstate", accessToken, { allow404: true }),
]);
const summary = buildSummary(
+32
View File
@@ -75,6 +75,38 @@ describe("widgets/duplicati/proxy", () => {
expect(res.body.lastBackup).toBe("2026-07-12T10:00:00.000Z");
});
it("tolerates progressstate 404 when no job has run", async () => {
getServiceWidget.mockResolvedValue({ type: "duplicati", url: "http://dup", password: "secret" });
httpProxy
.mockResolvedValueOnce([200, "application/json", Buffer.from(JSON.stringify({ AccessToken: "token" }))])
.mockResolvedValueOnce([200, "application/json", Buffer.from(JSON.stringify([]))])
.mockResolvedValueOnce([200, "application/json", Buffer.from(JSON.stringify({ ActiveTask: null }))])
.mockResolvedValueOnce([200, "application/json", Buffer.from(JSON.stringify([]))])
.mockResolvedValueOnce([
404,
"application/json",
Buffer.from(JSON.stringify({ Error: "No active backup", Code: 404 })),
]);
const res = createMockRes();
await duplicatiProxyHandler({ query: { group: "g", service: "s" } }, res);
expect(res.statusCode).toBe(200);
expect(res.body.running).toBe(0);
});
it("returns 500 when a non-progressstate endpoint 404s", async () => {
getServiceWidget.mockResolvedValue({ type: "duplicati", url: "http://dup", password: "secret" });
httpProxy
.mockResolvedValueOnce([200, "application/json", Buffer.from(JSON.stringify({ AccessToken: "token" }))])
.mockResolvedValue([404, "application/json", Buffer.from("{}")]);
const res = createMockRes();
await duplicatiProxyHandler({ query: { group: "g", service: "s" } }, res);
expect(res.statusCode).toBe(500);
});
it("returns 500 when login fails", async () => {
getServiceWidget.mockResolvedValue({ type: "duplicati", url: "http://dup", password: "secret" });
httpProxy.mockResolvedValueOnce([401, "application/json", Buffer.from("{}")]);