From a0bffd53cb21a37be5f1ffdbd603ae9b702e83c0 Mon Sep 17 00:00:00 2001 From: amaliadwiy Date: Thu, 28 May 2026 15:06:23 +0800 Subject: [PATCH] feat: tambah endpoint export-logs dan export-users untuk CSV download --- src/app/api/monitoring/[[...slug]]/route.ts | 135 ++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/src/app/api/monitoring/[[...slug]]/route.ts b/src/app/api/monitoring/[[...slug]]/route.ts index 4176299..095a165 100644 --- a/src/app/api/monitoring/[[...slug]]/route.ts +++ b/src/app/api/monitoring/[[...slug]]/route.ts @@ -1736,6 +1736,141 @@ const MonitoringServer = new Elysia({ prefix: "/api/monitoring" }) } ) + // ─── CSV EXPORT ────────────────────────────────────────────────────────── + + .get("/export-logs", async ({ query, set }) => { + const { search, action, idVillage, dateFrom, dateTo } = query; + + const whereClause = { + ...(action && { action: action.toUpperCase() }), + ...(idVillage && { User: { idVillage } }), + ...((dateFrom || dateTo) && { + createdAt: { + ...(dateFrom && { gte: new Date(dateFrom) }), + ...(dateTo && { lte: new Date(new Date(dateTo).setHours(23, 59, 59, 999)) }), + }, + }), + ...(search && { + OR: [ + { User: { name: { contains: search, mode: "insensitive" as const } } }, + { User: { Village: { name: { contains: search, mode: "insensitive" as const } } } }, + ], + }), + }; + + try { + const data = await prisma.userLog.findMany({ + where: whereClause, + select: { + createdAt: true, + action: true, + desc: true, + User: { + select: { + name: true, + Village: { select: { name: true } }, + }, + }, + }, + orderBy: { createdAt: "desc" }, + }); + + const result = data.map((item) => ({ + timestamp: moment(item.createdAt).format('DD MMM YYYY HH:mm'), + username: item.User.name, + village: item.User.Village.name, + action: item.action, + desc: item.desc, + })); + + return { success: true, data: result }; + } catch (error) { + console.error("[export-logs] error:", error); + set.status = 500; + return { success: false, message: "Terjadi kesalahan pada server", data: null }; + } + }, { + query: t.Object({ + search: t.Optional(t.String()), + action: t.Optional(t.String()), + idVillage: t.Optional(t.String()), + dateFrom: t.Optional(t.String()), + dateTo: t.Optional(t.String()), + }), + detail: { summary: "Export Logs CSV", tags: ["log-activity"] }, + }) + + .get("/export-users", async ({ query, set }) => { + const { search, isActive, idUserRole, idVillage } = query; + + const whereClause = { + ...(isActive !== undefined && { isActive: isActive === 'true' }), + ...(idUserRole && { idUserRole }), + ...(idVillage && { idVillage }), + ...(search && { + OR: [ + { name: { contains: search, mode: "insensitive" as const } }, + { phone: { contains: search, mode: "insensitive" as const } }, + { email: { contains: search, mode: "insensitive" as const } }, + { nik: { contains: search, mode: "insensitive" as const } }, + { Village: { name: { contains: search, mode: "insensitive" as const } } }, + ], + }), + }; + + try { + const data = await prisma.user.findMany({ + where: whereClause, + select: { + name: true, + nik: true, + phone: true, + email: true, + gender: true, + isActive: true, + UserRole: { select: { name: true } }, + Village: { select: { name: true } }, + Group: { select: { name: true } }, + Position: { select: { name: true } }, + UserLog: { + orderBy: { createdAt: 'desc' }, + take: 1, + select: { createdAt: true }, + }, + }, + orderBy: { name: 'asc' }, + }); + + const result = data.map((item) => ({ + name: item.name, + nik: item.nik, + email: item.email, + phone: item.phone, + gender: item.gender === 'M' ? 'Male' : item.gender === 'F' ? 'Female' : item.gender, + role: item.UserRole?.name ?? '', + village: item.Village?.name ?? '', + group: item.Group?.name ?? '', + position: item.Position?.name ?? '', + status: item.isActive ? 'Active' : 'Inactive', + lastActivity: item.UserLog[0]?.createdAt ? moment(item.UserLog[0].createdAt).format('DD MMM YYYY HH:mm') : '', + })); + + return { success: true, data: result }; + } catch (error) { + console.error("[export-users] error:", error); + set.status = 500; + return { success: false, message: "Terjadi kesalahan pada server", data: null }; + } + }, { + query: t.Object({ + search: t.Optional(t.String()), + isActive: t.Optional(t.String()), + idUserRole: t.Optional(t.String()), + idVillage: t.Optional(t.String()), + }), + detail: { summary: "Export Users CSV", tags: ["user"] }, + }) + // ─── API KEY MANAGEMENT ────────────────────────────────────────────────── .get("/api-keys", async ({ set }) => {