diff --git a/src/app/api/users/[id]/route.ts b/src/app/api/users/[id]/route.ts new file mode 100644 index 0000000..fcb3345 --- /dev/null +++ b/src/app/api/users/[id]/route.ts @@ -0,0 +1,123 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { prisma } from '@/lib/prisma'; +import { getSession } from '@/lib/auth-simple'; +import { hasRole, canEditUserProfiles } from '@/lib/permissions'; + +export async function GET( + request: NextRequest, + { params }: { params: { id: string } } +) { + try { + const session = await getSession(); + + if (!session) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } + + // Users can only query their own profile or if they're an admin + const requestingUser = await prisma.user.findUnique({ + where: { id: session.user.id }, + select: { role: true } + }); + + if (!requestingUser) { + return NextResponse.json({ error: 'Requesting user not found' }, { status: 404 }); + } + + // Allow if requesting own profile or if user is club_admin + const canView = session.user.id === params.id || requestingUser.role === 'club_admin'; + if (!canView) { + return NextResponse.json({ error: 'Forbidden' }, { status: 403 }); + } + + const user = await prisma.user.findUnique({ + where: { id: params.id }, + include: { + player: true, + } + }); + + if (!user) { + return NextResponse.json({ error: 'User not found' }, { status: 404 }); + } + + return NextResponse.json(user); + } catch { + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); + } +} + +export async function PATCH( + request: NextRequest, + { params }: { params: { id: string } } +) { + try { + const session = await getSession(); + + if (!session) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } + + // Check if user can edit this user's name + // Only club_admin can edit any user's name + const canEditResult = await canEditUserProfiles(); + if (!canEditResult.allowed) { + return NextResponse.json( + { error: canEditResult.reason || 'Insufficient permissions' }, + { status: 403 } + ); + } + + const { name } = await request.json(); + + // Validate the name + if (!name || typeof name !== 'string' || name.trim().length === 0) { + return NextResponse.json( + { error: 'Name is required and must be a non-empty string' }, + { status: 400 } + ); + } + + const trimmedName = name.trim(); + + // Check if user exists + const user = await prisma.user.findUnique({ + where: { id: params.id }, + include: { player: true } + }); + + if (!user) { + return NextResponse.json({ error: 'User not found' }, { status: 404 }); + } + + // Update the user's name and the associated player's name if it exists + const updateData: any = { name: trimmedName }; + + if (user.player) { + // Also update the player name if the user has an associated player + updateData.player = { + update: { + name: trimmedName, + normalizedName: trimmedName.toLowerCase(), + } + }; + } + + const updatedUser = await prisma.user.update({ + where: { id: params.id }, + data: updateData, + include: { player: true } + }); + + return NextResponse.json({ + message: 'User name updated successfully', + user: updatedUser + }); + } catch (error) { + console.error("Failed to update user name:", error); + return NextResponse.json( + { error: "Failed to update user name" }, + { status: 500 } + ); + } +}