Files
Moonbase/src/app/api/rambles/[id]/route.ts
tonym 083e2992c9 v0.29.0 — Ramble box, dark-mode toggle, pantry pull reasons
- #10 Ramble box: new /ramble sticky-note board (post/pin/archive/delete),
  ported from FMB. New Ramble model + migration, /api/rambles routes, nav entry.
- #6 Dark-mode toggle: sun/moon button in the top bar (dark palette already
  existed in CSS, just had no control).
- #9 Pantry pull reason: structured disposition (Immediate use / Preserved /
  Gave away / Waste) on ItemLog.reason, added to single + bulk pull dialogs
  and the audit payload. New migration.
- #2 Suggestions: drop the stale white-card wrapper; render SuggestionsPanel
  bare like FMB so it's readable and thumbnails show.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 14:40:54 -05:00

66 lines
2.1 KiB
TypeScript

import { NextResponse } from "next/server";
import { z } from "zod";
import { db } from "@/lib/db";
import { requireAuth } from "@/lib/auth";
export const dynamic = "force-dynamic";
const patchSchema = z.object({
body: z.string().trim().min(1).max(5000).optional(),
pinned: z.boolean().optional(),
archived: z.boolean().optional(),
});
// PATCH /api/rambles/:id — edit body, pin/unpin, or archive/restore.
export async function PATCH(req: Request, { params }: { params: { id: string } }) {
let session;
try {
session = await requireAuth();
} catch {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
let input;
try {
input = patchSchema.parse(await req.json());
} catch (err) {
const msg = err instanceof z.ZodError ? err.errors[0].message : "Invalid input";
return NextResponse.json({ error: msg }, { status: 400 });
}
const data: { body?: string; pinned?: boolean; archivedAt?: Date | null } = {};
if (input.body !== undefined) data.body = input.body;
if (input.pinned !== undefined) data.pinned = input.pinned;
if (input.archived !== undefined) data.archivedAt = input.archived ? new Date() : null;
try {
const ramble = await db.ramble.update({ where: { id: params.id }, data });
await db.auditEvent.create({
data: { action: "ramble.update", entityId: ramble.id, actorId: session.user.id, payload: input },
});
return NextResponse.json(ramble);
} catch {
return NextResponse.json({ error: "Not found" }, { status: 404 });
}
}
// DELETE /api/rambles/:id — hard delete (a ramble is disposable by design).
export async function DELETE(_req: Request, { params }: { params: { id: string } }) {
let session;
try {
session = await requireAuth();
} catch {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
try {
await db.ramble.delete({ where: { id: params.id } });
await db.auditEvent.create({
data: { action: "ramble.delete", entityId: params.id, actorId: session.user.id },
});
return NextResponse.json({ ok: true });
} catch {
return NextResponse.json({ error: "Not found" }, { status: 404 });
}
}