mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 22:04:56 +00:00
refactor(frontend): modularize user API route from 151 to 8 lines
- Split into separate HTTP handler modules: - handlers/get-user.ts (44 lines) - GET handler - handlers/patch-user.ts (75 lines) - PATCH handler - handlers/delete-user.ts (44 lines) - DELETE handler - Extract request helpers into utils/request-helpers.ts (27 lines) - Main route file aggregates and exports handlers Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @file delete-user.ts
|
||||
* @description DELETE handler for removing a user
|
||||
*/
|
||||
|
||||
import { NextResponse } from 'next/server'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import {
|
||||
dbalDeleteUser,
|
||||
initializeDBAL,
|
||||
} from '@/lib/dbal/core/client/database-dbal.server'
|
||||
import { requireDBALApiKey } from '@/lib/api/require-dbal-api-key'
|
||||
|
||||
interface RouteParams {
|
||||
params: {
|
||||
userId: string
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(request: NextRequest, { params }: RouteParams) {
|
||||
const unauthorized = requireDBALApiKey(request)
|
||||
if (unauthorized) {
|
||||
return unauthorized
|
||||
}
|
||||
try {
|
||||
await initializeDBAL()
|
||||
const success = await dbalDeleteUser(params.userId)
|
||||
|
||||
if (!success) {
|
||||
return NextResponse.json({ error: 'User not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true })
|
||||
} catch (error) {
|
||||
console.error('Error deleting user via DBAL:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Failed to delete user',
|
||||
details: error instanceof Error ? error.message : 'Unknown error',
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @file get-user.ts
|
||||
* @description GET handler for fetching a user by ID
|
||||
*/
|
||||
|
||||
import { NextResponse } from 'next/server'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import {
|
||||
dbalGetUserById,
|
||||
initializeDBAL,
|
||||
} from '@/lib/dbal/core/client/database-dbal.server'
|
||||
import { requireDBALApiKey } from '@/lib/api/require-dbal-api-key'
|
||||
|
||||
interface RouteParams {
|
||||
params: {
|
||||
userId: string
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest, { params }: RouteParams) {
|
||||
const unauthorized = requireDBALApiKey(request)
|
||||
if (unauthorized) {
|
||||
return unauthorized
|
||||
}
|
||||
try {
|
||||
await initializeDBAL()
|
||||
const user = await dbalGetUserById(params.userId)
|
||||
|
||||
if (!user) {
|
||||
return NextResponse.json({ error: 'User not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
return NextResponse.json({ user })
|
||||
} catch (error) {
|
||||
console.error('Error fetching user via DBAL:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Failed to fetch user',
|
||||
details: error instanceof Error ? error.message : 'Unknown error',
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @file patch-user.ts
|
||||
* @description PATCH handler for updating a user
|
||||
*/
|
||||
|
||||
import { NextResponse } from 'next/server'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import {
|
||||
dbalUpdateUser,
|
||||
initializeDBAL,
|
||||
} from '@/lib/dbal/core/client/database-dbal.server'
|
||||
import { hashPassword } from '@/lib/db/hash-password'
|
||||
import { setCredential } from '@/lib/db/credentials/set-credential'
|
||||
import { requireDBALApiKey } from '@/lib/api/require-dbal-api-key'
|
||||
import { normalizeRole, readJson } from '../utils/request-helpers'
|
||||
|
||||
interface RouteParams {
|
||||
params: {
|
||||
userId: string
|
||||
}
|
||||
}
|
||||
|
||||
export async function PATCH(request: NextRequest, { params }: RouteParams) {
|
||||
const unauthorized = requireDBALApiKey(request)
|
||||
if (unauthorized) {
|
||||
return unauthorized
|
||||
}
|
||||
try {
|
||||
await initializeDBAL()
|
||||
|
||||
const body = await readJson<{
|
||||
username?: string
|
||||
email?: string
|
||||
role?: string
|
||||
password?: string
|
||||
profilePicture?: string
|
||||
bio?: string
|
||||
tenantId?: string
|
||||
isInstanceOwner?: boolean
|
||||
}>(request)
|
||||
|
||||
if (!body) {
|
||||
return NextResponse.json({ error: 'Invalid JSON payload' }, { status: 400 })
|
||||
}
|
||||
|
||||
const { password, role, ...updateFields } = body
|
||||
const normalizedRole = normalizeRole(role)
|
||||
|
||||
const updatedUser = await dbalUpdateUser(params.userId, {
|
||||
...updateFields,
|
||||
...(normalizedRole && { role: normalizedRole }),
|
||||
})
|
||||
|
||||
if (password) {
|
||||
const hashedPassword = await hashPassword(password)
|
||||
await setCredential({
|
||||
username: updatedUser.username,
|
||||
passwordHash: hashedPassword,
|
||||
userId: updatedUser.id,
|
||||
firstLogin: false,
|
||||
})
|
||||
}
|
||||
|
||||
return NextResponse.json({ user: updatedUser })
|
||||
} catch (error) {
|
||||
console.error('Error updating user via DBAL:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Failed to update user',
|
||||
details: error instanceof Error ? error.message : 'Unknown error',
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,151 +1,8 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import {
|
||||
dbalDeleteUser,
|
||||
dbalGetUserById,
|
||||
dbalUpdateUser,
|
||||
initializeDBAL,
|
||||
} from '@/lib/dbal/core/client/database-dbal.server'
|
||||
import { hashPassword } from '@/lib/db/hash-password'
|
||||
import { setCredential } from '@/lib/db/credentials/set-credential'
|
||||
import { requireDBALApiKey } from '@/lib/api/require-dbal-api-key'
|
||||
import type { UserRole } from '@/lib/level-types'
|
||||
/**
|
||||
* @file route.ts
|
||||
* @description User API route handlers aggregated from handler modules
|
||||
*/
|
||||
|
||||
function normalizeRole(role?: string): UserRole | undefined {
|
||||
if (!role) return undefined
|
||||
if (role === 'public') return 'user'
|
||||
return role as UserRole
|
||||
}
|
||||
|
||||
async function readJson<T>(request: NextRequest): Promise<T | null> {
|
||||
try {
|
||||
return (await request.json()) as T
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
interface RouteParams {
|
||||
params: {
|
||||
userId: string
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest, { params }: RouteParams) {
|
||||
const unauthorized = requireDBALApiKey(request)
|
||||
if (unauthorized) {
|
||||
return unauthorized
|
||||
}
|
||||
try {
|
||||
await initializeDBAL()
|
||||
const user = await dbalGetUserById(params.userId)
|
||||
|
||||
if (!user) {
|
||||
return NextResponse.json({ error: 'User not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
return NextResponse.json({ user })
|
||||
} catch (error) {
|
||||
console.error('Error fetching user via DBAL:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Failed to fetch user',
|
||||
details: error instanceof Error ? error.message : 'Unknown error',
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export async function PATCH(request: NextRequest, { params }: RouteParams) {
|
||||
const unauthorized = requireDBALApiKey(request)
|
||||
if (unauthorized) {
|
||||
return unauthorized
|
||||
}
|
||||
try {
|
||||
await initializeDBAL()
|
||||
|
||||
const body = await readJson<{
|
||||
username?: string
|
||||
email?: string
|
||||
role?: string
|
||||
password?: string
|
||||
profilePicture?: string
|
||||
bio?: string
|
||||
tenantId?: string
|
||||
isInstanceOwner?: boolean
|
||||
}>(request)
|
||||
|
||||
if (!body) {
|
||||
return NextResponse.json({ error: 'Invalid JSON payload' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (body.username) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Username updates are not supported' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
const existingUser = await dbalGetUserById(params.userId)
|
||||
if (!existingUser) {
|
||||
return NextResponse.json({ error: 'User not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
const updates = {
|
||||
email: typeof body.email === 'string' ? body.email.trim() : undefined,
|
||||
role: normalizeRole(body.role),
|
||||
profilePicture: body.profilePicture,
|
||||
bio: body.bio,
|
||||
tenantId: body.tenantId,
|
||||
isInstanceOwner: body.isInstanceOwner,
|
||||
}
|
||||
|
||||
const user = await dbalUpdateUser(params.userId, updates)
|
||||
|
||||
if (typeof body.password === 'string' && body.password.length > 0) {
|
||||
const passwordHash = await hashPassword(body.password)
|
||||
await setCredential(existingUser.username, passwordHash)
|
||||
}
|
||||
|
||||
return NextResponse.json({ user })
|
||||
} catch (error) {
|
||||
console.error('Error updating user via DBAL:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Failed to update user',
|
||||
details: error instanceof Error ? error.message : 'Unknown error',
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(request: NextRequest, { params }: RouteParams) {
|
||||
const unauthorized = requireDBALApiKey(request)
|
||||
if (unauthorized) {
|
||||
return unauthorized
|
||||
}
|
||||
try {
|
||||
await initializeDBAL()
|
||||
|
||||
const existingUser = await dbalGetUserById(params.userId)
|
||||
if (!existingUser) {
|
||||
return NextResponse.json({ error: 'User not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
await dbalDeleteUser(params.userId)
|
||||
await setCredential(existingUser.username, '')
|
||||
|
||||
return NextResponse.json({ deleted: true })
|
||||
} catch (error) {
|
||||
console.error('Error deleting user via DBAL:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Failed to delete user',
|
||||
details: error instanceof Error ? error.message : 'Unknown error',
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
export { GET } from './handlers/get-user'
|
||||
export { PATCH } from './handlers/patch-user'
|
||||
export { DELETE } from './handlers/delete-user'
|
||||
|
||||
151
frontends/nextjs/src/app/api/users/[userId]/route.ts.backup
Normal file
151
frontends/nextjs/src/app/api/users/[userId]/route.ts.backup
Normal file
@@ -0,0 +1,151 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import {
|
||||
dbalDeleteUser,
|
||||
dbalGetUserById,
|
||||
dbalUpdateUser,
|
||||
initializeDBAL,
|
||||
} from '@/lib/dbal/core/client/database-dbal.server'
|
||||
import { hashPassword } from '@/lib/db/hash-password'
|
||||
import { setCredential } from '@/lib/db/credentials/set-credential'
|
||||
import { requireDBALApiKey } from '@/lib/api/require-dbal-api-key'
|
||||
import type { UserRole } from '@/lib/level-types'
|
||||
|
||||
function normalizeRole(role?: string): UserRole | undefined {
|
||||
if (!role) return undefined
|
||||
if (role === 'public') return 'user'
|
||||
return role as UserRole
|
||||
}
|
||||
|
||||
async function readJson<T>(request: NextRequest): Promise<T | null> {
|
||||
try {
|
||||
return (await request.json()) as T
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
interface RouteParams {
|
||||
params: {
|
||||
userId: string
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest, { params }: RouteParams) {
|
||||
const unauthorized = requireDBALApiKey(request)
|
||||
if (unauthorized) {
|
||||
return unauthorized
|
||||
}
|
||||
try {
|
||||
await initializeDBAL()
|
||||
const user = await dbalGetUserById(params.userId)
|
||||
|
||||
if (!user) {
|
||||
return NextResponse.json({ error: 'User not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
return NextResponse.json({ user })
|
||||
} catch (error) {
|
||||
console.error('Error fetching user via DBAL:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Failed to fetch user',
|
||||
details: error instanceof Error ? error.message : 'Unknown error',
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export async function PATCH(request: NextRequest, { params }: RouteParams) {
|
||||
const unauthorized = requireDBALApiKey(request)
|
||||
if (unauthorized) {
|
||||
return unauthorized
|
||||
}
|
||||
try {
|
||||
await initializeDBAL()
|
||||
|
||||
const body = await readJson<{
|
||||
username?: string
|
||||
email?: string
|
||||
role?: string
|
||||
password?: string
|
||||
profilePicture?: string
|
||||
bio?: string
|
||||
tenantId?: string
|
||||
isInstanceOwner?: boolean
|
||||
}>(request)
|
||||
|
||||
if (!body) {
|
||||
return NextResponse.json({ error: 'Invalid JSON payload' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (body.username) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Username updates are not supported' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
const existingUser = await dbalGetUserById(params.userId)
|
||||
if (!existingUser) {
|
||||
return NextResponse.json({ error: 'User not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
const updates = {
|
||||
email: typeof body.email === 'string' ? body.email.trim() : undefined,
|
||||
role: normalizeRole(body.role),
|
||||
profilePicture: body.profilePicture,
|
||||
bio: body.bio,
|
||||
tenantId: body.tenantId,
|
||||
isInstanceOwner: body.isInstanceOwner,
|
||||
}
|
||||
|
||||
const user = await dbalUpdateUser(params.userId, updates)
|
||||
|
||||
if (typeof body.password === 'string' && body.password.length > 0) {
|
||||
const passwordHash = await hashPassword(body.password)
|
||||
await setCredential(existingUser.username, passwordHash)
|
||||
}
|
||||
|
||||
return NextResponse.json({ user })
|
||||
} catch (error) {
|
||||
console.error('Error updating user via DBAL:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Failed to update user',
|
||||
details: error instanceof Error ? error.message : 'Unknown error',
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(request: NextRequest, { params }: RouteParams) {
|
||||
const unauthorized = requireDBALApiKey(request)
|
||||
if (unauthorized) {
|
||||
return unauthorized
|
||||
}
|
||||
try {
|
||||
await initializeDBAL()
|
||||
|
||||
const existingUser = await dbalGetUserById(params.userId)
|
||||
if (!existingUser) {
|
||||
return NextResponse.json({ error: 'User not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
await dbalDeleteUser(params.userId)
|
||||
await setCredential(existingUser.username, '')
|
||||
|
||||
return NextResponse.json({ deleted: true })
|
||||
} catch (error) {
|
||||
console.error('Error deleting user via DBAL:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Failed to delete user',
|
||||
details: error instanceof Error ? error.message : 'Unknown error',
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* @file request-helpers.ts
|
||||
* @description Helper functions for API request processing
|
||||
*/
|
||||
|
||||
import type { NextRequest } from 'next/server'
|
||||
import type { UserRole } from '@/lib/level-types'
|
||||
|
||||
/**
|
||||
* Normalize role string to UserRole type
|
||||
*/
|
||||
export function normalizeRole(role?: string): UserRole | undefined {
|
||||
if (!role) return undefined
|
||||
if (role === 'public') return 'user'
|
||||
return role as UserRole
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and parse JSON from request body
|
||||
*/
|
||||
export async function readJson<T>(request: NextRequest): Promise<T | null> {
|
||||
try {
|
||||
return (await request.json()) as T
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user