109 lines
3.7 KiB
JavaScript
109 lines
3.7 KiB
JavaScript
import AdminJS from 'adminjs'
|
|
import AdminJSFastify from '@adminjs/fastify'
|
|
import { Database, Resource, getModelByName } from '@adminjs/prisma'
|
|
import bcrypt from 'bcrypt'
|
|
import { exec } from 'child_process'
|
|
import { prisma } from './src/lib/db.mjs'
|
|
|
|
AdminJS.registerAdapter({ Database, Resource })
|
|
|
|
// ── Auto-build (prod only) ──────────────────────────────────────────────────
|
|
let buildTimeout = null
|
|
let buildInProgress = false
|
|
|
|
function triggerBuild() {
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
console.log('[admin] Dev mode — skipping build')
|
|
return
|
|
}
|
|
if (buildTimeout) clearTimeout(buildTimeout)
|
|
buildTimeout = setTimeout(() => {
|
|
if (buildInProgress) return
|
|
buildInProgress = true
|
|
console.log('[admin] Building site...')
|
|
exec('pnpm build', { cwd: process.cwd(), timeout: 120_000 }, (err, stdout, stderr) => {
|
|
buildInProgress = false
|
|
if (err) console.error('[admin] Build FAILED:', stderr)
|
|
else console.log('[admin] Build OK')
|
|
})
|
|
}, 5_000)
|
|
}
|
|
|
|
const afterBuildHook = async (response) => { triggerBuild(); return response }
|
|
|
|
// ── AdminJS setup ───────────────────────────────────────────────────────────
|
|
export async function setupAdmin(app) {
|
|
const admin = new AdminJS({
|
|
rootPath: '/admin',
|
|
resources: [
|
|
{
|
|
resource: { model: getModelByName('Product'), client: prisma },
|
|
options: {
|
|
navigation: { name: 'Contenu', icon: 'Package' },
|
|
listProperties: ['sortOrder', 'name', 'type', 'price', 'isPublished', 'updatedAt'],
|
|
editProperties: [
|
|
'slug', 'sortOrder', 'index', 'name', 'type', 'materials',
|
|
'year', 'status', 'description', 'specs', 'notes',
|
|
'imagePath', 'imageAlt',
|
|
'seoTitle', 'seoDescription', 'ogImage',
|
|
'productDisplayName', 'price', 'currency', 'availability',
|
|
'stripePriceId', 'stripeKey', 'isPublished',
|
|
],
|
|
properties: {
|
|
description: { type: 'textarea' },
|
|
specs: { type: 'textarea' },
|
|
notes: { type: 'textarea' },
|
|
seoDescription: { type: 'textarea' },
|
|
},
|
|
actions: {
|
|
new: { after: [afterBuildHook] },
|
|
edit: { after: [afterBuildHook] },
|
|
delete: { after: [afterBuildHook] },
|
|
},
|
|
},
|
|
},
|
|
{
|
|
resource: { model: getModelByName('Order'), client: prisma },
|
|
options: {
|
|
navigation: { name: 'Commerce', icon: 'CreditCard' },
|
|
listProperties: ['stripeSessionId', 'status', 'amount', 'customerEmail', 'productSlug', 'createdAt'],
|
|
actions: {
|
|
new: { isAccessible: false },
|
|
edit: { isAccessible: false },
|
|
delete: { isAccessible: false },
|
|
},
|
|
},
|
|
},
|
|
],
|
|
branding: {
|
|
companyName: 'REBOURS Studio',
|
|
logo: false,
|
|
withMadeWithLove: false,
|
|
},
|
|
})
|
|
|
|
await AdminJSFastify.buildAuthenticatedRouter(
|
|
admin,
|
|
{
|
|
authenticate: async (email, password) => {
|
|
const user = await prisma.adminUser.findUnique({ where: { email } })
|
|
if (!user) return null
|
|
const valid = await bcrypt.compare(password, user.passwordHash)
|
|
return valid ? { email: user.email, id: user.id } : null
|
|
},
|
|
cookiePassword: process.env.COOKIE_SECRET ?? 'super-secret-cookie-password-at-least-32-chars',
|
|
cookieName: 'adminjs',
|
|
},
|
|
app,
|
|
{
|
|
saveUninitialized: false,
|
|
cookie: {
|
|
httpOnly: true,
|
|
secure: process.env.NODE_ENV === 'production',
|
|
},
|
|
}
|
|
)
|
|
|
|
return admin
|
|
}
|