Upload files to "api"

This commit is contained in:
2026-06-02 03:13:49 +00:00
parent 9763625d13
commit d45bcee067
5 changed files with 511 additions and 0 deletions
+44
View File
@@ -0,0 +1,44 @@
<?php
require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../config/auth.php';
header('Content-Type: application/json; charset=utf-8');
function json_response(array $payload, int $status = 200): void
{
http_response_code($status);
echo json_encode($payload, JSON_UNESCAPED_UNICODE);
exit;
}
function get_json_input(): array
{
$raw = file_get_contents('php://input');
if (!$raw) return [];
$data = json_decode($raw, true);
return is_array($data) ? $data : [];
}
function required_fields(array $data, array $fields): void
{
foreach ($fields as $field) {
if (!isset($data[$field]) || $data[$field] === '') {
json_response(['success' => false, 'message' => "Field {$field} wajib diisi."], 422);
}
}
}
function clean_string($value): string
{
return trim((string)($value ?? ''));
}
function clean_float($value): float
{
return (float)($value ?? 0);
}
function clean_int($value): int
{
return (int)($value ?? 0);
}
+102
View File
@@ -0,0 +1,102 @@
<?php
require_once __DIR__ . '/_helpers.php';
api_require_login();
api_require_role(['admin','dinas']);
function haversine_meter(float $lat1, float $lng1, float $lat2, float $lng2): float
{
$earth = 6371000;
$dLat = deg2rad($lat2 - $lat1);
$dLng = deg2rad($lng2 - $lng1);
$a = sin($dLat / 2) * sin($dLat / 2) +
cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
sin($dLng / 2) * sin($dLng / 2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
return $earth * $c;
}
$pdo->beginTransaction();
try {
$rumahStmt = $pdo->query('SELECT * FROM rumah_ibadah WHERE status = "Aktif" ORDER BY nama ASC');
$rumahIbadah = $rumahStmt->fetchAll();
$kelStmt = $pdo->query('SELECT * FROM keluarga ORDER BY FIELD(kerentanan, "Miskin Ekstrem", "Sangat Miskin", "Miskin", "Rentan Miskin"), created_at ASC');
$keluarga = $kelStmt->fetchAll();
$terpakai = [];
foreach ($rumahIbadah as $ri) {
$terpakai[(int)$ri['id']] = 0;
}
$update = $pdo->prepare('UPDATE keluarga SET status_bantuan = ?, rumah_ibadah_id = ? WHERE id = ?');
$jumlahDitanggung = 0;
$jumlahBlankSpot = 0;
$jumlahMenunggu = 0;
$jumlahTidakValid = 0;
foreach ($keluarga as $kel) {
$kelId = (int)$kel['id'];
if ($kel['status_verifikasi'] === 'Tidak Valid') {
$update->execute(['Tidak Valid', null, $kelId]);
$jumlahTidakValid++;
continue;
}
if ($kel['status_verifikasi'] !== 'Valid') {
$update->execute(['Menunggu Verifikasi', null, $kelId]);
$jumlahMenunggu++;
continue;
}
$kandidat = [];
foreach ($rumahIbadah as $ri) {
$riId = (int)$ri['id'];
$kuota = (int)$ri['kuota'];
$radius = (int)$ri['radius'];
if ($kuota <= 0 || ($terpakai[$riId] ?? 0) >= $kuota) {
continue;
}
$jarak = haversine_meter((float)$kel['lat'], (float)$kel['lng'], (float)$ri['lat'], (float)$ri['lng']);
if ($jarak <= $radius) {
$kandidat[] = [
'id' => $riId,
'jarak' => $jarak,
'sisa_kuota' => $kuota - ($terpakai[$riId] ?? 0),
];
}
}
if (!empty($kandidat)) {
usort($kandidat, function ($a, $b) {
if ($a['jarak'] == $b['jarak']) return $b['sisa_kuota'] <=> $a['sisa_kuota'];
return $a['jarak'] <=> $b['jarak'];
});
$riId = $kandidat[0]['id'];
$terpakai[$riId]++;
$update->execute(['Ditanggung', $riId, $kelId]);
$jumlahDitanggung++;
} else {
$update->execute(['Blank Spot', null, $kelId]);
$jumlahBlankSpot++;
}
}
$pdo->commit();
json_response([
'success' => true,
'message' => 'Analisis tanggungan selesai.',
'summary' => [
'ditanggung' => $jumlahDitanggung,
'blank_spot' => $jumlahBlankSpot,
'menunggu_verifikasi' => $jumlahMenunggu,
'tidak_valid' => $jumlahTidakValid,
]
]);
} catch (Throwable $e) {
$pdo->rollBack();
json_response(['success' => false, 'message' => 'Analisis gagal: ' . $e->getMessage()], 500);
}
+71
View File
@@ -0,0 +1,71 @@
<?php
require_once __DIR__ . '/_helpers.php';
api_require_login();
api_require_role(['admin','dinas','rumah_ibadah','relawan']);
$method = $_SERVER['REQUEST_METHOD'];
$user = current_user();
$role = current_role();
if ($method === 'GET') {
$keluargaId = clean_int($_GET['keluarga_id'] ?? 0);
$params = [];
$where = [];
if ($keluargaId > 0) {
$where[] = 'rb.keluarga_id = ?';
$params[] = $keluargaId;
}
if ($role === 'rumah_ibadah' && !empty($user['rumah_ibadah_id'])) {
$where[] = 'rb.rumah_ibadah_id = ?';
$params[] = (int)$user['rumah_ibadah_id'];
}
$sql = 'SELECT rb.*, k.nama_kk, r.nama AS nama_rumah_ibadah
FROM riwayat_bantuan rb
JOIN keluarga k ON k.id = rb.keluarga_id
LEFT JOIN rumah_ibadah r ON r.id = rb.rumah_ibadah_id';
if ($where) $sql .= ' WHERE ' . implode(' AND ', $where);
$sql .= ' ORDER BY rb.tanggal_bantuan DESC, rb.created_at DESC';
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
json_response(['success' => true, 'data' => $stmt->fetchAll()]);
}
if ($method === 'POST') {
$data = get_json_input();
required_fields($data, ['keluarga_id','tanggal_bantuan','jenis_bantuan']);
$keluargaId = clean_int($data['keluarga_id']);
$stmtKel = $pdo->prepare('SELECT rumah_ibadah_id, status_bantuan FROM keluarga WHERE id = ?');
$stmtKel->execute([$keluargaId]);
$kel = $stmtKel->fetch();
if (!$kel) json_response(['success' => false, 'message' => 'Data keluarga tidak ditemukan.'], 404);
if ($kel['status_bantuan'] !== 'Ditanggung') {
json_response(['success' => false, 'message' => 'Bantuan hanya dapat dicatat untuk keluarga berstatus Ditanggung.'], 422);
}
$rumahIbadahId = $kel['rumah_ibadah_id'] ? (int)$kel['rumah_ibadah_id'] : null;
if ($role === 'rumah_ibadah' && $user['rumah_ibadah_id'] && $rumahIbadahId !== (int)$user['rumah_ibadah_id']) {
json_response(['success' => false, 'message' => 'Pengurus rumah ibadah hanya dapat mencatat bantuan untuk keluarga tanggungannya sendiri.'], 403);
}
$stmt = $pdo->prepare('INSERT INTO riwayat_bantuan
(keluarga_id, rumah_ibadah_id, tanggal_bantuan, jenis_bantuan, nilai_bantuan, catatan, created_by)
VALUES (?, ?, ?, ?, ?, ?, ?)');
$stmt->execute([
$keluargaId,
$rumahIbadahId,
clean_string($data['tanggal_bantuan']),
clean_string($data['jenis_bantuan']),
clean_float($data['nilai_bantuan'] ?? 0),
clean_string($data['catatan'] ?? ''),
$user['id']
]);
json_response(['success' => true, 'message' => 'Riwayat bantuan berhasil dicatat.'], 201);
}
json_response(['success' => false, 'message' => 'Method tidak didukung.'], 405);
+190
View File
@@ -0,0 +1,190 @@
<?php
require_once __DIR__ . '/_helpers.php';
api_require_login();
$method = $_SERVER['REQUEST_METHOD'];
$user = current_user();
$role = current_role();
function clean_allowed($value, array $allowed, string $default): string
{
$v = clean_string($value);
return in_array($v, $allowed, true) ? $v : $default;
}
function can_access_family(array $kel, array $user, string $role): bool
{
if (in_array($role, ['admin','dinas','relawan'], true)) return true;
if ($role === 'masyarakat') return (int)$kel['created_by'] === (int)$user['id'];
if ($role === 'rumah_ibadah') {
return (!empty($user['rumah_ibadah_id']) && (int)$kel['rumah_ibadah_id'] === (int)$user['rumah_ibadah_id']) || (int)$kel['created_by'] === (int)$user['id'] || $kel['status_bantuan'] === 'Blank Spot';
}
return false;
}
if ($method === 'GET') {
$where = '';
$params = [];
if ($role === 'masyarakat') {
$where = 'WHERE k.created_by = ?';
$params[] = $user['id'];
} elseif ($role === 'rumah_ibadah' && !empty($user['rumah_ibadah_id'])) {
$where = 'WHERE k.rumah_ibadah_id = ? OR k.status_bantuan = "Blank Spot" OR k.created_by = ?';
$params[] = (int)$user['rumah_ibadah_id'];
$params[] = $user['id'];
}
$sql = 'SELECT k.*, r.nama AS nama_rumah_ibadah, r.kategori AS kategori_rumah_ibadah,
r.lat AS ri_lat, r.lng AS ri_lng,
COALESCE(a.jumlah_anggota, 0) AS jumlah_anggota,
COALESCE(a.jumlah_mampu_bekerja, 0) AS jumlah_mampu_bekerja
FROM keluarga k
LEFT JOIN rumah_ibadah r ON r.id = k.rumah_ibadah_id
LEFT JOIN (
SELECT keluarga_id,
COUNT(*) AS jumlah_anggota,
SUM(CASE WHEN mampu_bekerja = "Ya" THEN 1 ELSE 0 END) AS jumlah_mampu_bekerja
FROM keluarga_anggota
GROUP BY keluarga_id
) a ON a.keluarga_id = k.id
' . $where . '
ORDER BY FIELD(k.kerentanan, "Miskin Ekstrem", "Sangat Miskin", "Miskin", "Rentan Miskin"), k.nama_kk ASC';
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$rows = $stmt->fetchAll();
if ($rows) {
$ids = array_map(fn($r) => (int)$r['id'], $rows);
$placeholders = implode(',', array_fill(0, count($ids), '?'));
$anggotaStmt = $pdo->prepare('SELECT * FROM keluarga_anggota WHERE keluarga_id IN (' . $placeholders . ') ORDER BY FIELD(hubungan, "Kepala Keluarga", "Suami", "Istri", "Anak", "Orang Tua", "Mertua", "Famili Lain", "Lainnya"), tanggal_lahir ASC, nama ASC');
$anggotaStmt->execute($ids);
$anggotaByKeluarga = [];
foreach ($anggotaStmt->fetchAll() as $anggota) {
$anggotaByKeluarga[(int)$anggota['keluarga_id']][] = $anggota;
}
foreach ($rows as &$row) {
$row['anggota'] = $anggotaByKeluarga[(int)$row['id']] ?? [];
}
unset($row);
}
json_response(['success' => true, 'data' => $rows]);
}
if ($method === 'POST') {
$data = get_json_input();
required_fields($data, ['nama_kk','alamat','kerentanan','kebutuhan','lat','lng']);
$statusVerifikasi = clean_string($data['status_verifikasi'] ?? 'Menunggu Verifikasi');
if ($role === 'masyarakat' || !role_in(['admin','dinas','relawan'])) {
$statusVerifikasi = 'Menunggu Verifikasi';
}
$allowedStatus = ['Menunggu Verifikasi','Valid','Tidak Valid','Perlu Survei Ulang'];
if (!in_array($statusVerifikasi, $allowedStatus, true)) {
$statusVerifikasi = 'Menunggu Verifikasi';
}
$anggota = is_array($data['anggota'] ?? null) ? $data['anggota'] : [];
$anggota = array_values(array_filter($anggota, fn($a) => is_array($a) && trim((string)($a['nama'] ?? '')) !== ''));
if (count($anggota) === 0) {
json_response(['success' => false, 'message' => 'Minimal satu anggota keluarga harus diisi.'], 422);
}
$statusBantuan = $statusVerifikasi === 'Tidak Valid' ? 'Tidak Valid' : 'Menunggu Verifikasi';
$pdo->beginTransaction();
try {
$stmt = $pdo->prepare('INSERT INTO keluarga
(nama_kk, alamat, no_kk, nik, kerentanan, kebutuhan, status_verifikasi, status_bantuan, catatan, lat, lng, created_by)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
$stmt->execute([
clean_string($data['nama_kk']),
clean_string($data['alamat']),
clean_string($data['no_kk'] ?? ''),
clean_string($data['nik'] ?? ''),
clean_string($data['kerentanan']),
clean_string($data['kebutuhan']),
$statusVerifikasi,
$statusBantuan,
clean_string($data['catatan'] ?? ''),
clean_float($data['lat']),
clean_float($data['lng']),
$user['id']
]);
$keluargaId = (int)$pdo->lastInsertId();
$anggotaStmt = $pdo->prepare('INSERT INTO keluarga_anggota
(keluarga_id, nik, nama, hubungan, jenis_kelamin, tempat_lahir, tanggal_lahir, agama, pendidikan, pekerjaan, status_perkawinan, penghasilan, mampu_bekerja, keahlian, status_pemberdayaan, catatan)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
$allowedHubungan = ['Kepala Keluarga','Istri','Suami','Anak','Orang Tua','Mertua','Famili Lain','Lainnya'];
$allowedGender = ['Laki-laki','Perempuan'];
$allowedWork = ['Ya','Tidak'];
foreach ($anggota as $a) {
$tanggal = clean_string($a['tanggal_lahir'] ?? '');
$anggotaStmt->execute([
$keluargaId,
clean_string($a['nik'] ?? ''),
clean_string($a['nama'] ?? ''),
clean_allowed($a['hubungan'] ?? '', $allowedHubungan, 'Lainnya'),
clean_allowed($a['jenis_kelamin'] ?? '', $allowedGender, 'Laki-laki'),
clean_string($a['tempat_lahir'] ?? ''),
$tanggal !== '' ? $tanggal : null,
clean_string($a['agama'] ?? ''),
clean_string($a['pendidikan'] ?? ''),
clean_string($a['pekerjaan'] ?? ''),
clean_string($a['status_perkawinan'] ?? ''),
clean_float($a['penghasilan'] ?? 0),
clean_allowed($a['mampu_bekerja'] ?? 'Tidak', $allowedWork, 'Tidak'),
clean_string($a['keahlian'] ?? ''),
clean_allowed($a['mampu_bekerja'] ?? 'Tidak', $allowedWork, 'Tidak') === 'Ya' ? 'Layak Diberdayakan' : 'Belum Dinilai',
clean_string($a['catatan'] ?? '')
]);
}
$pdo->commit();
json_response(['success' => true, 'message' => 'Data keluarga dan anggota KK berhasil disimpan.', 'id' => $keluargaId], 201);
} catch (Throwable $e) {
$pdo->rollBack();
json_response(['success' => false, 'message' => 'Data gagal disimpan: ' . $e->getMessage()], 500);
}
}
if ($method === 'PUT') {
api_require_role(['admin','dinas','relawan']);
$data = get_json_input();
required_fields($data, ['id']);
$id = clean_int($data['id']);
$allowedStatus = ['Menunggu Verifikasi','Valid','Tidak Valid','Perlu Survei Ulang'];
$statusVerifikasi = clean_string($data['status_verifikasi'] ?? 'Menunggu Verifikasi');
if (!in_array($statusVerifikasi, $allowedStatus, true)) {
json_response(['success' => false, 'message' => 'Status verifikasi tidak valid.'], 422);
}
$statusBantuan = $statusVerifikasi === 'Tidak Valid' ? 'Tidak Valid' : 'Menunggu Verifikasi';
$stmt = $pdo->prepare('UPDATE keluarga SET
status_verifikasi = ?, status_bantuan = ?, rumah_ibadah_id = NULL, catatan = CONCAT(COALESCE(catatan, ""), ?)
WHERE id = ?');
$catatanTambahan = clean_string($data['catatan'] ?? '');
$catatanTambahan = $catatanTambahan ? "\n[Verifikasi] " . $catatanTambahan : '';
$stmt->execute([$statusVerifikasi, $statusBantuan, $catatanTambahan, $id]);
json_response(['success' => true, 'message' => 'Status verifikasi berhasil diperbarui. Jalankan analisis ulang untuk memperbarui status bantuan.']);
}
if ($method === 'DELETE') {
api_require_role(['admin','dinas']);
$id = clean_int($_GET['id'] ?? 0);
if ($id <= 0) json_response(['success' => false, 'message' => 'ID tidak valid.'], 422);
$stmt = $pdo->prepare('DELETE FROM keluarga WHERE id = ?');
$stmt->execute([$id]);
json_response(['success' => true, 'message' => 'Data keluarga berhasil dihapus.']);
}
json_response(['success' => false, 'message' => 'Method tidak didukung.'], 405);
+104
View File
@@ -0,0 +1,104 @@
<?php
require_once __DIR__ . '/_helpers.php';
api_require_login();
$method = $_SERVER['REQUEST_METHOD'];
$user = current_user();
$role = current_role();
function allowed_value($value, array $allowed, string $default): string
{
$v = clean_string($value);
return in_array($v, $allowed, true) ? $v : $default;
}
if ($method === 'GET') {
$where = [];
$params = [];
if ($role === 'masyarakat') {
$where[] = 'lm.pelapor_id = ?';
$params[] = $user['id'];
} elseif ($role === 'rumah_ibadah' && !empty($user['rumah_ibadah_id'])) {
$where[] = '(k.rumah_ibadah_id = ? OR lm.pelapor_id = ?)';
$params[] = (int)$user['rumah_ibadah_id'];
$params[] = $user['id'];
}
$sql = 'SELECT lm.*, k.nama_kk, k.status_bantuan, r.nama AS nama_rumah_ibadah, u.nama AS nama_pelapor
FROM laporan_musibah lm
LEFT JOIN keluarga k ON k.id = lm.keluarga_id
LEFT JOIN rumah_ibadah r ON r.id = k.rumah_ibadah_id
LEFT JOIN users u ON u.id = lm.pelapor_id';
if ($where) $sql .= ' WHERE ' . implode(' AND ', $where);
$sql .= ' ORDER BY FIELD(lm.tingkat_urgensi, "Darurat", "Tinggi", "Sedang", "Rendah"), lm.created_at DESC';
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
json_response(['success' => true, 'data' => $stmt->fetchAll()]);
}
if ($method === 'POST') {
$data = get_json_input();
required_fields($data, ['jenis_musibah','tingkat_urgensi','tanggal_kejadian','deskripsi']);
$keluargaId = clean_int($data['keluarga_id'] ?? 0);
$alamat = clean_string($data['alamat'] ?? '');
$lat = $data['lat'] ?? '';
$lng = $data['lng'] ?? '';
if ($keluargaId > 0) {
$stmtKel = $pdo->prepare('SELECT id, alamat, lat, lng FROM keluarga WHERE id = ? LIMIT 1');
$stmtKel->execute([$keluargaId]);
$kel = $stmtKel->fetch();
if (!$kel) json_response(['success' => false, 'message' => 'Data keluarga tidak ditemukan.'], 404);
if ($alamat === '') $alamat = $kel['alamat'];
if ($lat === '' || $lng === '') {
$lat = $kel['lat'];
$lng = $kel['lng'];
}
}
if ($alamat === '' || $lat === '' || $lng === '') {
json_response(['success' => false, 'message' => 'Pilih keluarga terdata atau tentukan lokasi kejadian pada peta.'], 422);
}
$stmt = $pdo->prepare('INSERT INTO laporan_musibah
(keluarga_id, pelapor_id, jenis_musibah, tingkat_urgensi, tanggal_kejadian, alamat, lat, lng, deskripsi, kebutuhan_mendesak, status)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "Baru")');
$stmt->execute([
$keluargaId > 0 ? $keluargaId : null,
$user['id'],
allowed_value($data['jenis_musibah'], ['Kebakaran','Banjir','Sakit Mendesak','Kehilangan Pekerjaan','Kematian Tulang Punggung Keluarga','Rumah Rusak','Lainnya'], 'Lainnya'),
allowed_value($data['tingkat_urgensi'], ['Rendah','Sedang','Tinggi','Darurat'], 'Sedang'),
clean_string($data['tanggal_kejadian']),
$alamat,
clean_float($lat),
clean_float($lng),
clean_string($data['deskripsi']),
clean_string($data['kebutuhan_mendesak'] ?? '')
]);
json_response(['success' => true, 'message' => 'Laporan musibah berhasil dikirim dan masuk antrian tindak lanjut.', 'id' => $pdo->lastInsertId()], 201);
}
if ($method === 'PUT') {
api_require_role(['admin','dinas','relawan','rumah_ibadah']);
$data = get_json_input();
required_fields($data, ['id','status']);
$id = clean_int($data['id']);
$status = allowed_value($data['status'], ['Baru','Diverifikasi','Diproses','Ditindaklanjuti','Selesai','Ditolak'], 'Baru');
$tindak = clean_string($data['tindak_lanjut'] ?? '');
if ($role === 'rumah_ibadah') {
$stmtCheck = $pdo->prepare('SELECT lm.id FROM laporan_musibah lm LEFT JOIN keluarga k ON k.id = lm.keluarga_id WHERE lm.id = ? AND (k.rumah_ibadah_id = ? OR lm.pelapor_id = ?)');
$stmtCheck->execute([$id, (int)($user['rumah_ibadah_id'] ?? 0), (int)$user['id']]);
if (!$stmtCheck->fetch()) json_response(['success' => false, 'message' => 'Akses laporan musibah ditolak.'], 403);
}
$stmt = $pdo->prepare('UPDATE laporan_musibah SET status = ?, tindak_lanjut = CONCAT(COALESCE(tindak_lanjut, ""), ?), handled_by = ?, updated_at = NOW() WHERE id = ?');
$tambahan = $tindak !== '' ? "\n[" . date('Y-m-d H:i') . "] " . $tindak : '';
$stmt->execute([$status, $tambahan, $user['id'], $id]);
json_response(['success' => true, 'message' => 'Status laporan musibah berhasil diperbarui.']);
}
json_response(['success' => false, 'message' => 'Method tidak didukung.'], 405);