const axios = require('axios'); const qs = require('qs'); const { KEYCLOAK_REALM, KEYCLOAK_ADMIN_URL, CLIENT_ID, CLIENT_SECRET } = require('../../../config/keycloak.js'); const HttpException = require('../../utils/HttpException.js'); const bcrypt = require('bcrypt'); const prisma = require('../../prisma/PrismaClient.js'); const getAdminToken = async () => { const tokenParams = qs.stringify({ grant_type: 'client_credentials', client_id: CLIENT_ID, client_secret: CLIENT_SECRET }); const { data } = await axios.post( `${KEYCLOAK_ADMIN_URL}/realms/${KEYCLOAK_REALM}/protocol/openid-connect/token`, tokenParams, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } ); return data.access_token; }; const KeycloakRepository = { createUser: async (userData) => { const token = await getAdminToken(); // Cek apakah username sudah terpakai const { data: usersByUsername } = await axios.get( `${KEYCLOAK_ADMIN_URL}/admin/realms/${KEYCLOAK_REALM}/users?username=${encodeURIComponent(userData.username)}`, { headers: { Authorization: `Bearer ${token}` } } ); if (usersByUsername.length > 0) { throw new HttpException('Username already exists in Keycloak', 409); } // Cek apakah email sudah terpakai const { data: usersByEmail } = await axios.get( `${KEYCLOAK_ADMIN_URL}/admin/realms/${KEYCLOAK_REALM}/users?email=${encodeURIComponent(userData.email)}`, { headers: { Authorization: `Bearer ${token}` } } ); if (usersByEmail.length > 0) { throw new HttpException('Email already exists in Keycloak', 409); } const response = await axios.post( `${KEYCLOAK_ADMIN_URL}/admin/realms/${KEYCLOAK_REALM}/users`, { username: userData.username, email: userData.email, firstName: userData.firstname, lastName: userData.lastname, enabled: true, credentials: [{ type: "password", value: userData.password, temporary: false }] }, { headers: { Authorization: `Bearer ${token}` } } ); return response.headers.location.split('/').pop(); }, assignAdminRole: async (userId) => { const token = await getAdminToken(); // Get role sales const { data: roles } = await axios.get( `${KEYCLOAK_ADMIN_URL}/admin/realms/${KEYCLOAK_REALM}/roles`, { headers: { Authorization: `Bearer ${token}` } } ); const adminRole = roles.find(role => role.name === 'admin'); if (!adminRole) throw new HttpException('Admin role not found in Keycloak', 500); // Assign role to user await axios.post( `${KEYCLOAK_ADMIN_URL}/admin/realms/${KEYCLOAK_REALM}/users/${userId}/role-mappings/realm`, [adminRole], { headers: { Authorization: `Bearer ${token}` } } ); }, updateUser: async (userId, updatedData) => { const token = await getAdminToken(); await axios.put( `${KEYCLOAK_ADMIN_URL}/admin/realms/${KEYCLOAK_REALM}/users/${userId}`, { firstName: updatedData.firstname, lastName: updatedData.lastname, email: updatedData.email, credentials: updatedData.password ? [{ type: 'password', value: updatedData.password, temporary: false }] : undefined }, { headers: { Authorization: `Bearer ${token}` } } ); }, deleteUser: async (userId) => { const token = await getAdminToken(); await axios.delete( `${KEYCLOAK_ADMIN_URL}/admin/realms/${KEYCLOAK_REALM}/users/${userId}`, { headers: { Authorization: `Bearer ${token}` } } ); } }; const AdminRepository = { createUser: async (userId, userData) => { const hashedPassword = await bcrypt.hash(userData.password, 10); return prisma.user.create({ data: { id: userId, username: userData.username, email: userData.email, firstname: userData.firstname, lastname: userData.lastname, password: hashedPassword, role: 'admin' } }); }, findAll: async ({ skip, take, where, orderBy }) => { return prisma.user.findMany({ where: { ...where, role: 'admin' }, skip, take, orderBy, select: { id: true, username: true, email: true, firstname: true, lastname: true, role: true, createdAt: true, updatedAt: true, }, }); }, countAll: async (where) => { return prisma.user.count({ where: { ...where, role: 'admin' } }); }, findById: async (id) => { return prisma.user.findFirst({ where: { id, deletedAt: null }, select: { id: true, username: true, email: true, firstname: true, lastname: true, createdAt: true, updatedAt: true, } }); }, updateUser: async (id, updatedData) => { const updatePayload = { email: updatedData.email, firstname: updatedData.firstname, lastname: updatedData.lastname }; if (updatedData.password) { updatePayload.password = await bcrypt.hash(updatedData.password, 10); } return prisma.user.update({ where: { id }, data: updatePayload }); }, deleteUser: async (id) => { return prisma.user.update({ where: { id }, data: { deletedAt: new Date() } }); } }; module.exports = { KeycloakRepository, AdminRepository };