Bootstrap configured admin users
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "prisma generate && next build",
|
"build": "prisma generate && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"start:deploy": "prisma db push && tsx prisma/seed-if-empty.ts && next start",
|
"start:deploy": "prisma db push && tsx prisma/seed-if-empty.ts && tsx prisma/bootstrap-admins.ts && next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"db:generate": "prisma generate",
|
"db:generate": "prisma generate",
|
||||||
"db:migrate": "prisma migrate dev",
|
"db:migrate": "prisma migrate dev",
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import { PrismaClient, SubscriptionStatus, UserRole } from "@prisma/client";
|
||||||
|
import { getConfiguredAdminEmails } from "../src/lib/admin-emails";
|
||||||
|
|
||||||
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const adminEmails = getConfiguredAdminEmails();
|
||||||
|
if (adminEmails.length === 0) {
|
||||||
|
console.log("No ADMIN_EMAILS configured. Skipping admin bootstrap.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const premiumPlan = await prisma.plan.findUnique({ where: { code: "PREMIUM" } });
|
||||||
|
if (!premiumPlan) {
|
||||||
|
throw new Error("PREMIUM plan is not seeded.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const email of adminEmails) {
|
||||||
|
const user = await prisma.user.findUnique({ where: { email } });
|
||||||
|
if (!user) {
|
||||||
|
console.log(`Admin email ${email} is configured but user does not exist yet.`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await prisma.user.update({
|
||||||
|
where: { id: user.id },
|
||||||
|
data: { role: UserRole.ADMIN }
|
||||||
|
});
|
||||||
|
|
||||||
|
await prisma.subscription.upsert({
|
||||||
|
where: { userId: user.id },
|
||||||
|
update: {
|
||||||
|
planId: premiumPlan.id,
|
||||||
|
status: SubscriptionStatus.ACTIVE,
|
||||||
|
cancelAtPeriodEnd: false
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
userId: user.id,
|
||||||
|
planId: premiumPlan.id,
|
||||||
|
status: SubscriptionStatus.ACTIVE
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Admin access ensured for ${email}.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
process.exit(1);
|
||||||
|
})
|
||||||
|
.finally(async () => {
|
||||||
|
await prisma.$disconnect();
|
||||||
|
});
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
import bcrypt from "bcryptjs";
|
import bcrypt from "bcryptjs";
|
||||||
|
import { UserRole } from "@prisma/client";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { prisma } from "@/lib/db";
|
import { prisma } from "@/lib/db";
|
||||||
import { createSession } from "@/lib/auth/session";
|
import { createSession } from "@/lib/auth/session";
|
||||||
|
import { isConfiguredAdminEmail } from "@/lib/admin-emails";
|
||||||
|
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
email: z.string().email(),
|
email: z.string().email(),
|
||||||
@@ -12,18 +14,21 @@ const schema = z.object({
|
|||||||
|
|
||||||
export async function POST(req: Request) {
|
export async function POST(req: Request) {
|
||||||
const body = schema.parse(await req.json());
|
const body = schema.parse(await req.json());
|
||||||
const free = await prisma.plan.findUnique({ where: { code: "FREE" } });
|
const email = body.email.trim().toLowerCase();
|
||||||
if (!free) return NextResponse.json({ error: "PLAN_NOT_SEEDED" }, { status: 500 });
|
const isAdmin = isConfiguredAdminEmail(email);
|
||||||
|
const plan = await prisma.plan.findUnique({ where: { code: isAdmin ? "PREMIUM" : "FREE" } });
|
||||||
|
if (!plan) return NextResponse.json({ error: "PLAN_NOT_SEEDED" }, { status: 500 });
|
||||||
|
|
||||||
const exists = await prisma.user.findUnique({ where: { email: body.email } });
|
const exists = await prisma.user.findUnique({ where: { email } });
|
||||||
if (exists) return NextResponse.json({ error: "EMAIL_EXISTS" }, { status: 409 });
|
if (exists) return NextResponse.json({ error: "EMAIL_EXISTS" }, { status: 409 });
|
||||||
|
|
||||||
const user = await prisma.user.create({
|
const user = await prisma.user.create({
|
||||||
data: {
|
data: {
|
||||||
email: body.email,
|
email,
|
||||||
name: body.name || body.email.split("@")[0],
|
name: body.name || email.split("@")[0],
|
||||||
passwordHash: await bcrypt.hash(body.password, 10),
|
passwordHash: await bcrypt.hash(body.password, 10),
|
||||||
subscription: { create: { planId: free.id, status: "ACTIVE" } }
|
role: isAdmin ? UserRole.ADMIN : UserRole.USER,
|
||||||
|
subscription: { create: { planId: plan.id, status: "ACTIVE" } }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await createSession(user.id);
|
await createSession(user.id);
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
export function getConfiguredAdminEmails() {
|
||||||
|
return (process.env.ADMIN_EMAILS || "")
|
||||||
|
.split(/[\s,;]+/)
|
||||||
|
.map((email) => email.trim().toLowerCase())
|
||||||
|
.filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isConfiguredAdminEmail(email: string) {
|
||||||
|
return getConfiguredAdminEmails().includes(email.trim().toLowerCase());
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user