55 lines
1.6 KiB
TypeScript
55 lines
1.6 KiB
TypeScript
import { userRepo } from "@/server/repositories/user.repo";
|
|
|
|
export const userService = {
|
|
/**
|
|
* Suspend user oleh admin. Idempotent — kalau sudah suspended, tolak supaya
|
|
* admin tahu (cegah race condition multiple admin suspend sekaligus).
|
|
* Wajib reason untuk audit (min 10 char).
|
|
*/
|
|
async suspendUser(input: {
|
|
userId: string;
|
|
adminId: string;
|
|
reason: string;
|
|
}) {
|
|
if (input.userId === input.adminId) {
|
|
throw new Error("Tidak bisa suspend akun sendiri");
|
|
}
|
|
const trimmedReason = input.reason.trim();
|
|
if (trimmedReason.length < 10) {
|
|
throw new Error("Alasan suspend wajib min 10 karakter untuk audit");
|
|
}
|
|
if (trimmedReason.length > 500) {
|
|
throw new Error("Alasan suspend maksimal 500 karakter");
|
|
}
|
|
|
|
const target = await userRepo.findById(input.userId);
|
|
if (!target) {
|
|
throw new Error("User tidak ditemukan");
|
|
}
|
|
if (target.suspended) {
|
|
throw new Error("User sudah dalam status suspended");
|
|
}
|
|
|
|
return userRepo.setSuspension(input.userId, {
|
|
suspended: true,
|
|
suspendedById: input.adminId,
|
|
suspendedReason: trimmedReason,
|
|
});
|
|
},
|
|
|
|
async unsuspendUser(input: { userId: string; adminId: string }) {
|
|
if (input.userId === input.adminId) {
|
|
throw new Error("Tidak bisa modifikasi akun sendiri");
|
|
}
|
|
const target = await userRepo.findById(input.userId);
|
|
if (!target) {
|
|
throw new Error("User tidak ditemukan");
|
|
}
|
|
if (!target.suspended) {
|
|
throw new Error("User tidak dalam status suspended");
|
|
}
|
|
|
|
return userRepo.setSuspension(input.userId, { suspended: false });
|
|
},
|
|
};
|