PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ] ); } catch (PDOException $e) { http_response_code(500); echo json_encode(['ok' => false, 'error' => 'Koneksi DB gagal: ' . $e->getMessage()]); exit; } // DEBUG SEMENTARA - hapus setelah selesai if ($action === 'debug') { echo json_encode([ 'ok' => true, 'host' => $db_host, 'port' => $db_port, 'name' => $db_name, 'user' => $db_user, ]); exit; } $body = json_decode(file_get_contents('php://input'), true) ?? []; $action = $body['action'] ?? ($_GET['action'] ?? ''); function pt(float $lng, float $lat): string { return "POINT($lng $lat)"; } try { switch ($action) { // ── AUTH: REGISTER (Pengguna only) ────────────────────────────── case 'register': $nama = trim($body['nama'] ?? ''); $email = trim($body['email'] ?? ''); $pass = $body['password'] ?? ''; if (!$nama || !$email || strlen($pass) < 8) { echo json_encode(['ok' => false, 'error' => 'Data tidak lengkap.']); break; } if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { echo json_encode(['ok' => false, 'error' => 'Format email tidak valid.']); break; } // Check duplicate $chk = $pdo->prepare("SELECT id FROM users WHERE email = :e LIMIT 1"); $chk->execute(['e' => $email]); if ($chk->fetch()) { echo json_encode(['ok' => false, 'error' => 'Email sudah terdaftar.']); break; } $id = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0,0xffff), mt_rand(0,0xffff), mt_rand(0,0xffff), mt_rand(0,0x0fff)|0x4000, mt_rand(0,0x3fff)|0x8000, mt_rand(0,0xffff), mt_rand(0,0xffff), mt_rand(0,0xffff)); $hash = password_hash($pass, PASSWORD_BCRYPT); $st = $pdo->prepare( "INSERT INTO users (id, nama, email, password_hash, role) VALUES (:id, :nama, :email, :hash, 'pengguna')" ); $st->execute(['id' => $id, 'nama' => $nama, 'email' => $email, 'hash' => $hash]); echo json_encode(['ok' => true]); break; // ── AUTH: LOGIN ───────────────────────────────────────────────── case 'login': $email = trim($body['email'] ?? ''); $pass = $body['password'] ?? ''; $role = $body['role'] ?? 'pengguna'; // 'pengguna' or 'pengurus' if (!$email || !$pass) { echo json_encode(['ok' => false, 'error' => 'Email dan kata sandi wajib diisi.']); break; } $st = $pdo->prepare("SELECT id, nama, email, password_hash, role FROM users WHERE email = :e LIMIT 1"); $st->execute(['e' => $email]); $user = $st->fetch(); if (!$user || !password_verify($pass, $user['password_hash'])) { echo json_encode(['ok' => false, 'error' => 'Email atau kata sandi salah.']); break; } // Role mismatch guard if ($user['role'] !== $role) { if ($role === 'pengurus') { echo json_encode(['ok' => false, 'error' => 'Akun ini bukan akun Pengurus.']); break; } else { echo json_encode(['ok' => false, 'error' => 'Akun Pengurus tidak bisa masuk sebagai Pengguna.']); break; } } echo json_encode([ 'ok' => true, 'user' => ['id' => $user['id'], 'nama' => $user['nama'], 'role' => $user['role']], ]); break; // ── LOAD SEMUA DATA ────────────────────────────────────────────── case 'load': $ri = $pdo->query( "SELECT id, nama, jenis, kontak, alamat, ST_Y(geom) AS lat, ST_X(geom) AS lng, jangkauan_m FROM rumah_ibadah ORDER BY dibuat_pada ASC" )->fetchAll(); $rm = $pdo->query( "SELECT id, nama_kk, kontak, alamat, ST_Y(geom) AS lat, ST_X(geom) AS lng, ri_id, jarak_ke_ri_m FROM rumah_miskin ORDER BY dibuat_pada ASC" )->fetchAll(); echo json_encode(['ok' => true, 'ri' => $ri, 'rm' => $rm]); break; case 'add_ri': $st = $pdo->prepare( "INSERT INTO rumah_ibadah (id, nama, jenis, kontak, alamat, geom, jangkauan_m) VALUES (:id,:nama,:jenis,:kontak,:alamat,ST_GeomFromText(:geom),:jangkauan)" ); $st->execute([ 'id' => $body['id'], 'nama' => $body['nama'], 'jenis' => $body['jenis'], 'kontak' => $body['kontak'] ?? '-', 'alamat' => $body['alamat'] ?? '', 'geom' => pt((float)$body['lng'], (float)$body['lat']), 'jangkauan' => (int)($body['jangkauan_m'] ?? 500), ]); echo json_encode(['ok' => true]); break; case 'add_rm': $st = $pdo->prepare( "INSERT INTO rumah_miskin (id, nama_kk, kontak, alamat, geom, ri_id, jarak_ke_ri_m) VALUES (:id,:nama,:kontak,:alamat,ST_GeomFromText(:geom),:ri_id,:jarak)" ); $st->execute([ 'id' => $body['id'], 'nama' => $body['nama_kk'], 'kontak' => $body['kontak'] ?? '-', 'alamat' => $body['alamat'] ?? '', 'geom' => pt((float)$body['lng'], (float)$body['lat']), 'ri_id' => $body['ri_id'] ?: null, 'jarak' => isset($body['jarak_ke_ri_m']) ? (float)$body['jarak_ke_ri_m'] : null, ]); echo json_encode(['ok' => true]); break; case 'update_ri': $st = $pdo->prepare("UPDATE rumah_ibadah SET nama=:nama,jenis=:jenis,kontak=:kontak WHERE id=:id"); $st->execute(['nama'=>$body['nama'],'jenis'=>$body['jenis'],'kontak'=>$body['kontak'],'id'=>$body['id']]); echo json_encode(['ok' => true]); break; case 'update_ri_range': $pdo->prepare("UPDATE rumah_ibadah SET jangkauan_m=:j WHERE id=:id") ->execute(['j'=>(int)$body['jangkauan_m'],'id'=>$body['id']]); echo json_encode(['ok' => true]); break; case 'update_ri_pos': $pdo->prepare("UPDATE rumah_ibadah SET geom=ST_GeomFromText(:geom),alamat=:alamat WHERE id=:id") ->execute(['geom'=>pt((float)$body['lng'],(float)$body['lat']),'alamat'=>$body['alamat']??'','id'=>$body['id']]); echo json_encode(['ok' => true]); break; case 'update_rm': $pdo->prepare("UPDATE rumah_miskin SET nama_kk=:nama,kontak=:kontak WHERE id=:id") ->execute(['nama'=>$body['nama_kk'],'kontak'=>$body['kontak'],'id'=>$body['id']]); echo json_encode(['ok' => true]); break; case 'update_rm_pos': $pdo->prepare("UPDATE rumah_miskin SET geom=ST_GeomFromText(:geom),alamat=:alamat WHERE id=:id") ->execute(['geom'=>pt((float)$body['lng'],(float)$body['lat']),'alamat'=>$body['alamat']??'','id'=>$body['id']]); echo json_encode(['ok' => true]); break; case 'update_rm_assignment': $old = $pdo->prepare("SELECT ri_id FROM rumah_miskin WHERE id=:id"); $old->execute(['id' => $body['rm_id']]); $row = $old->fetch(); $oldRI = $row ? $row['ri_id'] : null; $newRI = $body['ri_id'] ?: null; $pdo->prepare("UPDATE rumah_miskin SET ri_id=:ri_id,jarak_ke_ri_m=:jarak WHERE id=:id") ->execute(['ri_id'=>$newRI,'jarak'=>isset($body['jarak_ke_ri_m'])?(float)$body['jarak_ke_ri_m']:null,'id'=>$body['rm_id']]); if ($oldRI !== $newRI) { $pdo->prepare("INSERT INTO riwayat_binaan (rm_id,ri_id_lama,ri_id_baru,alasan) VALUES (:rm,:lama,:baru,:alasan)") ->execute(['rm'=>$body['rm_id'],'lama'=>$oldRI,'baru'=>$newRI,'alasan'=>$body['alasan']??'otomatis']); } echo json_encode(['ok' => true]); break; case 'delete_ri': $pdo->prepare("DELETE FROM rumah_ibadah WHERE id=:id")->execute(['id'=>$body['id']]); echo json_encode(['ok' => true]); break; case 'delete_rm': $pdo->prepare("DELETE FROM rumah_miskin WHERE id=:id")->execute(['id'=>$body['id']]); echo json_encode(['ok' => true]); break; // ── BANTUAN TYPES ──────────────────────────────────────────────── case 'load_bantuan_types': $rows = $pdo->query("SELECT id,nama,kategori,deskripsi FROM jenis_bantuan ORDER BY dibuat_pada ASC")->fetchAll(); echo json_encode(['ok' => true, 'data' => $rows]); break; case 'add_bantuan_type': $id = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0,0xffff),mt_rand(0,0xffff),mt_rand(0,0xffff), mt_rand(0,0x0fff)|0x4000,mt_rand(0,0x3fff)|0x8000, mt_rand(0,0xffff),mt_rand(0,0xffff),mt_rand(0,0xffff)); $pdo->prepare("INSERT INTO jenis_bantuan (id,nama,kategori,deskripsi) VALUES (:id,:nama,:kategori,:deskripsi)") ->execute(['id'=>$body['id']??$id,'nama'=>$body['nama'],'kategori'=>$body['kategori']??'Lainnya','deskripsi'=>$body['deskripsi']??null]); echo json_encode(['ok' => true]); break; case 'delete_bantuan_type': $pdo->prepare("DELETE FROM jenis_bantuan WHERE id=:id")->execute(['id'=>$body['id']]); echo json_encode(['ok' => true]); break; case 'load_riwayat_bantuan': $st = $pdo->prepare( "SELECT rb.id, rb.tanggal, rb.catatan, jb.nama AS bantuan_nama, jb.kategori, u.nama AS dikonfirmasi_oleh FROM riwayat_bantuan rb JOIN jenis_bantuan jb ON jb.id = rb.bantuan_id LEFT JOIN users u ON u.id = rb.user_id WHERE rb.rm_id = :rm_id ORDER BY rb.tanggal DESC, rb.dibuat_pada DESC" ); $st->execute(['rm_id' => $body['rm_id']]); echo json_encode(['ok' => true, 'data' => $st->fetchAll()]); break; case 'add_riwayat_bantuan': $id = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0,0xffff),mt_rand(0,0xffff),mt_rand(0,0xffff), mt_rand(0,0x0fff)|0x4000,mt_rand(0,0x3fff)|0x8000, mt_rand(0,0xffff),mt_rand(0,0xffff),mt_rand(0,0xffff)); $pdo->prepare( "INSERT INTO riwayat_bantuan (id,rm_id,bantuan_id,tanggal,catatan,user_id) VALUES (:id,:rm_id,:bantuan_id,:tanggal,:catatan,:user_id)" )->execute([ 'id' => $body['id'] ?? $id, 'rm_id' => $body['rm_id'], 'bantuan_id' => $body['bantuan_id'], 'tanggal' => $body['tanggal'], 'catatan' => $body['catatan'] ?? null, 'user_id' => $body['user_id'] ?? null, ]); echo json_encode(['ok' => true]); break; default: http_response_code(400); echo json_encode(['ok' => false, 'error' => "Action tidak dikenal: $action"]); } } catch (PDOException $e) { http_response_code(500); echo json_encode(['ok' => false, 'error' => $e->getMessage()]); }