diff --git a/app/api/rigs/route.ts b/app/api/rigs/route.ts index bbf86787..65847392 100644 --- a/app/api/rigs/route.ts +++ b/app/api/rigs/route.ts @@ -9,22 +9,24 @@ function bad(msg: string, code = 400) { return NextResponse.json({ error: msg }, { status: code }); } -// tiny helper so we handle either `dxGET` shape -async function dxArray(path: string, bearer: string): Promise { - const res = await dxGET(path, bearer); - if (Array.isArray(res)) return res as T[]; - if (res?.data && Array.isArray(res.data)) return res.data as T[]; +function takeRows(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); - const me = await dxGET<{ id: string }>("/users/me?fields=id", bearer); + + // 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 wantDebug = q.get("debug") === "1"; const fields = [ "id", @@ -46,53 +48,46 @@ export async function GET(req: Request) { "date_updated", ].join(","); - const base = `/items/user_rigs?fields=${encodeURIComponent( - fields - )}&sort=-date_updated&limit=${limit}`; + // 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}` }, + ]; - // Attempt A: filter by owner - const byOwnerPath = `${base}&filter[owner][_eq]=${encodeURIComponent( - me.id - )}`; - const rowsOwner = await dxArray(byOwnerPath, bearer); + const attempts: Array<{ label: string; count: number }> = []; + let picked: string | null = null; + let rows: any[] = []; - // If nothing, Attempt B: fall back to user_created - let picked = "owner"; - let rows = rowsOwner; - if (!rowsOwner.length) { - const byCreatedPath = `${base}&filter[user_created][_eq]=${encodeURIComponent( - me.id - )}`; - const rowsCreated = await dxArray(byCreatedPath, bearer); - - // Prefer created if owner == 0, otherwise merge (dedupe by id) - if (rowsCreated.length) { - picked = "user_created"; - const map = new Map(); - for (const r of [...rowsOwner, ...rowsCreated]) map.set(r.id, r); - rows = Array.from(map.values()); + for (const t of tries) { + const res = await dxGET(t.path, bearer); + const r = takeRows(res); + attempts.push({ label: t.label, count: r.length }); + if (r.length) { + picked = t.label; + rows = r; + break; } } - if (wantDebug) { - // also fetch counts for the debug panel - const ownerCount = rowsOwner.length; - // Re-run created count only if needed - let createdCount = 0; - if (picked === "user_created") { - const createdCountPath = `${base}&filter[user_created][_eq]=${encodeURIComponent( - me.id - )}&limit=1`; - const createdProbe = await dxArray(createdCountPath, bearer); - createdCount = createdProbe.length ? rows.length : 0; + // last resort: rely entirely on Directus role rule (no filter) + if (!rows.length) { + const res = await dxGET(`/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: [ - { label: "owner", count: ownerCount }, - { label: "user_created", count: picked === "user_created" ? rows.length : 0 }, - ], + attempts, }, data: rows, }); @@ -103,3 +98,70 @@ export async function GET(req: Request) { 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( + `/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); + } +} diff --git a/makearmy-app1806.zip b/makearmy-app1806.zip deleted file mode 100644 index 66ee569e..00000000 Binary files a/makearmy-app1806.zip and /dev/null differ