Initial commit
This commit is contained in:
166
app/api/admin/users/route.ts
Normal file
166
app/api/admin/users/route.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import { NextRequest } from "next/server";
|
||||
import { z } from "zod";
|
||||
import { NextResponse } from "next/server";
|
||||
import { getPrisma } from "../../../../lib/db";
|
||||
import { getSession } from "../../../../lib/auth/session";
|
||||
import { ok, fail } from "../../../../lib/http";
|
||||
|
||||
export const runtime = "nodejs";
|
||||
|
||||
const QuerySchema = z.object({
|
||||
page: z.string().default("1").transform(Number),
|
||||
search: z.string().optional(),
|
||||
});
|
||||
|
||||
const UpdateUserSchema = z.object({
|
||||
role: z.enum(["USER", "ADMIN"]).optional(),
|
||||
isActive: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const session = await getSession();
|
||||
if (!session || session.role !== "ADMIN") {
|
||||
return fail(new Error("Unauthorized"), { status: 401 });
|
||||
}
|
||||
|
||||
const prisma = await getPrisma();
|
||||
if (!prisma) return fail(new Error("Database not configured"), { status: 503 });
|
||||
|
||||
const parsed = QuerySchema.safeParse(
|
||||
Object.fromEntries(new URL(req.url).searchParams)
|
||||
);
|
||||
if (!parsed.success) return fail(new Error("Invalid query parameters"));
|
||||
|
||||
const appSetup = await prisma.appSetup.findUnique({ where: { id: 1 } });
|
||||
const pageSize = appSetup?.paginationItemsPerPage || 10;
|
||||
const page = Math.max(1, parsed.data.page);
|
||||
const skip = (page - 1) * pageSize;
|
||||
|
||||
const searchFilter = parsed.data.search
|
||||
? {
|
||||
OR: [
|
||||
{ email: { contains: parsed.data.search, mode: "insensitive" as const } },
|
||||
{ firstName: { contains: parsed.data.search, mode: "insensitive" as const } },
|
||||
{ lastName: { contains: parsed.data.search, mode: "insensitive" as const } },
|
||||
],
|
||||
}
|
||||
: undefined;
|
||||
|
||||
const [users, total] = await Promise.all([
|
||||
prisma.user.findMany({
|
||||
where: searchFilter,
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
role: true,
|
||||
isActive: true,
|
||||
emailVerified: true,
|
||||
createdAt: true,
|
||||
gender: true,
|
||||
dob: true,
|
||||
address: true,
|
||||
image: true,
|
||||
},
|
||||
orderBy: { createdAt: "desc" },
|
||||
skip,
|
||||
take: pageSize,
|
||||
}),
|
||||
prisma.user.count({ where: searchFilter }),
|
||||
]);
|
||||
|
||||
// Fetch webinars for each user
|
||||
const usersWithWebinars = await Promise.all(
|
||||
users.map(async (user) => {
|
||||
const registrations = await prisma.webinarRegistration.findMany({
|
||||
where: { userId: user.id, status: { not: "CANCELLED" } },
|
||||
});
|
||||
return {
|
||||
...user,
|
||||
_count: {
|
||||
webinarRegistrations: registrations.length,
|
||||
},
|
||||
registeredWebinars: await prisma.webinarRegistration.findMany({
|
||||
where: { userId: user.id, status: { not: "CANCELLED" } },
|
||||
select: {
|
||||
id: true,
|
||||
status: true,
|
||||
webinar: {
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
startAt: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: 5,
|
||||
}),
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return ok({
|
||||
users: usersWithWebinars,
|
||||
pagination: {
|
||||
page,
|
||||
pageSize,
|
||||
total,
|
||||
pages: Math.ceil(total / pageSize),
|
||||
hasMore: page < Math.ceil(total / pageSize),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function PATCH(req: NextRequest) {
|
||||
const session = await getSession();
|
||||
if (!session || session.role !== "ADMIN") {
|
||||
return fail(new Error("Unauthorized"), { status: 401 });
|
||||
}
|
||||
|
||||
const prisma = await getPrisma();
|
||||
if (!prisma) return fail(new Error("Database not configured"), { status: 503 });
|
||||
|
||||
const body = await req.json().catch(() => ({}));
|
||||
const { userId, ...updateData } = body;
|
||||
|
||||
if (!userId) return fail(new Error("userId is required"));
|
||||
|
||||
const parsed = UpdateUserSchema.safeParse(updateData);
|
||||
if (!parsed.success) return fail(new Error("Invalid update data"));
|
||||
|
||||
// Prevent disabling the current admin
|
||||
if (session.sub === userId && parsed.data.isActive === false) {
|
||||
return fail(new Error("Cannot disable your own account"), { status: 400 });
|
||||
}
|
||||
|
||||
// Prevent removing admin role from self
|
||||
if (session.sub === userId && parsed.data.role && parsed.data.role !== "ADMIN") {
|
||||
return fail(new Error("Cannot change your own role"), { status: 400 });
|
||||
}
|
||||
|
||||
const user = await prisma.user.update({
|
||||
where: { id: userId },
|
||||
data: {
|
||||
...(parsed.data.role && { role: parsed.data.role }),
|
||||
...(parsed.data.isActive !== undefined && { isActive: parsed.data.isActive }),
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
role: true,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
|
||||
return ok({
|
||||
message:
|
||||
parsed.data.isActive === false
|
||||
? "User blocked successfully"
|
||||
: "User updated successfully",
|
||||
user,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user