refactor(catalog): unify commands and embed guarded catalog workspace

This commit is contained in:
Simo committed 2026-09-06 19:40:52 +02:00
1 parent 16f35568f5
commit 193b6686a9
57 files changed
+3268 -728

No files matched your search

@@ -0,0 +1,49 @@
import { NextRequest } from "next/server";
import { beforeEach, describe, expect, it, vi } from "vitest";
vi.mock("@/lib/permissions", () => import("@/lib/permission-slugs"));
const search = vi.hoisted(() => vi.fn());
const guard = vi.hoisted(() => vi.fn());
vi.mock("@/features/catalog/server/search", () => ({ searchCatalog: search }));
vi.mock("@/features/catalog/server/errors", () => ({
catalogFailure: () => ({ message: "Invalid search", status: 400 }),
}));
vi.mock("@/lib/api-handler", () => ({
withAdmin: (
options: unknown,
handler: (request: NextRequest) => Promise<Response>,
) => {
guard(options);
return handler;
},
}));
import { PERMS } from "@/lib/permissions";
import { GET } from "./route";
beforeEach(() => {
search.mockReset();
});
describe("catalog search route", () => {
it("registers the catalog read permission", () => {
expect(guard).toHaveBeenCalledWith({ permission: PERMS.CATALOG_VIEW });
});
it("forwards normal or BC without widening scope and returns results", async () => {
search.mockResolvedValue([]);
const response = await GET(
new NextRequest(
"https://cms.test/api/admin/catalog/search?catalog=bc&q=chair",
),
);
expect(search).toHaveBeenCalledWith("bc", "chair");
expect(await response.json()).toEqual({ ok: true, results: [] });
});
it("returns a validation error without a success payload", async () => {
search.mockRejectedValue(Error("Invalid search"));
const response = await GET(
new NextRequest("https://cms.test/api/admin/catalog/search?q=a"),
);
expect(response.status).toBe(400);
expect(await response.json()).toEqual({ error: "Invalid search" });
});
});
+22
View File
@@ -0,0 +1,22 @@
import { catalogFailure } from "@/features/catalog/server/errors";
import { searchCatalog } from "@/features/catalog/server/search";
import { apiError, apiOk } from "@/lib/api";
import { withAdmin } from "@/lib/api-handler";
import { PERMS } from "@/lib/permissions";
export const GET = withAdmin(
{ permission: PERMS.CATALOG_VIEW },
async (request) => {
const params = request.nextUrl.searchParams;
try {
return apiOk({
results: await searchCatalog(
params.get("catalog") ?? "normal",
params.get("q") ?? "",
),
});
} catch (error) {
const failure = catalogFailure(error);
return apiError(failure.message, failure.status);
}
},
);
+18
View File
@@ -0,0 +1,18 @@
import {
readCatalogHotelStatus,
sendCatalogUpdate,
} from "@/features/catalog/server/sync-status";
import { apiOk } from "@/lib/api";
import { withAdmin } from "@/lib/api-handler";
import { PERMS } from "@/lib/permissions";
import { catalogExportStatus } from "@/lib/services/catalog-git-queue";
export const GET = withAdmin({ permission: PERMS.CATALOG_VIEW }, async () => {
const [hotel, git] = await Promise.all([
readCatalogHotelStatus(),
catalogExportStatus(),
]);
return apiOk({ hotel, git });
});
export const POST = withAdmin({ permission: PERMS.CATALOG_EDIT }, async () =>
apiOk({ hotel: await sendCatalogUpdate() }),
);
File diff suppressed because it is too large. Load diff