feat: tambah endpoint export-logs dan export-users untuk CSV download

This commit is contained in:
2026-05-28 15:06:23 +08:00
parent 8dca3e440f
commit a0bffd53cb

View File

@@ -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 }) => {