feat: tambah endpoint inactive-users dan lengkapi field response-nya
This commit is contained in:
@@ -1572,6 +1572,116 @@ const MonitoringServer = new Elysia({ prefix: "/api/monitoring" })
|
||||
}
|
||||
)
|
||||
|
||||
.get("/inactive-users", async ({ query, set }) => {
|
||||
const VALID_DAYS = [7, 14, 30];
|
||||
const days = VALID_DAYS.includes(Number(query.days)) ? Number(query.days) : 7;
|
||||
const pageNum = Number(query.page ?? 1) || 1;
|
||||
const take = 15;
|
||||
const { idVillage } = query;
|
||||
|
||||
try {
|
||||
const users = await prisma.user.findMany({
|
||||
where: {
|
||||
idUserRole: { not: 'developer' },
|
||||
...(idVillage && { idVillage }),
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
nik: true,
|
||||
email: true,
|
||||
phone: true,
|
||||
gender: true,
|
||||
isActive: true,
|
||||
isWithoutOTP: true,
|
||||
isApprover: true,
|
||||
idUserRole: true,
|
||||
idVillage: true,
|
||||
idGroup: true,
|
||||
idPosition: true,
|
||||
UserRole: { select: { name: true } },
|
||||
Village: { select: { id: true, name: true } },
|
||||
Group: { select: { name: true } },
|
||||
Position: { select: { name: true } },
|
||||
UserLog: {
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 1,
|
||||
select: { createdAt: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const threshold = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
|
||||
|
||||
const inactive = users
|
||||
.map((u) => ({
|
||||
id: u.id,
|
||||
name: u.name,
|
||||
nik: u.nik,
|
||||
email: u.email,
|
||||
phone: u.phone,
|
||||
gender: u.gender,
|
||||
isActive: u.isActive,
|
||||
isWithoutOTP: u.isWithoutOTP,
|
||||
isApprover: u.isApprover,
|
||||
role: u.UserRole?.name ?? null,
|
||||
idUserRole: u.idUserRole,
|
||||
village: u.Village?.name ?? null,
|
||||
idVillage: u.Village?.id ?? null,
|
||||
group: u.Group?.name ?? null,
|
||||
position: u.Position?.name ?? null,
|
||||
idGroup: u.idGroup,
|
||||
idPosition: u.idPosition,
|
||||
lastActivity: u.UserLog[0]?.createdAt ?? null,
|
||||
daysSince: u.UserLog[0]?.createdAt
|
||||
? Math.floor((Date.now() - u.UserLog[0].createdAt.getTime()) / (1000 * 60 * 60 * 24))
|
||||
: null,
|
||||
}))
|
||||
.filter((u) => u.lastActivity === null || u.lastActivity < threshold)
|
||||
.sort((a, b) => {
|
||||
if (a.lastActivity === null) return -1;
|
||||
if (b.lastActivity === null) return 1;
|
||||
return a.lastActivity.getTime() - b.lastActivity.getTime();
|
||||
});
|
||||
|
||||
const total = inactive.length;
|
||||
const paginated = inactive.slice((pageNum - 1) * take, pageNum * take);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Berhasil mendapatkan data",
|
||||
data: {
|
||||
users: paginated,
|
||||
total,
|
||||
totalPage: Math.ceil(total / take),
|
||||
currentPage: pageNum,
|
||||
days,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("[inactive-users] error:", error);
|
||||
set.status = 500;
|
||||
return {
|
||||
success: false,
|
||||
message: "Terjadi kesalahan pada server",
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
query: t.Object({
|
||||
days: t.Optional(t.String({ description: "Threshold hari tidak aktif: 7, 14, atau 30 (default: 7)" })),
|
||||
idVillage: t.Optional(t.String({ description: "Filter berdasarkan ID desa" })),
|
||||
page: t.Optional(t.String({ description: "Halaman (default: 1)" })),
|
||||
}),
|
||||
detail: {
|
||||
summary: "Inactive Users",
|
||||
description: "Mendapatkan daftar user yang tidak ada aktivitas dalam X hari terakhir, atau belum pernah ada aktivitas sama sekali.",
|
||||
tags: ["user"],
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// ─── API KEY MANAGEMENT ──────────────────────────────────────────────────
|
||||
|
||||
.get("/api-keys", async ({ set }) => {
|
||||
|
||||
Reference in New Issue
Block a user