db = $db ?? Database::connect(); } /** * @return array{status: int, pesan: string, data?: mixed} */ public function kantorList(): array { $rows = $this->db->table('kantor')->orderBy('nama_kantor', 'ASC')->get()->getResultArray(); return ['status' => 1, 'pesan' => 'OK', 'data' => ['rows' => $rows]]; } /** * @param array $input * * @return array{status: int, pesan: string, data?: mixed} */ public function kantorSave(array $input, ?int $id = null): array { $rules = [ 'kode_kantor' => 'required|max_length[100]', 'nama_kantor' => 'required|max_length[50]', 'alamat_kantor' => 'required|max_length[255]', 'tipe' => 'required|max_length[50]', 'lat' => 'required', 'lng' => 'required', 'jarak_rekam_presensi' => 'permit_empty|integer', ]; $v = Services::validation(); $v->setRules($rules); if (! $v->run($input)) { return ['status' => 0, 'pesan' => implode(' ', $v->getErrors())]; } $row = [ 'kode_kantor' => (string) $input['kode_kantor'], 'nama_kantor' => (string) $input['nama_kantor'], 'alamat_kantor' => (string) $input['alamat_kantor'], 'tipe' => (string) $input['tipe'], 'lat' => (float) $input['lat'], 'lng' => (float) $input['lng'], 'jarak_rekam_presensi' => (int) ($input['jarak_rekam_presensi'] ?? 30), ]; if ($id === null) { $this->db->table('kantor')->insert($row); return ['status' => 1, 'pesan' => 'Disimpan.', 'data' => ['id_kantor' => (int) $this->db->insertID()]]; } $this->db->table('kantor')->where('id_kantor', $id)->update($row); return ['status' => 1, 'pesan' => 'Diperbarui.']; } /** * @return array{status: int, pesan: string} */ public function kantorDelete(int $id): array { $n = (int) $this->db->table('pegawai')->where('kantor', $id)->countAllResults(); if ($n > 0) { return ['status' => 0, 'pesan' => 'Kantor masih dipakai ' . $n . ' pegawai.']; } $this->db->table('kantor')->where('id_kantor', $id)->delete(); return ['status' => 1, 'pesan' => 'Dihapus.']; } /** * @return array{status: int, pesan: string, data?: mixed} */ public function unitKerjaList(): array { $rows = $this->db->table('unit_kerja')->orderBy('nama_unit_kerja', 'ASC')->get()->getResultArray(); return ['status' => 1, 'pesan' => 'OK', 'data' => ['rows' => $rows]]; } /** * @param array $input * * @return array{status: int, pesan: string, data?: mixed} */ public function unitKerjaSave(array $input, ?int $id = null): array { $v = Services::validation(); $v->setRules(['nama_unit_kerja' => 'required|max_length[50]']); if (! $v->run($input)) { return ['status' => 0, 'pesan' => implode(' ', $v->getErrors())]; } $row = ['nama_unit_kerja' => (string) $input['nama_unit_kerja']]; if ($id === null) { $this->db->table('unit_kerja')->insert($row); return ['status' => 1, 'pesan' => 'Disimpan.', 'data' => ['id_unit_kerja' => (int) $this->db->insertID()]]; } $this->db->table('unit_kerja')->where('id_unit_kerja', $id)->update($row); return ['status' => 1, 'pesan' => 'Diperbarui.']; } /** * @return array{status: int, pesan: string} */ public function unitKerjaDelete(int $id): array { $n = (int) $this->db->table('pegawai')->where('unit_kerja', $id)->countAllResults(); if ($n > 0) { return ['status' => 0, 'pesan' => 'Unit masih dipakai pegawai.']; } $this->db->table('unit_kerja')->where('id_unit_kerja', $id)->delete(); return ['status' => 1, 'pesan' => 'Dihapus.']; } /** * @return array{status: int, pesan: string, data?: mixed} */ public function golonganList(): array { $rows = $this->db->table('golongan')->orderBy('nama_golongan', 'ASC')->get()->getResultArray(); return ['status' => 1, 'pesan' => 'OK', 'data' => ['rows' => $rows]]; } /** * @param array $input * * @return array{status: int, pesan: string, data?: mixed} */ public function golonganSave(array $input, ?int $id = null): array { $v = Services::validation(); $v->setRules(['nama_golongan' => 'permit_empty|max_length[100]']); if (! $v->run($input)) { return ['status' => 0, 'pesan' => implode(' ', $v->getErrors())]; } $row = ['nama_golongan' => (string) ($input['nama_golongan'] ?? '')]; if ($id === null) { $this->db->table('golongan')->insert($row); return ['status' => 1, 'pesan' => 'Disimpan.', 'data' => ['id_golongan' => (int) $this->db->insertID()]]; } $this->db->table('golongan')->where('id_golongan', $id)->update($row); return ['status' => 1, 'pesan' => 'Diperbarui.']; } /** * @return array{status: int, pesan: string} */ public function golonganDelete(int $id): array { $n = (int) $this->db->table('pegawai')->where('golongan_pekerjaan', $id)->countAllResults(); if ($n > 0) { return ['status' => 0, 'pesan' => 'Golongan masih dipakai pegawai.']; } $this->db->table('golongan')->where('id_golongan', $id)->delete(); return ['status' => 1, 'pesan' => 'Dihapus.']; } /** * @return array{status: int, pesan: string, data?: mixed} */ public function jabatanList(): array { $rows = $this->db->table('jabatan')->orderBy('nama_jabatan', 'ASC')->get()->getResultArray(); return ['status' => 1, 'pesan' => 'OK', 'data' => ['rows' => $rows]]; } /** * @param array $input * * @return array{status: int, pesan: string, data?: mixed} */ public function jabatanSave(array $input, ?int $id = null): array { $v = Services::validation(); $v->setRules(['nama_jabatan' => 'required|max_length[50]']); if (! $v->run($input)) { return ['status' => 0, 'pesan' => implode(' ', $v->getErrors())]; } $row = ['nama_jabatan' => (string) $input['nama_jabatan']]; if ($id === null) { $this->db->table('jabatan')->insert($row); return ['status' => 1, 'pesan' => 'Disimpan.', 'data' => ['id_jabatan' => (int) $this->db->insertID()]]; } $this->db->table('jabatan')->where('id_jabatan', $id)->update($row); return ['status' => 1, 'pesan' => 'Diperbarui.']; } /** * @return array{status: int, pesan: string} */ public function jabatanDelete(int $id): array { $n = (int) $this->db->table('pegawai')->where('jabatan', $id)->countAllResults(); if ($n > 0) { return ['status' => 0, 'pesan' => 'Jabatan masih dipakai pegawai.']; } $this->db->table('jabatan')->where('id_jabatan', $id)->delete(); return ['status' => 1, 'pesan' => 'Dihapus.']; } /** * @return array{status: int, pesan: string, data?: mixed} */ public function beritaList(): array { $rows = $this->db->table('berita')->orderBy('tanggal', 'DESC')->get()->getResultArray(); return ['status' => 1, 'pesan' => 'OK', 'data' => ['rows' => $rows]]; } /** * @param array $input * * @return array{status: int, pesan: string, data?: mixed} */ public function beritaSave(array $input, ?int $id = null): array { $v = Services::validation(); $v->setRules([ 'tanggal' => 'required|valid_date', 'judul' => 'required|max_length[255]', 'isi' => 'required', 'photo' => 'permit_empty|max_length[255]', ]); if (! $v->run($input)) { return ['status' => 0, 'pesan' => implode(' ', $v->getErrors())]; } $photo = trim((string) ($input['photo'] ?? '')); if ($photo === '') { $photo = '-'; } $row = [ 'tanggal' => (string) $input['tanggal'], 'judul' => (string) $input['judul'], 'isi' => (string) $input['isi'], 'photo' => $photo, ]; if ($id === null) { $this->db->table('berita')->insert($row); return ['status' => 1, 'pesan' => 'Disimpan.', 'data' => ['id_berita' => (int) $this->db->insertID()]]; } $this->db->table('berita')->where('id_berita', $id)->update($row); return ['status' => 1, 'pesan' => 'Diperbarui.']; } /** * @return array{status: int, pesan: string} */ public function beritaDelete(int $id): array { $this->db->table('berita')->where('id_berita', $id)->delete(); return ['status' => 1, 'pesan' => 'Dihapus.']; } /** * @return array{status: int, pesan: string, data?: mixed} */ public function dilapanganList(?int $cabangKantorId = null): array { $b = $this->db->table('dilapangan d') ->select('d.*, p.nama_lengkap, p.nip') ->join('pegawai p', 'p.id_pegawai = d.pegawai', 'left'); $this->applyCabangPegawaiAlias($b, 'p', $cabangKantorId); $rows = $b->orderBy('d.id_dilapangan', 'DESC') ->get() ->getResultArray(); return ['status' => 1, 'pesan' => 'OK', 'data' => ['rows' => $rows]]; } /** * @param array $input * * @return array{status: int, pesan: string, data?: mixed} */ public function dilapanganSave(array $input, ?int $id = null, ?int $cabangKantorId = null): array { $v = Services::validation(); $v->setRules([ 'pegawai' => 'required|integer', 'alasan' => 'required|max_length[255]', ]); if (! $v->run($input)) { return ['status' => 0, 'pesan' => implode(' ', $v->getErrors())]; } $pegawaiId = (int) $input['pegawai']; if (! $this->pegawaiIdAllowedCabang($pegawaiId, $cabangKantorId)) { return ['status' => 0, 'pesan' => 'Pegawai tidak termasuk cabang Anda.']; } if ($id !== null && $id > 0) { $ex = $this->db->table('dilapangan')->select('pegawai')->where('id_dilapangan', $id)->get()->getRowArray(); if ($ex === null) { return ['status' => 0, 'pesan' => 'Data tidak ditemukan.']; } if (! $this->pegawaiIdAllowedCabang((int) $ex['pegawai'], $cabangKantorId)) { return ['status' => 0, 'pesan' => 'Data tidak ditemukan.']; } } $row = [ 'pegawai' => $pegawaiId, 'alasan' => (string) $input['alasan'], ]; if ($id === null) { $this->db->table('dilapangan')->insert($row); return ['status' => 1, 'pesan' => 'Disimpan.', 'data' => ['id_dilapangan' => (int) $this->db->insertID()]]; } $this->db->table('dilapangan')->where('id_dilapangan', $id)->update($row); return ['status' => 1, 'pesan' => 'Diperbarui.']; } /** * @return array{status: int, pesan: string} */ public function dilapanganDelete(int $id, ?int $cabangKantorId = null): array { $ex = $this->db->table('dilapangan')->select('pegawai')->where('id_dilapangan', $id)->get()->getRowArray(); if ($ex === null) { return ['status' => 0, 'pesan' => 'Data tidak ditemukan.']; } if (! $this->pegawaiIdAllowedCabang((int) $ex['pegawai'], $cabangKantorId)) { return ['status' => 0, 'pesan' => 'Data tidak ditemukan.']; } $this->db->table('dilapangan')->where('id_dilapangan', $id)->delete(); return ['status' => 1, 'pesan' => 'Dihapus.']; } /** * @return array{status: int, pesan: string, data?: mixed} */ public function lemburList(?int $cabangKantorId = null): array { $b = $this->db->table('lembur l') ->select('l.*, p.nama_lengkap, p.nip') ->join('pegawai p', 'p.id_pegawai = l.pegawai', 'left'); $this->applyCabangPegawaiAlias($b, 'p', $cabangKantorId); $rows = $b->orderBy('l.tanggal_lembur', 'DESC') ->get() ->getResultArray(); return ['status' => 1, 'pesan' => 'OK', 'data' => ['rows' => $rows]]; } /** * @param array $input * * @return array{status: int, pesan: string, data?: mixed} */ public function lemburSave(array $input, ?int $id = null, ?int $cabangKantorId = null): array { $v = Services::validation(); $v->setRules([ 'tanggal_lembur' => 'required|valid_date', 'pegawai' => 'required|integer', 'masuk' => 'required|max_length[5]', 'beres' => 'required|max_length[5]', 'keterangan' => 'required|max_length[255]', ]); if (! $v->run($input)) { return ['status' => 0, 'pesan' => implode(' ', $v->getErrors())]; } $pegawaiId = (int) $input['pegawai']; if (! $this->pegawaiIdAllowedCabang($pegawaiId, $cabangKantorId)) { return ['status' => 0, 'pesan' => 'Pegawai tidak termasuk cabang Anda.']; } if ($id !== null && $id > 0) { $ex = $this->db->table('lembur')->select('pegawai')->where('id_lembur', $id)->get()->getRowArray(); if ($ex === null) { return ['status' => 0, 'pesan' => 'Data tidak ditemukan.']; } if (! $this->pegawaiIdAllowedCabang((int) $ex['pegawai'], $cabangKantorId)) { return ['status' => 0, 'pesan' => 'Data tidak ditemukan.']; } } $row = [ 'tanggal_lembur' => (string) $input['tanggal_lembur'], 'pegawai' => $pegawaiId, 'masuk' => (string) $input['masuk'], 'beres' => (string) $input['beres'], 'keterangan' => (string) $input['keterangan'], ]; if ($id === null) { $this->db->table('lembur')->insert($row); return ['status' => 1, 'pesan' => 'Disimpan.', 'data' => ['id_lembur' => (int) $this->db->insertID()]]; } $this->db->table('lembur')->where('id_lembur', $id)->update($row); return ['status' => 1, 'pesan' => 'Diperbarui.']; } /** * @return array{status: int, pesan: string} */ public function lemburDelete(int $id, ?int $cabangKantorId = null): array { $ex = $this->db->table('lembur')->select('pegawai')->where('id_lembur', $id)->get()->getRowArray(); if ($ex === null) { return ['status' => 0, 'pesan' => 'Data tidak ditemukan.']; } if (! $this->pegawaiIdAllowedCabang((int) $ex['pegawai'], $cabangKantorId)) { return ['status' => 0, 'pesan' => 'Data tidak ditemukan.']; } $this->db->table('lembur')->where('id_lembur', $id)->delete(); return ['status' => 1, 'pesan' => 'Dihapus.']; } /** * @return array{status: int, pesan: string, data?: mixed} */ public function liburList(): array { $rows = $this->db->table('libur')->orderBy('tanggal_libur', 'DESC')->get()->getResultArray(); return ['status' => 1, 'pesan' => 'OK', 'data' => ['rows' => $rows]]; } /** * @param array $input * * @return array{status: int, pesan: string, data?: mixed} */ public function liburSave(array $input, ?int $id = null): array { $v = Services::validation(); $v->setRules([ 'tanggal_libur' => 'required|valid_date', 'keterangan_libur' => 'required|max_length[255]', ]); if (! $v->run($input)) { return ['status' => 0, 'pesan' => implode(' ', $v->getErrors())]; } $row = [ 'tanggal_libur' => (string) $input['tanggal_libur'], 'keterangan_libur' => (string) $input['keterangan_libur'], ]; if ($id === null) { $this->db->table('libur')->insert($row); return ['status' => 1, 'pesan' => 'Disimpan.', 'data' => ['id_libur' => (int) $this->db->insertID()]]; } $this->db->table('libur')->where('id_libur', $id)->update($row); return ['status' => 1, 'pesan' => 'Diperbarui.']; } /** * @return array{status: int, pesan: string} */ public function liburDelete(int $id): array { $this->db->table('libur')->where('id_libur', $id)->delete(); return ['status' => 1, 'pesan' => 'Dihapus.']; } /** * @return array{status: int, pesan: string, data?: mixed} */ public function jadwalList(): array { $rows = $this->db->table('jadwal')->orderBy('nama_jadwal', 'ASC')->get()->getResultArray(); return ['status' => 1, 'pesan' => 'OK', 'data' => ['rows' => $rows]]; } /** * @param array $input * * @return array{status: int, pesan: string, data?: mixed} */ public function jadwalSave(array $input, ?int $id = null): array { $v = Services::validation(); $v->setRules([ 'nama_jadwal' => 'required|max_length[50]', 'toleransi_terlambat' => 'required|integer', 'toleransi_pulang_cepat' => 'required|integer', '1_in' => 'required|max_length[5]', '1_out' => 'required|max_length[5]', '2_in' => 'required|max_length[5]', '2_out' => 'required|max_length[5]', '3_in' => 'required|max_length[5]', '3_out' => 'required|max_length[5]', '4_in' => 'required|max_length[5]', '4_out' => 'required|max_length[5]', '5_in' => 'required|max_length[5]', '5_out' => 'required|max_length[5]', '6_in' => 'permit_empty|max_length[5]', '6_out' => 'permit_empty|max_length[5]', '7_in' => 'permit_empty|max_length[5]', '7_out' => 'permit_empty|max_length[5]', ]); if (! $v->run($input)) { return ['status' => 0, 'pesan' => implode(' ', $v->getErrors())]; } $row = [ 'nama_jadwal' => (string) $input['nama_jadwal'], 'toleransi_terlambat' => (int) $input['toleransi_terlambat'], 'toleransi_pulang_cepat' => (int) $input['toleransi_pulang_cepat'], '1_in' => (string) $input['1_in'], '1_out' => (string) $input['1_out'], '2_in' => (string) $input['2_in'], '2_out' => (string) $input['2_out'], '3_in' => (string) $input['3_in'], '3_out' => (string) $input['3_out'], '4_in' => (string) $input['4_in'], '4_out' => (string) $input['4_out'], '5_in' => (string) $input['5_in'], '5_out' => (string) $input['5_out'], '6_in' => (string) ($input['6_in'] ?? ''), '6_out' => (string) ($input['6_out'] ?? ''), '7_in' => (string) ($input['7_in'] ?? ''), '7_out' => (string) ($input['7_out'] ?? ''), ]; if ($id === null) { $this->db->table('jadwal')->insert($row); return ['status' => 1, 'pesan' => 'Disimpan.', 'data' => ['id_jadwal' => (int) $this->db->insertID()]]; } $this->db->table('jadwal')->where('id_jadwal', $id)->update($row); return ['status' => 1, 'pesan' => 'Diperbarui.']; } /** * @return array{status: int, pesan: string} */ public function jadwalDelete(int $id): array { $n = (int) $this->db->table('pegawai')->where('jadwal', $id)->countAllResults(); if ($n > 0) { return ['status' => 0, 'pesan' => 'Jadwal dipakai ' . $n . ' pegawai.']; } $this->db->table('jadwal')->where('id_jadwal', $id)->delete(); return ['status' => 1, 'pesan' => 'Dihapus.']; } /** * @return array{status: int, pesan: string, data?: mixed} */ public function aktifitasList(int $page, int $perPage, ?int $cabangKantorId = null): array { $perPage = max(5, min(100, $perPage)); $page = max(1, $page); $offset = ($page - 1) * $perPage; $countB = $this->db->table('aktifitas_harian a')->join('pegawai p', 'p.id_pegawai = a.pegawai', 'left'); $this->applyCabangPegawaiAlias($countB, 'p', $cabangKantorId); $total = (int) $countB->countAllResults(); $rowsB = $this->db->table('aktifitas_harian a') ->select('a.*, p.nama_lengkap, p.nip') ->join('pegawai p', 'p.id_pegawai = a.pegawai', 'left'); $this->applyCabangPegawaiAlias($rowsB, 'p', $cabangKantorId); $rows = $rowsB->orderBy('a.waktu_aktifitas', 'DESC') ->limit($perPage, $offset) ->get() ->getResultArray(); return [ 'status' => 1, 'pesan' => 'OK', 'data' => [ 'rows' => $rows, 'total' => $total, 'page' => $page, 'per_page' => $perPage, 'total_page' => (int) ceil($total / $perPage), ], ]; } /** * @return array{status: int, pesan: string} */ public function aktifitasDelete(int $id, ?int $cabangKantorId = null): array { $ex = $this->db->table('aktifitas_harian')->select('pegawai')->where('id_aktifitas_harian', $id)->get()->getRowArray(); if ($ex === null) { return ['status' => 0, 'pesan' => 'Data tidak ditemukan.']; } if (! $this->pegawaiIdAllowedCabang((int) $ex['pegawai'], $cabangKantorId)) { return ['status' => 0, 'pesan' => 'Data tidak ditemukan.']; } $this->db->table('aktifitas_harian')->where('id_aktifitas_harian', $id)->delete(); return ['status' => 1, 'pesan' => 'Dihapus.']; } /** * @return array{status: int, pesan: string, data?: mixed} */ public function laporanCutiRentang(string $dari, string $sampai, ?int $cabangKantorId = null): array { $b = $this->db->table('cuti c') ->select('c.*, p.nama_lengkap, p.nip') ->join('pegawai p', 'p.id_pegawai = c.pegawai', 'left') ->where('c.tanggal_cuti >=', $dari) ->where('c.tanggal_cuti <=', $sampai); $this->applyCabangPegawaiAlias($b, 'p', $cabangKantorId); $rows = $b->orderBy('c.tanggal_cuti', 'DESC') ->get() ->getResultArray(); return ['status' => 1, 'pesan' => 'OK', 'data' => ['rows' => $rows, 'dari' => $dari, 'sampai' => $sampai]]; } /** * @return array{status: int, pesan: string, data?: mixed} */ public function adminUsersList(): array { if (! $this->db->tableExists('admin_users')) { return ['status' => 1, 'pesan' => 'OK', 'data' => ['rows' => []]]; } $users = $this->db->table('admin_users')->orderBy('id', 'ASC')->get()->getResultArray(); $hasPegawaiCol = $this->db->fieldExists('id_pegawai', 'admin_users'); foreach ($users as &$u) { unset($u['password'], $u['remember_code'], $u['activation_code'], $u['forgotten_password_code']); $u['groups'] = $this->adminUserGroupNames((int) $u['id']); $u['pegawai_proxy'] = null; if ($hasPegawaiCol && $this->db->tableExists('pegawai')) { $pid = (int) ($u['id_pegawai'] ?? 0); if ($pid > 0) { $p = $this->db->table('pegawai') ->select('nip, nama_lengkap') ->where('id_pegawai', $pid) ->get() ->getRowArray(); if ($p !== null) { $u['pegawai_proxy'] = trim((string) ($p['nama_lengkap'] ?? '')) . ' (NIP ' . (string) ($p['nip'] ?? '') . ')'; } } } } return ['status' => 1, 'pesan' => 'OK', 'data' => ['rows' => $users]]; } /** * @return list */ public function adminUserGroupNames(int $userId): array { if (! $this->db->tableExists('admin_users_groups') || ! $this->db->tableExists('admin_groups')) { return []; } $q = $this->db->table('admin_users_groups ug') ->select('g.name') ->join('admin_groups g', 'g.id = ug.group_id', 'inner') ->where('ug.user_id', $userId) ->get() ->getResultArray(); return array_values(array_filter(array_map(static fn ($r) => (string) ($r['name'] ?? ''), $q))); } /** * @return array{status: int, pesan: string, data?: mixed} */ public function adminGroupsList(): array { if (! $this->db->tableExists('admin_groups')) { return ['status' => 1, 'pesan' => 'OK', 'data' => ['rows' => []]]; } $rows = $this->db->table('admin_groups')->orderBy('id', 'ASC')->get()->getResultArray(); if ($this->db->tableExists('admin_users_groups')) { foreach ($rows as &$r) { $r['user_count'] = (int) $this->db->table('admin_users_groups') ->where('group_id', (int) ($r['id'] ?? 0)) ->countAllResults(); } } else { foreach ($rows as &$r) { $r['user_count'] = 0; } } unset($r); return ['status' => 1, 'pesan' => 'OK', 'data' => ['rows' => $rows]]; } /** * @param array $input * * @return array{status: int, pesan: string, data?: mixed} */ public function adminGroupCreate(array $input): array { if (! $this->db->tableExists('admin_groups')) { return ['status' => 0, 'pesan' => 'Tabel admin_groups tidak ada.']; } $v = Services::validation(); $v->setRules([ 'name' => 'required|max_length[20]|regex_match[/^[a-zA-Z0-9_]+$/]', 'description' => 'required|max_length[100]', ]); if (! $v->run($input)) { return ['status' => 0, 'pesan' => implode(' ', $v->getErrors())]; } $name = strtolower(trim((string) $input['name'])); if ($name === 'webmaster') { return ['status' => 0, 'pesan' => 'Nama grup webmaster sudah dipakai sistem.']; } $exists = $this->db->table('admin_groups')->where('name', $name)->countAllResults(); if ($exists > 0) { return ['status' => 0, 'pesan' => 'Nama grup sudah dipakai.']; } $this->db->table('admin_groups')->insert([ 'name' => $name, 'description' => trim((string) $input['description']), ]); return ['status' => 1, 'pesan' => 'Grup dibuat.', 'data' => ['id' => (int) $this->db->insertID()]]; } /** * @param array $input * * @return array{status: int, pesan: string} */ public function adminGroupUpdate(int $groupId, array $input): array { if (! $this->db->tableExists('admin_groups')) { return ['status' => 0, 'pesan' => 'Tabel admin_groups tidak ada.']; } $row = $this->db->table('admin_groups')->where('id', $groupId)->get()->getRowArray(); if ($row === null) { return ['status' => 0, 'pesan' => 'Grup tidak ditemukan.']; } $v = Services::validation(); $v->setRules([ 'name' => "required|max_length[20]|regex_match[/^[a-zA-Z0-9_]+$/]|is_unique[admin_groups.name,id,{$groupId}]", 'description' => 'required|max_length[100]', ]); if (! $v->run($input)) { return ['status' => 0, 'pesan' => implode(' ', $v->getErrors())]; } $name = strtolower(trim((string) $input['name'])); if (strtolower((string) $row['name']) === 'webmaster' && $name !== 'webmaster') { return ['status' => 0, 'pesan' => 'Grup webmaster tidak boleh diubah namanya.']; } if ($name === 'webmaster' && strtolower((string) $row['name']) !== 'webmaster') { return ['status' => 0, 'pesan' => 'Tidak boleh mengubah nama grup menjadi webmaster.']; } $this->db->table('admin_groups')->where('id', $groupId)->update([ 'name' => $name, 'description' => trim((string) $input['description']), ]); return ['status' => 1, 'pesan' => 'Grup diperbarui.']; } /** * @return array{status: int, pesan: string} */ public function adminGroupDelete(int $groupId): array { if (! $this->db->tableExists('admin_groups')) { return ['status' => 0, 'pesan' => 'Tabel admin_groups tidak ada.']; } $row = $this->db->table('admin_groups')->where('id', $groupId)->get()->getRowArray(); if ($row === null) { return ['status' => 0, 'pesan' => 'Grup tidak ditemukan.']; } if (strtolower((string) $row['name']) === 'webmaster') { return ['status' => 0, 'pesan' => 'Grup webmaster tidak boleh dihapus.']; } if ($this->db->tableExists('admin_users_groups')) { $n = (int) $this->db->table('admin_users_groups')->where('group_id', $groupId)->countAllResults(); if ($n > 0) { return ['status' => 0, 'pesan' => 'Grup masih dipakai ' . $n . ' pengguna. Pindahkan pengguna dulu.']; } } $this->db->table('admin_groups')->where('id', $groupId)->delete(); return ['status' => 1, 'pesan' => 'Grup dihapus.']; } /** * @param array $input * * @return array{status: int, pesan: string, data?: mixed} */ public function adminUserCreate(array $input): array { if (! $this->db->tableExists('admin_users')) { return ['status' => 0, 'pesan' => 'Tabel admin_users tidak ada.']; } $hasPegawaiCol = $this->db->fieldExists('id_pegawai', 'admin_users'); $rules = [ 'username' => 'required|max_length[100]|is_unique[admin_users.username]', 'email' => 'permit_empty|max_length[100]', 'password' => 'required|min_length[6]', 'nama_lengkap' => 'required|max_length[100]', 'no_telepon' => 'permit_empty|max_length[25]', 'group_id' => 'required|integer', ]; if ($hasPegawaiCol) { $rules['id_pegawai'] = 'permit_empty|integer'; } $v = Services::validation(); $v->setRules($rules); if (! $v->run($input)) { return ['status' => 0, 'pesan' => implode(' ', $v->getErrors())]; } $gid = (int) $input['group_id']; $g = $this->db->table('admin_groups')->where('id', $gid)->get()->getRowArray(); if ($g === null) { return ['status' => 0, 'pesan' => 'Grup tidak valid.']; } if (strtolower((string) $g['name']) === 'webmaster') { return ['status' => 0, 'pesan' => 'Tidak boleh membuat akun webmaster dari sini.']; } $idPegawaiInsert = null; if ($hasPegawaiCol && $this->db->tableExists('pegawai')) { $pid = (int) ($input['id_pegawai'] ?? 0); if ($pid > 0) { $okP = $this->db->table('pegawai')->where('id_pegawai', $pid)->countAllResults() > 0; if (! $okP) { return ['status' => 0, 'pesan' => 'Pegawai (proxy API) tidak ditemukan.']; } $idPegawaiInsert = $pid; } } $hash = password_hash((string) $input['password'], PASSWORD_BCRYPT); $rowInsert = [ 'ip_address' => $this->db->escapeString(service('request')->getIPAddress()), 'username' => (string) $input['username'], 'password' => $hash, 'email' => (string) ($input['email'] ?? ''), 'created_on' => time(), 'active' => 1, 'first_name' => '', 'last_name' => '', 'photo' => '', 'nama_lengkap' => (string) $input['nama_lengkap'], 'no_telepon' => (string) ($input['no_telepon'] ?? ''), ]; if ($hasPegawaiCol) { $rowInsert['id_pegawai'] = $idPegawaiInsert; } $this->db->table('admin_users')->insert($rowInsert); $uid = (int) $this->db->insertID(); if ($this->db->tableExists('admin_users_groups')) { $this->db->table('admin_users_groups')->insert(['user_id' => $uid, 'group_id' => $gid]); } return ['status' => 1, 'pesan' => 'Pengguna dibuat.', 'data' => ['id' => $uid]]; } /** * Satu pengguna untuk form edit (tanpa password). * * @return array{status: int, pesan: string, data?: mixed} */ public function adminUserShow(int $userId): array { if (! $this->db->tableExists('admin_users')) { return ['status' => 0, 'pesan' => 'Tabel admin_users tidak ada.']; } $row = $this->db->table('admin_users')->where('id', $userId)->get()->getRowArray(); if ($row === null) { return ['status' => 0, 'pesan' => 'Pengguna tidak ditemukan.']; } unset($row['password'], $row['remember_code'], $row['activation_code'], $row['forgotten_password_code']); $row['groups'] = $this->adminUserGroupNames($userId); $row['group_id'] = null; if ($this->db->tableExists('admin_users_groups')) { $ug = $this->db->table('admin_users_groups') ->where('user_id', $userId) ->orderBy('group_id', 'ASC') ->get() ->getRowArray(); if ($ug !== null) { $row['group_id'] = (int) $ug['group_id']; } } return ['status' => 1, 'pesan' => 'OK', 'data' => $row]; } /** * @param array $input * * @return array{status: int, pesan: string} */ public function adminUserUpdate(int $userId, array $input): array { if (! $this->db->tableExists('admin_users')) { return ['status' => 0, 'pesan' => 'Tabel admin_users tidak ada.']; } $existing = $this->db->table('admin_users')->where('id', $userId)->get()->getRowArray(); if ($existing === null) { return ['status' => 0, 'pesan' => 'Pengguna tidak ditemukan.']; } $hasPegawaiCol = $this->db->fieldExists('id_pegawai', 'admin_users'); $rules = [ 'username' => "required|max_length[100]|is_unique[admin_users.username,id,{$userId}]", 'email' => 'permit_empty|max_length[100]', 'nama_lengkap' => 'required|max_length[100]', 'no_telepon' => 'permit_empty|max_length[25]', 'group_id' => 'required|integer', 'active' => 'required|in_list[0,1]', ]; if ($hasPegawaiCol) { $rules['id_pegawai'] = 'permit_empty|integer'; } $v = Services::validation(); $v->setRules($rules); if (! $v->run($input)) { return ['status' => 0, 'pesan' => implode(' ', $v->getErrors())]; } $gidNew = (int) $input['group_id']; $gNew = $this->db->table('admin_groups')->where('id', $gidNew)->get()->getRowArray(); if ($gNew === null) { return ['status' => 0, 'pesan' => 'Grup tidak valid.']; } $currentNames = array_map('strtolower', $this->adminUserGroupNames($userId)); $isWebmaster = in_array('webmaster', $currentNames, true); $newName = strtolower((string) $gNew['name']); if ($newName === 'webmaster' && ! $isWebmaster) { return ['status' => 0, 'pesan' => 'Tidak boleh mengangkat pengguna menjadi webmaster dari sini.']; } if ($isWebmaster && $newName !== 'webmaster') { return ['status' => 0, 'pesan' => 'Tidak boleh mengubah grup akun webmaster.']; } $idPegawaiVal = null; if ($hasPegawaiCol && $this->db->tableExists('pegawai')) { $pid = (int) ($input['id_pegawai'] ?? 0); if ($pid > 0) { $okP = $this->db->table('pegawai')->where('id_pegawai', $pid)->countAllResults() > 0; if (! $okP) { return ['status' => 0, 'pesan' => 'Pegawai (proxy API) tidak ditemukan.']; } $idPegawaiVal = $pid; } } $update = [ 'username' => (string) $input['username'], 'email' => (string) ($input['email'] ?? ''), 'nama_lengkap' => (string) $input['nama_lengkap'], 'no_telepon' => (string) ($input['no_telepon'] ?? ''), 'active' => (int) $input['active'] === 1 ? 1 : 0, ]; if ($hasPegawaiCol) { $update['id_pegawai'] = $idPegawaiVal; } $this->db->table('admin_users')->where('id', $userId)->update($update); if ($this->db->tableExists('admin_users_groups')) { $this->db->table('admin_users_groups')->where('user_id', $userId)->delete(); $this->db->table('admin_users_groups')->insert(['user_id' => $userId, 'group_id' => $gidNew]); } return ['status' => 1, 'pesan' => 'Pengguna diperbarui.']; } /** * @param array $input * * @return array{status: int, pesan: string} */ public function adminUserResetPassword(int $userId, array $input): array { $v = Services::validation(); $v->setRules(['password' => 'required|min_length[6]']); if (! $v->run($input)) { return ['status' => 0, 'pesan' => implode(' ', $v->getErrors())]; } $exists = $this->db->table('admin_users')->where('id', $userId)->get()->getRowArray(); if ($exists === null) { return ['status' => 0, 'pesan' => 'Pengguna tidak ditemukan.']; } $hash = password_hash((string) $input['password'], PASSWORD_BCRYPT); $this->db->table('admin_users')->where('id', $userId)->update(['password' => $hash]); return ['status' => 1, 'pesan' => 'Password diperbarui.']; } /** * @return array{status: int, pesan: string, data?: mixed} */ public function backupListFiles(): array { $dir = WRITEPATH . 'admin_db_backup'; if (! is_dir($dir)) { @mkdir($dir, 0755, true); } $files = glob($dir . DIRECTORY_SEPARATOR . '*.sql') ?: []; rsort($files); $out = []; foreach ($files as $f) { $out[] = [ 'name' => basename($f), 'size' => filesize($f) ?: 0, 'mtime'=> date('Y-m-d H:i:s', (int) filemtime($f)), ]; } return ['status' => 1, 'pesan' => 'OK', 'data' => ['directory' => $dir, 'files' => $out]]; } /** * @return array{status: int, pesan: string, data?: mixed} */ public function backupRun(bool $alsoLatest): array { $dir = WRITEPATH . 'admin_db_backup'; if (! is_dir($dir)) { @mkdir($dir, 0755, true); } try { $util = \Config\Database::utils(); $backup = $util->backup(['format' => 'sql']); } catch (\Throwable $e) { return ['status' => 0, 'pesan' => 'Backup gagal: ' . $e->getMessage()]; } $name = date('Y-m-d_H-i-s') . '.sql'; $path = $dir . DIRECTORY_SEPARATOR . $name; if (file_put_contents($path, $backup) === false) { return ['status' => 0, 'pesan' => 'Gagal menulis file backup.']; } if ($alsoLatest) { file_put_contents($dir . DIRECTORY_SEPARATOR . 'latest.sql', $backup); } return ['status' => 1, 'pesan' => 'Backup dibuat.', 'data' => ['file' => $name]]; } /** * @return array{status: int, pesan: string} */ public function backupDelete(string $filename): array { if (! preg_match('/^[a-zA-Z0-9._-]+\\.sql$/', $filename)) { return ['status' => 0, 'pesan' => 'Nama file tidak valid.']; } $path = WRITEPATH . 'admin_db_backup' . DIRECTORY_SEPARATOR . $filename; if (! is_file($path)) { return ['status' => 0, 'pesan' => 'File tidak ada.']; } @unlink($path); return ['status' => 1, 'pesan' => 'File dihapus.']; } public function backupFilePath(string $filename): ?string { if (! preg_match('/^[a-zA-Z0-9._-]+\\.sql$/', $filename)) { return null; } $path = WRITEPATH . 'admin_db_backup' . DIRECTORY_SEPARATOR . $filename; return is_file($path) ? $path : null; } private function applyCabangPegawaiAlias(BaseBuilder $b, string $alias, ?int $cabangKantorId): void { if ($cabangKantorId !== null && $cabangKantorId > 0) { $b->where("{$alias}.kantor", $cabangKantorId); } } private function pegawaiIdAllowedCabang(int $pegawaiId, ?int $cabangKantorId): bool { if ($cabangKantorId === null || $cabangKantorId <= 0) { return true; } return $this->db->table('pegawai')->where('id_pegawai', $pegawaiId)->where('kantor', $cabangKantorId)->countAllResults() > 0; } }