feat(auth): align login and bootstrap with new user schema
This commit is contained in:
+96
-23
@@ -1,4 +1,6 @@
|
||||
import { fileURLToPath } from "node:url"
|
||||
import { UserStatus } from "@/generated/prisma/client"
|
||||
import { normalizeEmail } from "@/lib/email"
|
||||
import { getPasswordHash } from "@/lib/security"
|
||||
import prisma from "../src/lib/prisma"
|
||||
|
||||
@@ -8,10 +10,19 @@ type BootstrapAdminInput = {
|
||||
password: string
|
||||
}
|
||||
|
||||
function splitName(name: string) {
|
||||
const [firstName = "Administrator", ...rest] = name.trim().split(/\s+/)
|
||||
|
||||
return {
|
||||
firstName,
|
||||
lastName: rest.join(" "),
|
||||
}
|
||||
}
|
||||
|
||||
function getBootstrapAdminInput(): BootstrapAdminInput {
|
||||
const isProduction = process.env.NODE_ENV === "production"
|
||||
|
||||
const email = process.env.ADMIN_EMAIL ?? "admin@localhost"
|
||||
const email = process.env.ADMIN_EMAIL ?? "admin@local.host"
|
||||
const name = process.env.ADMIN_NAME ?? "Administrator"
|
||||
const password = process.env.ADMIN_PASSWORD
|
||||
|
||||
@@ -28,36 +39,98 @@ function getBootstrapAdminInput(): BootstrapAdminInput {
|
||||
|
||||
export async function bootstrapAdmin(client: typeof prisma) {
|
||||
const enabled = process.env.ADMIN_BOOTSTRAP_ENABLED !== "false"
|
||||
const existingAdmin = await client.user.findFirst({
|
||||
if (!enabled) return
|
||||
|
||||
const admin = getBootstrapAdminInput()
|
||||
const email = normalizeEmail(admin.email)
|
||||
const { firstName, lastName } = splitName(admin.name)
|
||||
const existingUser = await client.user.findUnique({
|
||||
where: {
|
||||
role: "ADMIN",
|
||||
isActive: true,
|
||||
emailNormalized: email,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
passwordHash: true,
|
||||
activatedAt: true,
|
||||
person: {
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if (existingAdmin || !enabled) return
|
||||
const user = existingUser
|
||||
? await client.user.update({
|
||||
where: {
|
||||
id: existingUser.id,
|
||||
},
|
||||
data: {
|
||||
name: admin.name,
|
||||
email: admin.email,
|
||||
emailNormalized: email,
|
||||
role: "ADMIN",
|
||||
status: UserStatus.ACTIVE,
|
||||
...(existingUser.passwordHash
|
||||
? {}
|
||||
: {
|
||||
passwordHash: await getPasswordHash(admin.password),
|
||||
passwordChangedAt: new Date(),
|
||||
}),
|
||||
...(existingUser.activatedAt ? {} : { activatedAt: new Date() }),
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
person: {
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
: await client.user.create({
|
||||
data: {
|
||||
name: admin.name,
|
||||
email: admin.email,
|
||||
emailNormalized: email,
|
||||
role: "ADMIN",
|
||||
status: UserStatus.ACTIVE,
|
||||
passwordHash: await getPasswordHash(admin.password),
|
||||
activatedAt: new Date(),
|
||||
passwordChangedAt: new Date(),
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
person: {
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const admin = getBootstrapAdminInput()
|
||||
|
||||
await client.user.upsert({
|
||||
where: {
|
||||
email: admin.email,
|
||||
},
|
||||
update: {
|
||||
role: "ADMIN",
|
||||
isActive: true,
|
||||
},
|
||||
create: {
|
||||
name: admin.name,
|
||||
email: admin.email,
|
||||
role: "ADMIN",
|
||||
password: await getPasswordHash(admin.password),
|
||||
isActive: true,
|
||||
},
|
||||
})
|
||||
if (!user.person) {
|
||||
await client.person.upsert({
|
||||
where: {
|
||||
userId: user.id,
|
||||
},
|
||||
update: {
|
||||
firstName,
|
||||
lastName,
|
||||
email: admin.email,
|
||||
},
|
||||
create: {
|
||||
firstName,
|
||||
lastName,
|
||||
email: admin.email,
|
||||
user: {
|
||||
connect: {
|
||||
id: user.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
|
||||
Reference in New Issue
Block a user