feat(web): per-item pause route for queued jobs

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jonathan
2026-07-15 12:14:45 +02:00
parent 3d30e7dc8b
commit b78867435a
2 changed files with 73 additions and 0 deletions
@@ -0,0 +1,47 @@
import { describe, it, expect } from "vitest";
import { POST } from "./route";
import { prisma } from "@/lib/db";
import type { Prisma } from "@prisma/client";
function req(id: string, paused: boolean) {
return new Request(`http://localhost/api/requests/${id}/pause`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ paused }),
});
}
async function seed(jobData: Prisma.JobCreateWithoutRequestInput) {
return prisma.request.create({
data: { artist: "A", album: "B", status: "pending", job: { create: jobData } },
include: { job: true },
});
}
describe("per-item pause API", () => {
it("pauses a queued job", async () => {
const created = await seed({ state: "requested" });
const res = await POST(req(created.id, true), { params: Promise.resolve({ id: created.id }) });
expect(res.status).toBe(200);
const job = await prisma.job.findUnique({ where: { id: created.job!.id } });
expect(job?.paused).toBe(true);
});
it("resumes a paused job", async () => {
const created = await seed({ state: "requested", paused: true });
await POST(req(created.id, false), { params: Promise.resolve({ id: created.id }) });
const job = await prisma.job.findUnique({ where: { id: created.job!.id } });
expect(job?.paused).toBe(false);
});
it("rejects pausing an in-flight job", async () => {
const created = await seed({ state: "downloading" });
const res = await POST(req(created.id, true), { params: Promise.resolve({ id: created.id }) });
expect(res.status).toBe(400);
});
it("404s for a missing request", async () => {
const res = await POST(req("nope", true), { params: Promise.resolve({ id: "nope" }) });
expect(res.status).toBe(404);
});
});
@@ -0,0 +1,26 @@
import { prisma } from "@/lib/db";
export async function POST(request: Request, { params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
let body: { paused?: unknown };
try {
body = (await request.json()) as { paused?: unknown };
} catch {
return Response.json({ error: "invalid JSON" }, { status: 400 });
}
if (typeof body.paused !== "boolean") {
return Response.json({ error: "paused must be a boolean" }, { status: 400 });
}
const req = await prisma.request.findUnique({ where: { id }, include: { job: true } });
if (!req || !req.job) {
return Response.json({ error: "not found" }, { status: 404 });
}
if (req.job.state !== "requested") {
return Response.json({ error: "only queued jobs can be paused" }, { status: 400 });
}
await prisma.job.update({ where: { id: req.job.id }, data: { paused: body.paused } });
return Response.json({ ok: true, paused: body.paused });
}