4c3880e07f
Moderator role existed in the schema and was already respected by
comment deletion, but every admin page/route treated moderator
identically to a regular user (403/redirect). Wires it up narrowly:
admin/layout.tsx now lets admin+moderator through and filters the
nav by role, while every admin-only page (users, tiers, settings,
webhooks, insights, etc.) explicitly redirects moderators away via a
new requireFullAdminPage() helper -- the nav filter is UX, this is
the actual gate. Moderators land on Reports and Recipes: reports
GET/PATCH now accept requireAdmin({allowModerator: true}), and a new
PATCH /api/v1/admin/recipes/[id] lets admin+moderator unpublish a
public recipe (flip to private) as a takedown action, audit-logged.
Also found and fixed a real bug while auditing the PWA push pipeline
for a "push click-through" gap: public/sw.js had no `push` event
listener at all, so incoming push messages never displayed anything
-- push was silently non-functional end-to-end despite the
subscribe/send plumbing all working. Added the push listener
(showNotification) and a notificationclick listener that focuses an
existing tab or opens one at the payload's url.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
29 lines
846 B
TypeScript
29 lines
846 B
TypeScript
import { NextResponse } from "next/server";
|
|
import { requireAdmin } from "@/lib/api-auth";
|
|
import { db, reports, users, eq, desc } from "@epicure/db";
|
|
|
|
export async function GET() {
|
|
const { response } = await requireAdmin({ allowModerator: true });
|
|
if (response) return response;
|
|
|
|
const rows = await db
|
|
.select({
|
|
id: reports.id,
|
|
targetType: reports.targetType,
|
|
targetId: reports.targetId,
|
|
reason: reports.reason,
|
|
status: reports.status,
|
|
createdAt: reports.createdAt,
|
|
reporterId: reports.reporterId,
|
|
reporterName: users.name,
|
|
reporterEmail: users.email,
|
|
})
|
|
.from(reports)
|
|
.innerJoin(users, eq(reports.reporterId, users.id))
|
|
.where(eq(reports.status, "pending"))
|
|
.orderBy(desc(reports.createdAt))
|
|
.limit(100);
|
|
|
|
return NextResponse.json({ reports: rows });
|
|
}
|