167 lines
5.6 KiB
TypeScript
167 lines
5.6 KiB
TypeScript
// app/api/rigs/route.ts
|
||
import { NextResponse } from "next/server";
|
||
import { dxGET, dxPOST, dxDELETE } from "@/lib/directus";
|
||
import { requireBearer } from "@/app/api/_lib/auth";
|
||
|
||
export const runtime = "nodejs";
|
||
|
||
function bad(msg: string, code = 400) {
|
||
return NextResponse.json({ error: msg }, { status: code });
|
||
}
|
||
|
||
function takeRows<T = any>(res: any): T[] {
|
||
if (Array.isArray(res)) return res;
|
||
if (Array.isArray(res?.data)) return res.data;
|
||
return [];
|
||
}
|
||
|
||
export async function GET(req: Request) {
|
||
try {
|
||
const bearer = requireBearer(req);
|
||
|
||
// who am i?
|
||
const me = await dxGET<{ id: string; role?: { id: string; name?: string } }>(
|
||
"/users/me?fields=id,role.id,role.name",
|
||
bearer
|
||
);
|
||
|
||
const q = new URL(req.url).searchParams;
|
||
const limit = Math.min(parseInt(q.get("limit") || "50", 10), 100);
|
||
|
||
const fields = [
|
||
"id",
|
||
"name",
|
||
"notes",
|
||
"rig_type.id",
|
||
"rig_type.name",
|
||
"laser_source.submission_id",
|
||
"laser_source.make",
|
||
"laser_source.model",
|
||
"laser_scan_lens.id",
|
||
"laser_scan_lens.field_size",
|
||
"laser_scan_lens.focal_length",
|
||
"laser_focus_lens.id",
|
||
"laser_focus_lens.name",
|
||
"laser_software.id",
|
||
"laser_software.name",
|
||
"date_created",
|
||
"date_updated",
|
||
].join(",");
|
||
|
||
// we’ll try multiple filters; first non-empty result wins
|
||
const base = `&fields=${encodeURIComponent(fields)}&sort=-date_updated&limit=${limit}`;
|
||
const tries = [
|
||
{ label: "owner.id", path: `/items/user_rigs?filter[owner][id][_eq]=${encodeURIComponent(me.id)}${base}` },
|
||
{ label: "owner", path: `/items/user_rigs?filter[owner][_eq]=${encodeURIComponent(me.id)}${base}` },
|
||
{ label: "user_created", path: `/items/user_rigs?filter[user_created][_eq]=${encodeURIComponent(me.id)}${base}` },
|
||
];
|
||
|
||
const attempts: Array<{ label: string; count: number }> = [];
|
||
let picked: string | null = null;
|
||
let rows: any[] = [];
|
||
|
||
for (const t of tries) {
|
||
const res = await dxGET<any>(t.path, bearer);
|
||
const r = takeRows(res);
|
||
attempts.push({ label: t.label, count: r.length });
|
||
if (r.length) {
|
||
picked = t.label;
|
||
rows = r;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// last resort: rely entirely on Directus role rule (no filter)
|
||
if (!rows.length) {
|
||
const res = await dxGET<any>(`/items/user_rigs?${base.slice(1)}`, bearer);
|
||
const r = takeRows(res);
|
||
attempts.push({ label: "(no filter, rely on role rule)", count: r.length });
|
||
if (r.length) {
|
||
picked = "(role rule)";
|
||
rows = r;
|
||
}
|
||
}
|
||
|
||
if (q.get("debug") === "1") {
|
||
return NextResponse.json({
|
||
meta: {
|
||
me: { id: me.id, role: me.role?.name || me.role?.id || null },
|
||
picked,
|
||
attempts,
|
||
},
|
||
data: rows,
|
||
});
|
||
}
|
||
|
||
return NextResponse.json(rows);
|
||
} catch (e: any) {
|
||
return bad(e?.message || "Failed to load rigs", e?.status || 500);
|
||
}
|
||
}
|
||
|
||
export async function POST(req: Request) {
|
||
try {
|
||
const bearer = requireBearer(req);
|
||
const body = await req.json().catch(() => ({}));
|
||
|
||
const name = (body?.name || "").trim();
|
||
const rig_type = body?.rig_type; // id
|
||
const laser_source = body?.laser_source; // submission_id
|
||
const laser_scan_lens = body?.laser_scan_lens || null;
|
||
const laser_focus_lens = body?.laser_focus_lens || null;
|
||
const laser_software = body?.laser_software || null;
|
||
const notes = (body?.notes || "").trim();
|
||
|
||
if (!name) return bad("Missing: name");
|
||
if (!rig_type) return bad("Missing: rig_type");
|
||
if (!laser_source) return bad("Missing: laser_source");
|
||
|
||
// derive owner from the authenticated user
|
||
const me = await dxGET<{ id: string }>("/users/me?fields=id", bearer);
|
||
|
||
const payload: any = {
|
||
owner: me.id,
|
||
name,
|
||
rig_type,
|
||
laser_source,
|
||
laser_scan_lens,
|
||
laser_focus_lens,
|
||
laser_software,
|
||
notes,
|
||
};
|
||
|
||
const res = await dxPOST<{ data: { id: string } }>(
|
||
"/items/user_rigs",
|
||
bearer,
|
||
payload
|
||
);
|
||
|
||
return NextResponse.json({ ok: true, id: String(res?.data?.id) });
|
||
} catch (e: any) {
|
||
return bad(e?.message || "Failed to create rig", e?.status || 500);
|
||
}
|
||
}
|
||
|
||
export async function DELETE(req: Request) {
|
||
try {
|
||
const bearer = requireBearer(req);
|
||
const url = new URL(req.url);
|
||
const id = url.searchParams.get("id");
|
||
if (!id) return bad("Missing: id");
|
||
|
||
// ensure the rig belongs to the current user
|
||
const me = await dxGET<{ id: string }>("/users/me?fields=id", bearer);
|
||
const rig = await dxGET<any>(
|
||
`/items/user_rigs/${encodeURIComponent(id)}?fields=id,owner`,
|
||
bearer
|
||
);
|
||
if (!rig || String(rig.owner) !== String(me.id)) {
|
||
return bad("Not your rig", 403);
|
||
}
|
||
|
||
await dxDELETE(`/items/user_rigs/${encodeURIComponent(id)}`, bearer);
|
||
return NextResponse.json({ ok: true });
|
||
} catch (e: any) {
|
||
return bad(e?.message || "Failed to delete rig", e?.status || 500);
|
||
}
|
||
}
|