Separate YouTube video titles from on-video song/artist fields with Pro gating, serve curated fonts and watermark assets for 1:1 preview parity, and include billing/API/docs/deploy stack for self-hosted release.
70 lines
1.9 KiB
TypeScript
70 lines
1.9 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { adminResetUserCredits } from "@/lib/billing";
|
|
import { prisma } from "@/lib/db";
|
|
|
|
/**
|
|
* Admin utility: reset / adjust a user's credits.
|
|
* Authorization: Bearer ${ADMIN_API_KEY}
|
|
*
|
|
* Body: { userId | email, plan?, monthlyCredits?, creditsUsed?, extraCredits?, clearFreeTopUp? }
|
|
*/
|
|
export async function POST(req: NextRequest) {
|
|
const adminKey = process.env.ADMIN_API_KEY;
|
|
if (!adminKey) {
|
|
return NextResponse.json({ error: "Admin API not configured" }, { status: 503 });
|
|
}
|
|
|
|
const auth = req.headers.get("authorization");
|
|
if (auth !== `Bearer ${adminKey}`) {
|
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
}
|
|
|
|
let body: {
|
|
userId?: string;
|
|
email?: string;
|
|
plan?: "FREE" | "PREMIUM";
|
|
monthlyCredits?: number;
|
|
creditsUsed?: number;
|
|
extraCredits?: number;
|
|
clearFreeTopUp?: boolean;
|
|
};
|
|
try {
|
|
body = await req.json();
|
|
} catch {
|
|
return NextResponse.json({ error: "Invalid JSON" }, { status: 400 });
|
|
}
|
|
|
|
let userId = body.userId;
|
|
if (!userId && body.email) {
|
|
const found = await prisma.user.findUnique({ where: { email: body.email } });
|
|
if (!found) {
|
|
return NextResponse.json({ error: "User not found" }, { status: 404 });
|
|
}
|
|
userId = found.id;
|
|
}
|
|
if (!userId) {
|
|
return NextResponse.json({ error: "Provide userId or email" }, { status: 400 });
|
|
}
|
|
|
|
const updated = await adminResetUserCredits(userId, {
|
|
plan: body.plan,
|
|
monthlyCredits: body.monthlyCredits,
|
|
creditsUsed: body.creditsUsed,
|
|
extraCredits: body.extraCredits,
|
|
clearFreeTopUp: body.clearFreeTopUp,
|
|
});
|
|
|
|
return NextResponse.json({
|
|
ok: true,
|
|
user: {
|
|
id: updated.id,
|
|
email: updated.email,
|
|
plan: updated.plan,
|
|
monthlyCredits: updated.monthlyCredits,
|
|
creditsUsed: updated.videosUsed,
|
|
extraCredits: updated.extraCredits,
|
|
freeTopUpPurchased: updated.freeTopUpPurchased,
|
|
},
|
|
});
|
|
}
|