doxa-maps-cdn/server/api/admin/users/[id].delete.ts
2026-04-21 12:12:54 +01:00

60 lines
1.8 KiB
TypeScript

import { getRouterParam, getHeader } from 'h3'
import { db, sql } from '../../../utils/database'
import { requirePermission } from '../../../utils/rbac'
import { logEvent } from '../../../utils/activity-logger'
export default defineEventHandler(async (event) => {
const admin = await requirePermission(event, 'users.manage')
const id = getRouterParam(event, 'id')
if (!id) {
throw createError({ statusCode: 400, statusMessage: 'User id is required' })
}
if (id === admin.userId) {
throw createError({ statusCode: 400, statusMessage: 'You cannot delete your own account' })
}
const target = await db
.selectFrom('users')
.select(['id', 'email', 'display_name', 'roles'])
.where('id', '=', id)
.executeTakeFirst()
if (!target) {
throw createError({ statusCode: 404, statusMessage: 'User not found' })
}
if (target.roles.includes('admin')) {
const countRow = await db
.selectFrom('users')
.select(eb => eb.fn.count<string>('id').as('count'))
.where(sql<boolean>`'admin' = ANY(roles)`)
.executeTakeFirst()
const adminCount = Number(countRow?.count ?? 0)
if (adminCount <= 1) {
throw createError({ statusCode: 409, statusMessage: 'Cannot delete the last admin' })
}
}
await db.transaction().execute(async (trx) => {
await trx.deleteFrom('password_reset_requests').where('user_id', '=', id).execute()
await trx.deleteFrom('users').where('id', '=', id).execute()
})
await logEvent({
eventType: 'admin_delete_user',
tableName: 'users',
recordId: id,
userId: admin.userId,
userAgent: getHeader(event, 'user-agent') || undefined,
metadata: {
email: target.email,
display_name: target.display_name,
roles: target.roles
}
})
return { success: true }
})