"use server"; import { db } from "@/lib/db"; import { detectedObjects, adminModeration, } from "@/lib/db/schema"; import { eq } from "drizzle-orm"; import { getAdminSession } from "@/lib/admin"; import { revalidatePath } from "next/cache"; import * as Sentry from "@sentry/nextjs"; export type ReasonCode = | "wrong_object" | "wrong_category" | "false_positive" | "unclear_image" | "duplicate" | "out_of_scope"; export async function adminMarkIncorrect( detectionId: string, reasonCode: ReasonCode, notes?: string ) { try { const session = await getAdminSession(); if (!session) { return { success: false, error: "Unauthorized: admin access required" }; } // 1. Fetch current detection for audit snapshot const current = await db.query.detectedObjects.findFirst({ where: eq(detectedObjects.id, detectionId), }); if (!current) { return { success: false, error: "Detection not found" }; } const originalValues = { objectName: current.objectName, category: current.category, status: current.status, }; // 2. Start transaction return await db.transaction(async (tx) => { // 3. Update detected_objects status to rejected await tx .update(detectedObjects) .set({ status: "rejected", updatedAt: new Date(), }) .where(eq(detectedObjects.id, detectionId)); // 4. Insert audit log await tx.insert(adminModeration).values({ id: crypto.randomUUID(), detectionId, adminId: session.user.id, action: "marked_incorrect", reasonCode: reasonCode as any, originalValues, correctedValues: notes ? { notes } : null, trainAiFlag: true, }); revalidatePath("/admin/moderation"); return { success: true }; }); } catch (error) { Sentry.captureException(error, { tags: { action: "admin-mark-incorrect", detection_id: detectionId, reason_code: reasonCode }, }); console.error("Admin marking incorrect failed:", error); return { success: false, error: "Failed to mark detection as incorrect" }; } }