feat(web): /api/floor pause/resume/clear/stop controls
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { GET, POST } from "./route";
|
||||
import { prisma } from "@/lib/db";
|
||||
|
||||
function post(action: string) {
|
||||
return new Request("http://localhost/api/floor", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({ action }),
|
||||
});
|
||||
}
|
||||
|
||||
async function flag(key: string) {
|
||||
return (await prisma.config.findUnique({ where: { key } }))?.value ?? null;
|
||||
}
|
||||
|
||||
async function queuedRequest(album: string, state = "requested") {
|
||||
return prisma.request.create({
|
||||
data: { artist: "A", album, status: "pending", job: { create: { state: state as never } } },
|
||||
include: { job: true },
|
||||
});
|
||||
}
|
||||
|
||||
describe("floor API", () => {
|
||||
it("GET reports paused=false by default", async () => {
|
||||
const res = await GET();
|
||||
expect(await res.json()).toEqual({ paused: false });
|
||||
});
|
||||
|
||||
it("pause and resume toggle floor.paused", async () => {
|
||||
await POST(post("pause"));
|
||||
expect(await flag("floor.paused")).toBe("true");
|
||||
const paused = await (await GET()).json();
|
||||
expect(paused).toEqual({ paused: true });
|
||||
|
||||
await POST(post("resume"));
|
||||
expect(await flag("floor.paused")).toBe("false");
|
||||
});
|
||||
|
||||
it("stop sets both paused and killRequested", async () => {
|
||||
const res = await POST(post("stop"));
|
||||
expect(res.status).toBe(200);
|
||||
expect(await flag("floor.paused")).toBe("true");
|
||||
expect(await flag("floor.killRequested")).toBe("true");
|
||||
});
|
||||
|
||||
it("clear deletes only queued (requested) requests", async () => {
|
||||
const queued = await queuedRequest("Queued");
|
||||
const active = await queuedRequest("Downloading", "downloading");
|
||||
|
||||
const res = await POST(post("clear"));
|
||||
const body = await res.json();
|
||||
expect(body.cleared).toBe(1);
|
||||
|
||||
expect(await prisma.request.findUnique({ where: { id: queued.id } })).toBeNull();
|
||||
expect(await prisma.request.findUnique({ where: { id: active.id } })).not.toBeNull();
|
||||
});
|
||||
|
||||
it("rejects an unknown action", async () => {
|
||||
const res = await POST(post("nope"));
|
||||
expect(res.status).toBe(400);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
import { prisma } from "@/lib/db";
|
||||
|
||||
async function getFlag(key: string): Promise<boolean> {
|
||||
const row = await prisma.config.findUnique({ where: { key } });
|
||||
return row?.value === "true";
|
||||
}
|
||||
|
||||
async function setFlag(key: string, value: boolean): Promise<void> {
|
||||
const v = value ? "true" : "false";
|
||||
await prisma.config.upsert({
|
||||
where: { key },
|
||||
create: { key, value: v, secret: false },
|
||||
update: { value: v },
|
||||
});
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
return Response.json({ paused: await getFlag("floor.paused") });
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
let body: { action?: string };
|
||||
try {
|
||||
body = (await request.json()) as { action?: string };
|
||||
} catch {
|
||||
return Response.json({ error: "invalid JSON" }, { status: 400 });
|
||||
}
|
||||
|
||||
switch (body.action) {
|
||||
case "pause":
|
||||
await setFlag("floor.paused", true);
|
||||
return Response.json({ ok: true, paused: true });
|
||||
case "resume":
|
||||
await setFlag("floor.paused", false);
|
||||
return Response.json({ ok: true, paused: false });
|
||||
case "stop":
|
||||
await setFlag("floor.paused", true);
|
||||
await setFlag("floor.killRequested", true);
|
||||
return Response.json({ ok: true, paused: true, stopped: true });
|
||||
case "clear": {
|
||||
const { count } = await prisma.request.deleteMany({
|
||||
where: { job: { is: { state: "requested" } } },
|
||||
});
|
||||
return Response.json({ ok: true, cleared: count });
|
||||
}
|
||||
default:
|
||||
return Response.json({ error: "unknown action" }, { status: 400 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user