pertama dan terakhir

This commit is contained in:
Tazyeuu
2026-06-10 22:07:47 +07:00
commit cd376094df
143 changed files with 12090 additions and 0 deletions
+66
View File
@@ -0,0 +1,66 @@
<?php
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/helpers.php';
$pdo = Database::getConnection();
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
sendError('Method not allowed', 405);
}
// Warga miskin yang berada di luar semua radius bantuan rumah ibadah.
$sql = "
SELECT
w.id,
w.nama_kk,
w.penghasilan,
ST_AsGeoJSON(w.geom) AS geojson,
ri.nama AS rumah_ibadah_terdekat,
ST_Distance_Sphere(w.geom, ri.geom) AS jarak_meter,
ri.radius_bantuan_meter,
(ST_Distance_Sphere(w.geom, ri.geom) - ri.radius_bantuan_meter) AS selisih_meter
FROM warga_miskin w
JOIN rumah_ibadah ri
JOIN (
SELECT
nearest_distance.warga_id,
MIN(nearest_distance.jarak_meter) AS min_jarak_meter
FROM (
SELECT
w2.id AS warga_id,
ST_Distance_Sphere(w2.geom, ri2.geom) AS jarak_meter
FROM warga_miskin w2
CROSS JOIN rumah_ibadah ri2
) nearest_distance
GROUP BY nearest_distance.warga_id
) nearest
ON nearest.warga_id = w.id
AND ABS(ST_Distance_Sphere(w.geom, ri.geom) - nearest.min_jarak_meter) < 0.001
WHERE NOT EXISTS (
SELECT 1
FROM rumah_ibadah ri_in_radius
WHERE ST_Distance_Sphere(w.geom, ri_in_radius.geom) <= ri_in_radius.radius_bantuan_meter
)
GROUP BY w.id
ORDER BY selisih_meter DESC
";
$stmt = $pdo->query($sql);
$features = [];
while ($r = $stmt->fetch()) {
$features[] = [
'type' => 'Feature',
'geometry' => json_decode($r['geojson']),
'properties' => [
'id' => (int)$r['id'],
'nama_kk' => $r['nama_kk'],
'jarak_km' => round(((float)$r['jarak_meter']) / 1000, 2),
'radius_km' => round(((int)$r['radius_bantuan_meter']) / 1000, 2),
'selisih_km' => round(((float)$r['selisih_meter']) / 1000, 2),
'rumah_ibadah_terdekat' => $r['rumah_ibadah_terdekat']
]
];
}
sendSuccess(['type' => 'FeatureCollection', 'features' => $features], 'Blank Spot');
+52
View File
@@ -0,0 +1,52 @@
<?php
require_once __DIR__ . '/../config/session.php';
/**
* Shared response helper for all API endpoints
*/
header('Content-Type: application/json');
$allowedOrigin = getenv('CORS_ALLOWED_ORIGIN');
if ($allowedOrigin !== false && $allowedOrigin !== '') {
header('Access-Control-Allow-Origin: ' . $allowedOrigin);
header('Vary: Origin');
header('Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
}
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); exit; }
function sendSuccess($data, string $message = 'OK', int $code = 200): void {
http_response_code($code);
echo json_encode(['status' => 'success', 'message' => $message, 'data' => $data]);
exit;
}
function sendError(string $message = 'Bad Request', int $code = 400): void {
http_response_code($code);
echo json_encode(['status' => 'error', 'message' => $message, 'data' => null]);
exit;
}
function getInput(): array {
return json_decode(file_get_contents('php://input'), true) ?? [];
}
function requireApiRole(string $role): void {
if (session_status() === PHP_SESSION_NONE) {
startAppSession();
}
if (!isset($_SESSION['user_id'], $_SESSION['role'])) {
sendError('Unauthorized', 401);
}
if ($_SESSION['role'] !== $role) {
sendError('Forbidden', 403);
}
}
function requireAdminForMutation(): void {
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
requireApiRole('admin');
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php require_once __DIR__ . '/../config/db.php'; require_once __DIR__ . '/helpers.php';
$pdo = Database::getConnection(); $method = $_SERVER['REQUEST_METHOD'];
requireAdminForMutation();
switch ($method) {
case 'GET':
$stmt = $pdo->query("SELECT id,nama,jenis_jalan,created_at,ST_AsGeoJSON(geom) as geojson FROM jalan ORDER BY id DESC");
$features=[];
while($r=$stmt->fetch()) $features[]=['type'=>'Feature','geometry'=>json_decode($r['geojson']),'properties'=>['id'=>$r['id'],'nama'=>$r['nama'],'jenis_jalan'=>$r['jenis_jalan'],'created_at'=>$r['created_at']]];
sendSuccess(['type'=>'FeatureCollection','features'=>$features],'Data Jalan'); break;
case 'POST':
$d=getInput(); if(empty($d['nama'])||empty($d['geometry'])) sendError('Nama & geometri wajib');
$pdo->prepare("INSERT INTO jalan(nama,jenis_jalan,geom) VALUES(?,?,ST_GeomFromGeoJSON(?))")->execute([$d['nama'],$d['jenis_jalan']??'Lokal',json_encode($d['geometry'])]);
sendSuccess(['id'=>$pdo->lastInsertId()],'Jalan disimpan',201); break;
case 'PUT':
$d=getInput(); $id=$_GET['id']??null; if(!$id) sendError('ID wajib');
$pdo->prepare("UPDATE jalan SET nama=?,jenis_jalan=? WHERE id=?")->execute([$d['nama'],$d['jenis_jalan'],$id]);
sendSuccess(null,'Jalan diperbarui'); break;
case 'DELETE':
$id=$_GET['id']??null; if(!$id) sendError('ID wajib');
$pdo->prepare("DELETE FROM jalan WHERE id=?")->execute([$id]); sendSuccess(null,'Jalan dihapus'); break;
default: sendError('Method not allowed',405);
}
+26
View File
@@ -0,0 +1,26 @@
<?php require_once __DIR__ . '/../config/db.php'; require_once __DIR__ . '/helpers.php';
$pdo = Database::getConnection(); $method = $_SERVER['REQUEST_METHOD'];
requireAdminForMutation();
switch ($method) {
case 'GET':
$stmt = $pdo->query("SELECT id,nama_pemilik,status_kepemilikan,luas,created_at,ST_AsGeoJSON(geom) as geojson FROM kavling ORDER BY id DESC");
$features=[];
while($r=$stmt->fetch()) $features[]=['type'=>'Feature','geometry'=>json_decode($r['geojson']),'properties'=>['id'=>$r['id'],'nama_pemilik'=>$r['nama_pemilik'],'status_kepemilikan'=>$r['status_kepemilikan'],'luas'=>$r['luas'],'created_at'=>$r['created_at']]];
sendSuccess(['type'=>'FeatureCollection','features'=>$features],'Data Kavling'); break;
case 'POST':
$d=getInput(); if(empty($d['nama_pemilik'])||empty($d['status_kepemilikan'])||empty($d['geometry'])) sendError('Data tidak lengkap');
$pdo->prepare("INSERT INTO kavling(nama_pemilik,status_kepemilikan,luas,geom) VALUES(?,?,?,ST_GeomFromGeoJSON(?))")->execute([$d['nama_pemilik'],$d['status_kepemilikan'],$d['luas']??0,json_encode($d['geometry'])]);
sendSuccess(['id'=>$pdo->lastInsertId()],'Kavling disimpan',201); break;
case 'PUT':
$d=getInput(); $id=$_GET['id']??null; if(!$id) sendError('ID wajib');
if(!empty($d['geometry'])){
$pdo->prepare("UPDATE kavling SET geom=ST_GeomFromGeoJSON(?) WHERE id=?")->execute([json_encode($d['geometry']),$id]);
} else {
$pdo->prepare("UPDATE kavling SET nama_pemilik=?,status_kepemilikan=?,luas=? WHERE id=?")->execute([$d['nama_pemilik'],$d['status_kepemilikan'],$d['luas']??0,$id]);
}
sendSuccess(null,'Kavling diperbarui'); break;
case 'DELETE':
$id=$_GET['id']??null; if(!$id) sendError('ID wajib');
$pdo->prepare("DELETE FROM kavling WHERE id=?")->execute([$id]); sendSuccess(null,'Kavling dihapus'); break;
default: sendError('Method not allowed',405);
}
+22
View File
@@ -0,0 +1,22 @@
<?php require_once __DIR__ . '/../config/db.php'; require_once __DIR__ . '/helpers.php';
$pdo = Database::getConnection(); $method = $_SERVER['REQUEST_METHOD'];
requireAdminForMutation();
switch ($method) {
case 'GET':
$stmt = $pdo->query("SELECT id,nama_kawasan,created_at,ST_AsGeoJSON(geom) as geojson FROM kawasan_kumuh ORDER BY id DESC");
$features=[];
while($r=$stmt->fetch()) $features[]=['type'=>'Feature','geometry'=>json_decode($r['geojson']),'properties'=>['id'=>$r['id'],'nama_kawasan'=>$r['nama_kawasan'],'created_at'=>$r['created_at']]];
sendSuccess(['type'=>'FeatureCollection','features'=>$features],'Data Kawasan Kumuh'); break;
case 'POST':
$d=getInput(); if(empty($d['nama_kawasan'])||empty($d['geometry'])) sendError('Data tidak lengkap');
$pdo->prepare("INSERT INTO kawasan_kumuh(nama_kawasan,geom) VALUES(?,ST_GeomFromGeoJSON(?))")->execute([$d['nama_kawasan'],json_encode($d['geometry'])]);
sendSuccess(['id'=>$pdo->lastInsertId()],'Kawasan disimpan',201); break;
case 'PUT':
$d=getInput(); $id=$_GET['id']??null; if(!$id) sendError('ID wajib');
$pdo->prepare("UPDATE kawasan_kumuh SET nama_kawasan=? WHERE id=?")->execute([$d['nama_kawasan'],$id]);
sendSuccess(null,'Kawasan diperbarui'); break;
case 'DELETE':
$id=$_GET['id']??null; if(!$id) sendError('ID wajib');
$pdo->prepare("DELETE FROM kawasan_kumuh WHERE id=?")->execute([$id]); sendSuccess(null,'Kawasan dihapus'); break;
default: sendError('Method not allowed',405);
}
+104
View File
@@ -0,0 +1,104 @@
<?php
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/../config/session.php';
startAppSession();
header('Content-Type: application/json');
if (!isset($_SESSION['user_id'])) {
http_response_code(401);
echo json_encode(['status' => 'error', 'message' => 'Unauthorized']);
exit;
}
$pdo = Database::getConnection();
$method = $_SERVER['REQUEST_METHOD'];
try {
if ($method === 'GET') {
// Jika parameter my_reports=1, hanya laporan milik user yang login
// Jika tidak dan role=admin, ambil semua.
$my_reports = $_GET['my_reports'] ?? 0;
$sql = "SELECT l.*, ST_X(l.geometry) as lng, ST_Y(l.geometry) as lat, u.nama_lengkap, u.username
FROM laporan_warga l
JOIN users u ON l.user_id = u.id ";
if ($my_reports || $_SESSION['role'] !== 'admin') {
// User biasa hanya boleh melihat laporannya sendiri di tabel dashboard,
// tapi mungkin butuh lihat semua laporan di peta publik?
// Untuk peta public (semua laporan disetujui atau diproses), tambahkan parameter public=1
if (isset($_GET['public']) && $_GET['public'] == 1) {
$sql .= " WHERE l.status IN ('diproses', 'selesai') ";
} else {
$sql .= " WHERE l.user_id = " . (int)$_SESSION['user_id'];
}
}
$sql .= " ORDER BY l.id DESC";
$rows = $pdo->query($sql)->fetchAll();
$features = [];
foreach ($rows as $row) {
$features[] = [
'type' => 'Feature',
'properties' => [
'id' => $row['id'],
'user_id' => $row['user_id'],
'pelapor' => $row['nama_lengkap'] ?: $row['username'],
'kategori' => $row['kategori'],
'deskripsi' => $row['deskripsi'],
'status' => $row['status'],
'created_at' => $row['created_at']
],
'geometry' => [
'type' => 'Point',
'coordinates' => [(float)$row['lng'], (float)$row['lat']]
]
];
}
echo json_encode([
'type' => 'FeatureCollection',
'features' => $features
]);
}
elseif ($method === 'POST') {
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['kategori'], $input['deskripsi'], $input['geometry'])) {
throw new Exception("Data tidak lengkap.");
}
$coords = $input['geometry']['coordinates'];
$stmt = $pdo->prepare("INSERT INTO laporan_warga (user_id, kategori, deskripsi, geometry) VALUES (?, ?, ?, ST_GeomFromText(?))");
$stmt->execute([
$_SESSION['user_id'],
$input['kategori'],
$input['deskripsi'],
"POINT({$coords[0]} {$coords[1]})"
]);
echo json_encode(['status' => 'success', 'message' => 'Laporan berhasil dibuat.']);
}
elseif ($method === 'PUT') {
if ($_SESSION['role'] !== 'admin') throw new Exception("Unauthorized");
$id = $_GET['id'] ?? 0;
$input = json_decode(file_get_contents('php://input'), true);
$status = $input['status'] ?? 'menunggu';
$stmt = $pdo->prepare("UPDATE laporan_warga SET status = ? WHERE id = ?");
$stmt->execute([$status, $id]);
echo json_encode(['status' => 'success', 'message' => 'Status laporan diperbarui.']);
}
elseif ($method === 'DELETE') {
$id = $_GET['id'] ?? 0;
// User bisa hapus kalau status menunggu. Admin bisa hapus semua.
if ($_SESSION['role'] === 'admin') {
$stmt = $pdo->prepare("DELETE FROM laporan_warga WHERE id = ?");
$stmt->execute([$id]);
} else {
$stmt = $pdo->prepare("DELETE FROM laporan_warga WHERE id = ? AND user_id = ? AND status = 'menunggu'");
$stmt->execute([$id, $_SESSION['user_id']]);
}
echo json_encode(['status' => 'success', 'message' => 'Laporan dihapus.']);
}
} catch (Exception $e) {
http_response_code(400);
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
}
+102
View File
@@ -0,0 +1,102 @@
<?php
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/helpers.php';
$pdo = Database::getConnection();
$method = $_SERVER['REQUEST_METHOD'];
requireAdminForMutation();
function normalizeRadius($value): int {
$radius = (int)($value ?? 1000);
if ($radius < 100) return 100;
if ($radius > 10000) return 10000;
return $radius;
}
switch ($method) {
case 'GET':
$stmt = $pdo->query("
SELECT
r.id,
r.nama,
r.agama,
r.radius_bantuan_meter,
r.created_at,
ST_AsGeoJSON(r.geom) AS geojson,
IFNULL(AVG(u.rating), 0) AS avg_rating,
COUNT(u.id) AS total_ulasan
FROM rumah_ibadah r
LEFT JOIN ulasan_fasilitas u
ON u.fasilitas_id = r.id
AND u.fasilitas_tipe = 'rumah_ibadah'
GROUP BY r.id
ORDER BY r.id DESC
");
$features = [];
while ($r = $stmt->fetch()) {
$features[] = [
'type' => 'Feature',
'geometry' => json_decode($r['geojson']),
'properties' => [
'id' => (int)$r['id'],
'nama' => $r['nama'],
'agama' => $r['agama'],
'radius_bantuan_meter' => (int)$r['radius_bantuan_meter'],
'radius_bantuan_km' => round(((int)$r['radius_bantuan_meter']) / 1000, 2),
'created_at' => $r['created_at'],
'avg_rating' => round((float)$r['avg_rating'], 1),
'total_ulasan' => (int)$r['total_ulasan']
]
];
}
sendSuccess(['type' => 'FeatureCollection', 'features' => $features], 'Data Rumah Ibadah');
break;
case 'POST':
$d = getInput();
if (empty($d['nama']) || empty($d['agama']) || empty($d['geometry'])) {
sendError('Data tidak lengkap');
}
$radius = normalizeRadius($d['radius_bantuan_meter'] ?? null);
$pdo->prepare("
INSERT INTO rumah_ibadah (nama, agama, radius_bantuan_meter, geom)
VALUES (?, ?, ?, ST_GeomFromGeoJSON(?))
")->execute([$d['nama'], $d['agama'], $radius, json_encode($d['geometry'])]);
sendSuccess(['id' => $pdo->lastInsertId()], 'Rumah Ibadah disimpan', 201);
break;
case 'PUT':
$d = getInput();
$id = $_GET['id'] ?? null;
if (!$id) sendError('ID wajib');
if (!empty($d['geometry'])) {
$pdo->prepare("UPDATE rumah_ibadah SET geom = ST_GeomFromGeoJSON(?) WHERE id = ?")
->execute([json_encode($d['geometry']), $id]);
} else {
$radius = normalizeRadius($d['radius_bantuan_meter'] ?? null);
$pdo->prepare("
UPDATE rumah_ibadah
SET nama = ?, agama = ?, radius_bantuan_meter = ?
WHERE id = ?
")->execute([$d['nama'], $d['agama'], $radius, $id]);
}
sendSuccess(null, 'Rumah Ibadah diperbarui');
break;
case 'DELETE':
$id = $_GET['id'] ?? null;
if (!$id) sendError('ID wajib');
$pdo->prepare("DELETE FROM rumah_ibadah WHERE id = ?")->execute([$id]);
sendSuccess(null, 'Rumah Ibadah dihapus');
break;
default:
sendError('Method not allowed', 405);
}
+57
View File
@@ -0,0 +1,57 @@
<?php require_once __DIR__ . '/../config/db.php'; require_once __DIR__ . '/helpers.php';
$pdo = Database::getConnection();
$method = $_SERVER['REQUEST_METHOD'];
requireAdminForMutation();
switch ($method) {
case 'GET':
$stmt = $pdo->query("SELECT s.id, s.nama, s.deskripsi, s.buka_24_jam, s.created_at, ST_AsGeoJSON(s.geom) as geojson,
IFNULL(AVG(u.rating), 0) as avg_rating, COUNT(u.id) as total_ulasan
FROM spbu s
LEFT JOIN ulasan_fasilitas u ON u.fasilitas_id = s.id AND u.fasilitas_tipe = 'spbu'
GROUP BY s.id
ORDER BY s.id DESC");
$features = [];
while ($r = $stmt->fetch()) {
$features[] = [
'type'=>'Feature',
'geometry'=>json_decode($r['geojson']),
'properties'=>[
'id'=>$r['id'],
'nama'=>$r['nama'],
'deskripsi'=>$r['deskripsi'],
'buka_24_jam'=>(int)$r['buka_24_jam'],
'created_at'=>$r['created_at'],
'avg_rating'=>round($r['avg_rating'], 1),
'total_ulasan'=>$r['total_ulasan']
]
];
}
sendSuccess(['type'=>'FeatureCollection','features'=>$features], 'Data SPBU');
break;
case 'POST':
$d = getInput();
if (empty($d['nama']) || empty($d['geometry'])) sendError('Nama dan geometri wajib diisi');
$stmt = $pdo->prepare("INSERT INTO spbu (nama, deskripsi, buka_24_jam, geom) VALUES (?,?,?,ST_GeomFromGeoJSON(?))");
$stmt->execute([$d['nama'], $d['deskripsi']??'', (int)($d['buka_24_jam']??0), json_encode($d['geometry'])]);
sendSuccess(['id'=>$pdo->lastInsertId()], 'SPBU disimpan', 201);
break;
case 'PUT':
$d = getInput(); $id = $_GET['id'] ?? null;
if (!$id) sendError('ID wajib disertakan');
if (!empty($d['geometry'])) {
$stmt = $pdo->prepare("UPDATE spbu SET geom=ST_GeomFromGeoJSON(?) WHERE id=?");
$stmt->execute([json_encode($d['geometry']), $id]);
} else {
$stmt = $pdo->prepare("UPDATE spbu SET nama=?, deskripsi=?, buka_24_jam=? WHERE id=?");
$stmt->execute([$d['nama'], $d['deskripsi']??'', (int)($d['buka_24_jam']??0), $id]);
}
sendSuccess(null, 'SPBU diperbarui');
break;
case 'DELETE':
$id = $_GET['id'] ?? null;
if (!$id) sendError('ID wajib disertakan');
$pdo->prepare("DELETE FROM spbu WHERE id=?")->execute([$id]);
sendSuccess(null, 'SPBU dihapus');
break;
default: sendError('Method not allowed', 405);
}
+29
View File
@@ -0,0 +1,29 @@
<?php
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/helpers.php';
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
sendError('Method not allowed', 405);
}
$pdo = Database::getConnection();
date_default_timezone_set('Asia/Jakarta');
$row = $pdo->query("
SELECT
COUNT(*) AS total_spbu,
SUM(CASE WHEN buka_24_jam = 1 THEN 1 ELSE 0 END) AS spbu_buka
FROM spbu
")->fetch();
$total = (int)($row['total_spbu'] ?? 0);
$open = (int)($row['spbu_buka'] ?? 0);
sendSuccess([
'total_spbu' => $total,
'spbu_buka' => $open,
'spbu_tutup' => max(0, $total - $open),
'basis_perhitungan' => 'buka_24_jam',
'server_time' => date('Y-m-d H:i:s'),
'timezone' => date_default_timezone_get()
], 'Status SPBU');
+13
View File
@@ -0,0 +1,13 @@
<?php require_once __DIR__ . '/../config/db.php'; require_once __DIR__ . '/helpers.php';
$pdo = Database::getConnection();
if ($_SERVER['REQUEST_METHOD'] !== 'GET') sendError('Method not allowed', 405);
$lat = (float)($_GET['lat'] ?? 0); $lng = (float)($_GET['lng'] ?? 0);
if (!$lat || !$lng) sendError('lat dan lng wajib diisi');
$wkt = sprintf('POINT(%F %F)', $lng, $lat);
$stmt = $pdo->prepare("SELECT id, nama, buka_24_jam, ST_AsGeoJSON(geom) as geojson,
ST_Distance_Sphere(geom, ST_GeomFromText(?)) / 1000 as jarak_km
FROM spbu ORDER BY jarak_km ASC LIMIT 1");
$stmt->execute([$wkt]);
$r = $stmt->fetch();
if (!$r) sendError('Tidak ada SPBU di database', 404);
sendSuccess(['type'=>'Feature','geometry'=>json_decode($r['geojson']),'properties'=>['id'=>$r['id'],'nama'=>$r['nama'],'buka_24_jam'=>(int)$r['buka_24_jam'],'jarak_km'=>round($r['jarak_km'],2)]], 'SPBU terdekat');
+53
View File
@@ -0,0 +1,53 @@
<?php require_once __DIR__ . '/../config/db.php'; require_once __DIR__ . '/helpers.php';
$pdo = Database::getConnection();
if ($_SERVER['REQUEST_METHOD'] !== 'GET') sendError('Method not allowed', 405);
// Summary counts
$counts = $pdo->query("SELECT
(SELECT COUNT(*) FROM spbu) as total_spbu,
(SELECT COUNT(*) FROM jalan) as total_jalan,
(SELECT COUNT(*) FROM kavling) as total_kavling,
(SELECT COUNT(*) FROM rumah_ibadah) as total_rumah_ibadah,
(SELECT COUNT(*) FROM warga_miskin) as total_warga_miskin,
(SELECT COUNT(*) FROM kawasan_kumuh) as total_kawasan_kumuh,
(SELECT COUNT(*) FROM spbu WHERE buka_24_jam=1) as spbu_24jam
")->fetch();
// Choropleth: kawasan kumuh + jumlah warga di dalamnya
$sql = "SELECT k.id, k.nama_kawasan, ST_AsGeoJSON(k.geom) as geojson,
COUNT(w.id) as jumlah_warga,
COALESCE(SUM(w.jumlah_tanggungan),0) as total_tanggungan
FROM kawasan_kumuh k
LEFT JOIN warga_miskin w ON ST_Contains(k.geom, w.geom)
GROUP BY k.id";
$stmt = $pdo->query($sql);
$features = [];
$merahCount = 0;
while ($r = $stmt->fetch()) {
$jumlah = (int)$r['jumlah_warga'];
if ($jumlah > 3) $merahCount++;
$features[] = [
'type' => 'Feature',
'geometry' => json_decode($r['geojson']),
'properties' => [
'id' => $r['id'],
'nama_kawasan' => $r['nama_kawasan'],
'jumlah_warga' => $jumlah,
'total_tanggungan' => (int)$r['total_tanggungan'],
]
];
}
// Rumah ibadah by agama
$byAgama = $pdo->query("SELECT agama, COUNT(*) as total FROM rumah_ibadah GROUP BY agama")->fetchAll();
// Kavling by status
$byStatus = $pdo->query("SELECT status_kepemilikan, COUNT(*) as total FROM kavling GROUP BY status_kepemilikan")->fetchAll();
sendSuccess([
'counts' => $counts,
'kawasan_merah' => $merahCount,
'choropleth' => ['type' => 'FeatureCollection', 'features' => $features],
'rumah_by_agama' => $byAgama,
'kavling_by_status' => $byStatus,
], 'Statistik OK');
+50
View File
@@ -0,0 +1,50 @@
<?php
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/../config/session.php';
startAppSession();
header('Content-Type: application/json');
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'user') {
http_response_code(401);
echo json_encode(['status' => 'error', 'message' => 'Hanya pengguna terdaftar yang dapat memberikan ulasan']);
exit;
}
$pdo = Database::getConnection();
$method = $_SERVER['REQUEST_METHOD'];
try {
if ($method === 'POST') {
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['fasilitas_tipe'], $input['fasilitas_id'], $input['rating'])) {
throw new Exception("Data ulasan tidak lengkap.");
}
$tipe = $input['fasilitas_tipe'];
if (!in_array($tipe, ['spbu', 'rumah_ibadah'])) throw new Exception("Tipe fasilitas tidak valid");
$fasilitas_id = (int)$input['fasilitas_id'];
$rating = (int)$input['rating'];
$komentar = trim($input['komentar'] ?? '');
if ($rating < 1 || $rating > 5) throw new Exception("Rating harus antara 1 sampai 5");
// Cek apakah sudah pernah mengulas
$check = $pdo->prepare("SELECT id FROM ulasan_fasilitas WHERE user_id = ? AND fasilitas_tipe = ? AND fasilitas_id = ?");
$check->execute([$_SESSION['user_id'], $tipe, $fasilitas_id]);
if ($check->fetch()) {
throw new Exception("Anda sudah memberikan ulasan untuk fasilitas ini.");
}
$stmt = $pdo->prepare("INSERT INTO ulasan_fasilitas (user_id, fasilitas_tipe, fasilitas_id, rating, komentar) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$_SESSION['user_id'], $tipe, $fasilitas_id, $rating, $komentar]);
echo json_encode(['status' => 'success', 'message' => 'Ulasan berhasil disimpan! Terima kasih atas partisipasi Anda.']);
} else {
throw new Exception("Method not allowed");
}
} catch (Exception $e) {
http_response_code(400);
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
}
+31
View File
@@ -0,0 +1,31 @@
<?php require_once __DIR__ . '/../config/db.php'; require_once __DIR__ . '/helpers.php';
$pdo = Database::getConnection(); $method = $_SERVER['REQUEST_METHOD'];
requireApiRole('admin');
switch ($method) {
case 'GET':
$stmt = $pdo->query("SELECT id,username,role,nama_lengkap,created_at FROM users ORDER BY id ASC");
sendSuccess($stmt->fetchAll(), 'Data Users'); break;
case 'POST':
$d=getInput();
if(empty($d['username'])||empty($d['password'])||empty($d['role'])) sendError('Data tidak lengkap');
$hash = password_hash($d['password'], PASSWORD_BCRYPT);
try {
$pdo->prepare("INSERT INTO users(username,password,role,nama_lengkap) VALUES(?,?,?,?)")->execute([$d['username'],$hash,$d['role'],$d['nama_lengkap']??'']);
sendSuccess(['id'=>$pdo->lastInsertId()],'User disimpan',201);
} catch(Exception $e) { sendError('Username sudah digunakan'); }
break;
case 'PUT':
$d=getInput(); $id=$_GET['id']??null; if(!$id) sendError('ID wajib');
if(!empty($d['password'])) {
$hash=password_hash($d['password'],PASSWORD_BCRYPT);
$pdo->prepare("UPDATE users SET username=?,password=?,role=?,nama_lengkap=? WHERE id=?")->execute([$d['username'],$hash,$d['role'],$d['nama_lengkap']??'',$id]);
} else {
$pdo->prepare("UPDATE users SET username=?,role=?,nama_lengkap=? WHERE id=?")->execute([$d['username'],$d['role'],$d['nama_lengkap']??'',$id]);
}
sendSuccess(null,'User diperbarui'); break;
case 'DELETE':
$id=$_GET['id']??null; if(!$id) sendError('ID wajib');
if($id==1) sendError('Admin utama tidak dapat dihapus');
$pdo->prepare("DELETE FROM users WHERE id=?")->execute([$id]); sendSuccess(null,'User dihapus'); break;
default: sendError('Method not allowed',405);
}
+26
View File
@@ -0,0 +1,26 @@
<?php require_once __DIR__ . '/../config/db.php'; require_once __DIR__ . '/helpers.php';
$pdo = Database::getConnection(); $method = $_SERVER['REQUEST_METHOD'];
requireAdminForMutation();
switch ($method) {
case 'GET':
$stmt = $pdo->query("SELECT id,nama_kk,penghasilan,jumlah_tanggungan,created_at,ST_AsGeoJSON(geom) as geojson FROM warga_miskin ORDER BY id DESC");
$features=[];
while($r=$stmt->fetch()) $features[]=['type'=>'Feature','geometry'=>json_decode($r['geojson']),'properties'=>['id'=>$r['id'],'nama_kk'=>$r['nama_kk'],'penghasilan'=>$r['penghasilan'],'jumlah_tanggungan'=>$r['jumlah_tanggungan'],'created_at'=>$r['created_at']]];
sendSuccess(['type'=>'FeatureCollection','features'=>$features],'Data Warga Miskin'); break;
case 'POST':
$d=getInput(); if(empty($d['nama_kk'])||empty($d['geometry'])) sendError('Data tidak lengkap');
$pdo->prepare("INSERT INTO warga_miskin(nama_kk,penghasilan,jumlah_tanggungan,geom) VALUES(?,?,?,ST_GeomFromGeoJSON(?))")->execute([$d['nama_kk'],$d['penghasilan']??0,$d['jumlah_tanggungan']??0,json_encode($d['geometry'])]);
sendSuccess(['id'=>$pdo->lastInsertId()],'Warga disimpan',201); break;
case 'PUT':
$d=getInput(); $id=$_GET['id']??null; if(!$id) sendError('ID wajib');
if(!empty($d['geometry'])){
$pdo->prepare("UPDATE warga_miskin SET geom=ST_GeomFromGeoJSON(?) WHERE id=?")->execute([json_encode($d['geometry']),$id]);
} else {
$pdo->prepare("UPDATE warga_miskin SET nama_kk=?,penghasilan=?,jumlah_tanggungan=? WHERE id=?")->execute([$d['nama_kk'],$d['penghasilan']??0,$d['jumlah_tanggungan']??0,$id]);
}
sendSuccess(null,'Warga diperbarui'); break;
case 'DELETE':
$id=$_GET['id']??null; if(!$id) sendError('ID wajib');
$pdo->prepare("DELETE FROM warga_miskin WHERE id=?")->execute([$id]); sendSuccess(null,'Warga dihapus'); break;
default: sendError('Method not allowed',405);
}