diff --git a/web/src/app/api/config/route.test.ts b/web/src/app/api/config/route.test.ts index 22bad83..7f0bf97 100644 --- a/web/src/app/api/config/route.test.ts +++ b/web/src/app/api/config/route.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, beforeAll } from "vitest"; -import { GET, PUT } from "./route"; +import { GET, PUT, DELETE } from "./route"; import { prisma } from "@/lib/db"; beforeAll(() => { @@ -14,6 +14,10 @@ function putReq(body: unknown) { }); } +function delReq(field: string) { + return new Request(`http://localhost/api/config?field=${field}`, { method: "DELETE" }); +} + describe("config API", () => { it("stores plain fields verbatim and secret fields encrypted", async () => { await PUT(putReq({ qobuzEmail: "me@example.com", qobuzPassword: "hunter2", slskdUrl: "http://slskd:5030", slskdApiKey: "abc" })); @@ -59,3 +63,25 @@ describe("config API", () => { expect(pw).not.toBeNull(); // still present, not wiped }); }); + +describe("config DELETE", () => { + it("removes a stored secret by field name", async () => { + await PUT(putReq({ qobuzPassword: "hunter2" })); + expect(await prisma.config.findUnique({ where: { key: "qobuz.password" } })).not.toBeNull(); + const res = await DELETE(delReq("qobuzPassword")); + expect(res.status).toBe(200); + expect(await prisma.config.findUnique({ where: { key: "qobuz.password" } })).toBeNull(); + // GET now reports it unset + expect((await (await GET()).json()).qobuzPasswordSet).toBe(false); + }); + + it("rejects an unknown field with 400 and deletes nothing", async () => { + const res = await DELETE(delReq("monitor.enabled")); + expect(res.status).toBe(400); + }); + + it("is idempotent — deleting an absent field returns 200", async () => { + const res = await DELETE(delReq("slskdApiKey")); + expect(res.status).toBe(200); + }); +}); diff --git a/web/src/app/api/config/route.ts b/web/src/app/api/config/route.ts index add8476..440d215 100644 --- a/web/src/app/api/config/route.ts +++ b/web/src/app/api/config/route.ts @@ -45,3 +45,13 @@ export async function GET() { slskdApiKeySet: byKey.has("slskd.api_key"), }); } + +export async function DELETE(request: Request) { + const field = new URL(request.url).searchParams.get("field") ?? ""; + const entry = FIELDS[field]; + if (!entry) { + return Response.json({ error: "unknown field" }, { status: 400 }); + } + await prisma.config.deleteMany({ where: { key: entry.key } }); // idempotent + return Response.json({ ok: true }); +}