request->getGet('role'); if ($roleCode === null || $roleCode === '') { return $this->errorResponse('Query parameter role is required', null, null, 422); } $roleModel = new RoleModel(); $role = $roleModel->findByCode((string) $roleCode); if (!$role) { return $this->successResponse([], 'Users'); } $userRoleModel = new UserRoleModel(); $db = \Config\Database::connect(); $builder = $db->table('user_roles'); $builder->select('user_id'); $builder->where('role_id', $role->id); $rows = $builder->get()->getResultArray(); $userIdList = array_values(array_unique(array_map(static fn ($r) => (int) $r['user_id'], $rows))); if ($userIdList === []) { return $this->successResponse([], 'Users'); } $userModel = new UserModel(); $users = $userModel->whereIn('id', $userIdList)->findAll(); $data = []; foreach ($users as $u) { $data[] = [ 'id' => (int) $u->id, 'name' => (string) $u->name, 'email' => (string) $u->email, ]; } usort($data, static fn ($a, $b) => strcasecmp($a['name'], $b['name'])); return $this->successResponse($data, 'Users'); } /** * POST /api/users * Body (baru): name, email, password, roles[] (isi: GURU_MAPEL dan/atau WALI_KELAS). * Body (lama, tetap didukung): name, email, password, role_code. */ public function store(): ResponseInterface { $payload = $this->request->getJSON(true) ?? []; $name = trim($payload['name'] ?? ''); $email = trim($payload['email'] ?? ''); $password = $payload['password'] ?? ''; $rolesInput = $payload['roles'] ?? null; $roleCode = $payload['role_code'] ?? null; // fallback lama if ($name === '' || $email === '' || $password === '') { return $this->errorResponse('Name, email, and password are required', null, null, 422); } $roleModel = new RoleModel(); $allowedCodes = ['GURU_MAPEL', 'WALI_KELAS']; // Normalisasi roles: jika roles[] tidak ada, pakai role_code tunggal (kompatibilitas lama) $roleCodes = []; if (is_array($rolesInput)) { foreach ($rolesInput as $rc) { $rc = (string) $rc; if (in_array($rc, $allowedCodes, true)) { $roleCodes[] = $rc; } } $roleCodes = array_values(array_unique($roleCodes)); } elseif (is_string($roleCode) && $roleCode !== '') { if (! in_array($roleCode, $allowedCodes, true)) { return $this->errorResponse('role_code must be GURU_MAPEL or WALI_KELAS', null, null, 422); } $roleCodes = [$roleCode]; } if ($roleCodes === []) { return $this->errorResponse('At least one role (GURU_MAPEL or WALI_KELAS) is required', null, null, 422); } $userModel = new UserModel(); $existing = $userModel->findByEmail($email); if ($existing) { return $this->errorResponse('Email already registered', null, null, 422); } $userModel->skipValidation(false); $id = $userModel->insert([ 'name' => $name, 'email' => $email, 'password_hash' => password_hash($password, PASSWORD_DEFAULT), 'is_active' => 1, ]); if ($id === false) { return $this->errorResponse(implode(' ', $userModel->errors()), $userModel->errors(), null, 422); } $userRoleModel = new UserRoleModel(); foreach ($roleCodes as $code) { $role = $roleModel->findByCode($code); if ($role) { $userRoleModel->insert(['user_id' => $id, 'role_id' => $role->id]); } } $user = $userModel->find($id); return $this->successResponse([ 'id' => (int) $user->id, 'name' => (string) $user->name, 'email' => (string) $user->email, ], 'User created', null, ResponseInterface::HTTP_CREATED); } /** * PUT /api/users/{id} * Body (baru): name?, email?, password?, roles[] (GURU_MAPEL/WALI_KELAS) * Body (lama, tetap didukung): role_code tunggal. */ public function update(int $id): ResponseInterface { $userModel = new UserModel(); $user = $userModel->find($id); if (! $user) { return $this->errorResponse('User not found', null, null, 404); } $payload = $this->request->getJSON(true) ?? []; $data = []; if (array_key_exists('name', $payload)) { $data['name'] = trim($payload['name']); } if (array_key_exists('email', $payload)) { $data['email'] = trim($payload['email']); } if (isset($payload['password']) && $payload['password'] !== '') { $data['password_hash'] = password_hash($payload['password'], PASSWORD_DEFAULT); } if ($data !== []) { $validation = \Config\Services::validation(); $rules = [ 'name' => 'required|max_length[255]', 'email' => 'required|valid_email|max_length[255]|is_unique[users.email,id,' . $id . ']', ]; $toValidate = [ 'name' => $data['name'] ?? $user->name, 'email' => $data['email'] ?? $user->email, ]; if (! $validation->setRules($rules)->run($toValidate)) { return $this->errorResponse(implode(' ', $validation->getErrors()), $validation->getErrors(), null, 422); } $userModel->skipValidation(true); $userModel->update($id, $data); } // Sinkronisasi roles $rolesInput = $payload['roles'] ?? null; $roleCode = $payload['role_code'] ?? null; // fallback lama $allowedCodes = ['GURU_MAPEL', 'WALI_KELAS']; $roleCodes = null; if (is_array($rolesInput)) { $roleCodes = []; foreach ($rolesInput as $rc) { $rc = (string) $rc; if (in_array($rc, $allowedCodes, true)) { $roleCodes[] = $rc; } } $roleCodes = array_values(array_unique($roleCodes)); } elseif (isset($roleCode) && in_array($roleCode, $allowedCodes, true)) { // kompatibilitas lama: satu role_code $roleCodes = [$roleCode]; } if (is_array($roleCodes)) { $roleModel = new RoleModel(); $userRoleModel = new UserRoleModel(); $db = \Config\Database::connect(); // Hapus semua role sebelumnya, lalu insert sesuai request $db->table('user_roles')->where('user_id', $id)->delete(); foreach ($roleCodes as $code) { $role = $roleModel->findByCode($code); if ($role) { $userRoleModel->insert(['user_id' => $id, 'role_id' => $role->id]); } } } $updated = $userModel->find($id); return $this->successResponse([ 'id' => (int) $updated->id, 'name' => (string) $updated->name, 'email' => (string) $updated->email, ], 'User updated'); } /** * DELETE /api/users/{id} */ public function delete(int $id): ResponseInterface { $userModel = new UserModel(); if (! $userModel->find($id)) { return $this->errorResponse('User not found', null, null, 404); } $userModel->delete($id); return $this->successResponse(null, 'User deleted'); } }