first commit
This commit is contained in:
209
app/api/users/[id]/route.ts
Normal file
209
app/api/users/[id]/route.ts
Normal file
@@ -0,0 +1,209 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { userDb } from "@/lib/db";
|
||||
import bcrypt from "bcryptjs";
|
||||
|
||||
// GET /api/users/[id] - Get single user (admin only)
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
// Only admins can view users
|
||||
if ((session.user as any).role !== 'ADMIN') {
|
||||
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
const user = userDb.findById(id);
|
||||
|
||||
if (!user) {
|
||||
return NextResponse.json({ error: "User not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
const currentUsername = session.user.name || '';
|
||||
const currentUserId = (session.user as any).id || '';
|
||||
|
||||
// Only the "admin" user can view any user details
|
||||
// ADMIN users can only view their own created viewers
|
||||
if (currentUsername !== 'admin') {
|
||||
// Check if this user is a child of the current user
|
||||
if (user.parent_user_id !== currentUserId) {
|
||||
return NextResponse.json({ error: "User not found" }, { status: 404 });
|
||||
}
|
||||
}
|
||||
|
||||
// Remove password hash from response
|
||||
const { passwordHash, ...safeUser } = user;
|
||||
|
||||
return NextResponse.json({ user: safeUser });
|
||||
} catch (error) {
|
||||
console.error("Error fetching user:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to fetch user" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// PATCH /api/users/[id] - Update user (admin only)
|
||||
export async function PATCH(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
// Only admins can update users
|
||||
if ((session.user as any).role !== 'ADMIN') {
|
||||
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
const user = userDb.findById(id);
|
||||
if (!user) {
|
||||
return NextResponse.json({ error: "User not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
const currentUsername = session.user.name || '';
|
||||
const currentUserId = (session.user as any).id || '';
|
||||
|
||||
// Only the "admin" user can modify any user
|
||||
// ADMIN users can only modify their own created viewers
|
||||
if (currentUsername !== 'admin') {
|
||||
// Check if this user is a child of the current user
|
||||
if (user.parent_user_id !== currentUserId) {
|
||||
return NextResponse.json(
|
||||
{ error: "Forbidden: Cannot modify this user" },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const { username, email, password, role } = body;
|
||||
|
||||
// Validation
|
||||
if (role && !['ADMIN', 'VIEWER'].includes(role)) {
|
||||
return NextResponse.json(
|
||||
{ error: "Invalid role. Must be ADMIN or VIEWER" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// Check if username is taken by another user
|
||||
if (username && username !== user.username) {
|
||||
const existing = userDb.findByUsername(username);
|
||||
if (existing && existing.id !== id) {
|
||||
return NextResponse.json(
|
||||
{ error: "Username already exists" },
|
||||
{ status: 409 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare update data
|
||||
const updateData: {
|
||||
username?: string;
|
||||
email?: string | null;
|
||||
passwordHash?: string;
|
||||
role?: string;
|
||||
} = {};
|
||||
|
||||
if (username !== undefined) updateData.username = username;
|
||||
if (email !== undefined) updateData.email = email;
|
||||
if (role !== undefined) updateData.role = role;
|
||||
if (password) {
|
||||
updateData.passwordHash = await bcrypt.hash(password, 10);
|
||||
}
|
||||
|
||||
const updated = userDb.update(id, updateData);
|
||||
|
||||
if (!updated) {
|
||||
return NextResponse.json({ error: "Failed to update user" }, { status: 500 });
|
||||
}
|
||||
|
||||
// Remove password hash from response
|
||||
const { passwordHash, ...safeUser } = updated;
|
||||
|
||||
return NextResponse.json({ user: safeUser });
|
||||
} catch (error) {
|
||||
console.error("Error updating user:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to update user" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE /api/users/[id] - Delete user (admin only)
|
||||
export async function DELETE(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
// Only admins can delete users
|
||||
if ((session.user as any).role !== 'ADMIN') {
|
||||
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
const user = userDb.findById(id);
|
||||
if (!user) {
|
||||
return NextResponse.json({ error: "User not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
const currentUsername = session.user.name || '';
|
||||
const currentUserId = (session.user as any).id || '';
|
||||
|
||||
// Only the "admin" user can delete any user
|
||||
// ADMIN users can only delete their own created viewers
|
||||
if (currentUsername !== 'admin') {
|
||||
// Check if this user is a child of the current user
|
||||
if (user.parent_user_id !== currentUserId) {
|
||||
return NextResponse.json(
|
||||
{ error: "Forbidden: Cannot delete this user" },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent deleting yourself
|
||||
if ((session.user as any).id === id) {
|
||||
return NextResponse.json(
|
||||
{ error: "Cannot delete your own account" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const success = userDb.delete(id);
|
||||
|
||||
if (!success) {
|
||||
return NextResponse.json({ error: "Failed to delete user" }, { status: 500 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ message: "User deleted successfully" });
|
||||
} catch (error) {
|
||||
console.error("Error deleting user:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to delete user" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user