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:
@@ -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 });
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user