Lewati ke konten

Perbaikan update route

Hanya mengubah field yang benar-benar dikirim.

Berkas: alat/hari-3/Praktik 9/perbaikan/update-route.js

Praktik 9/perbaikan/update-route.js
// =====================================================================
// Praktik 9 - versi perbaikan update/route.js
//
// Perubahan dari versi modul:
//
// 1. requireAuth() dijalankan sebelum body dibaca.
//
// 2. HANYA field yang benar-benar dikirim yang ikut di-update. Versi modul
// selalu menulis
// data: { role: data.role, is_active: data.is_active }
// sehingga permintaan yang hanya ingin mengubah role tetap mengirim
// is_active: undefined. Perilaku Prisma untuk undefined adalah
// "jangan ubah", jadi kebetulan tidak merusak — tetapi ini bergantung
// pada detail implementasi, bukan pada niat penulis kode. Kalau
// suatu saat nilainya null (bukan undefined), kolomnya benar-benar
// dikosongkan.
//
// 3. Ada penjagaan agar super_admin tidak bisa diturunkan menjadi admin
// lewat API ini. Versi modul membatasi daftar role, tetapi tidak
// melindungi akun super_admin yang sudah ada dari perubahan is_active.
//
// 4. Ada penjagaan agar pengguna tidak menonaktifkan dirinya sendiri.
//
// 5. Respons memakai select yang sama seperti list — tanpa kolom password.
//
// Letakkan berkas ini di: src/app/api/users/update/route.js
// =====================================================================
import { NextResponse } from "next/server";
import { requireAuth } from "../../../../../lib/auth/verifyBearerToken";
import { db } from "../../../../../lib/db";
import { ROLE_DAPAT_DIUBAH } from "../../../../../lib/auth/roles";
export async function POST(request) {
const { payload, error, status } = requireAuth(request, "super_admin");
if (error) {
return NextResponse.json({ message: error }, { status });
}
let data;
try {
data = await request.json();
} catch {
return NextResponse.json({ message: "Body harus berupa JSON" }, { status: 400 });
}
const userId = typeof data.user_id === "string" ? data.user_id : "";
if (!userId) {
return NextResponse.json({ message: "user_id wajib diisi" }, { status: 400 });
}
const adaRole = data.role !== undefined;
const adaIsActive = data.is_active !== undefined;
if (!adaRole && !adaIsActive) {
return NextResponse.json(
{ message: "Tidak ada field yang diubah" },
{ status: 400 },
);
}
if (adaRole && !ROLE_DAPAT_DIUBAH.includes(data.role)) {
return NextResponse.json(
{ message: `Role tidak valid. Pilihan: ${ROLE_DAPAT_DIUBAH.join(", ")}` },
{ status: 400 },
);
}
if (adaIsActive && typeof data.is_active !== "boolean") {
return NextResponse.json({ message: "is_active harus true atau false" }, { status: 400 });
}
// Jangan biarkan super_admin menonaktifkan atau menurunkan dirinya sendiri.
if (payload.user_id === userId) {
if (adaIsActive && data.is_active === false) {
return NextResponse.json(
{ message: "Tidak bisa menonaktifkan akun sendiri" },
{ status: 400 },
);
}
if (adaRole && data.role !== "super_admin") {
return NextResponse.json(
{ message: "Tidak bisa menurunkan role akun sendiri" },
{ status: 400 },
);
}
}
try {
const target = await db.users.findUnique({
where: { user_id: userId },
select: { user_id: true, role: true, is_active: true },
});
if (!target) {
return NextResponse.json({ message: "User tidak ditemukan" }, { status: 404 });
}
// Akun super_admin tidak boleh diturunkan lewat endpoint ini.
// Untuk itu perlu jalur terpisah dengan pencatatan audit.
if (target.role === "super_admin" && adaRole && data.role !== "super_admin") {
return NextResponse.json(
{ message: "Role super_admin tidak dapat diubah lewat endpoint ini" },
{ status: 403 },
);
}
// Hanya sertakan field yang dikirim.
const perubahan = {};
if (adaRole) perubahan.role = data.role;
if (adaIsActive) perubahan.is_active = data.is_active;
const pengguna = await db.users.update({
where: { user_id: userId },
data: perubahan,
select: {
user_id: true,
nama: true,
email: true,
role: true,
is_active: true,
},
});
return NextResponse.json(
{ message: "Berhasil memperbarui data user", data: pengguna },
{ status: 200 },
);
} catch (err) {
console.error("[users/update]", err);
return NextResponse.json({ message: "Terjadi kesalahan pada server" }, { status: 500 });
}
}