Deploy WebGIS 01-05 dengan Docker
This commit is contained in:
+314
@@ -0,0 +1,314 @@
|
||||
<?php
|
||||
/**
|
||||
* auth.php
|
||||
* Fungsi session, role pengguna, response JSON, validasi umum,
|
||||
* prepared statement helper, perhitungan Haversine, dan sinkronisasi area.
|
||||
*/
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/koneksi.php';
|
||||
|
||||
function json_response($status = 'ok', $message = '', $data = [], $http_code = 200) {
|
||||
http_response_code($http_code);
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo json_encode([
|
||||
'status' => $status,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
function require_post() {
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
json_response('err', 'Method harus POST.', [], 405);
|
||||
}
|
||||
}
|
||||
|
||||
function is_logged_in() {
|
||||
return isset($_SESSION['user_id'], $_SESSION['role']);
|
||||
}
|
||||
|
||||
function require_login($json = false) {
|
||||
if (!is_logged_in()) {
|
||||
if ($json) json_response('err', 'Silakan login terlebih dahulu.', [], 401);
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
function current_user() {
|
||||
global $koneksi;
|
||||
if (!is_logged_in()) return null;
|
||||
$id = (int) $_SESSION['user_id'];
|
||||
$stmt = $koneksi->prepare("SELECT id, nama, username, role, status_akun FROM users WHERE id=? LIMIT 1");
|
||||
$stmt->bind_param('i', $id);
|
||||
$stmt->execute();
|
||||
$res = $stmt->get_result();
|
||||
return $res->fetch_assoc();
|
||||
}
|
||||
|
||||
function has_role($roles) {
|
||||
if (!is_array($roles)) $roles = [$roles];
|
||||
return is_logged_in() && in_array($_SESSION['role'], $roles, true);
|
||||
}
|
||||
|
||||
function require_role($roles, $json = false) {
|
||||
if (!has_role($roles)) {
|
||||
if ($json) json_response('err', 'Akses ditolak. Role tidak sesuai.', [], 403);
|
||||
http_response_code(403);
|
||||
echo '<h2>403 - Akses ditolak</h2>';
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
function post($key, $default = '') {
|
||||
return isset($_POST[$key]) ? trim((string) $_POST[$key]) : $default;
|
||||
}
|
||||
|
||||
function getv($key, $default = '') {
|
||||
return isset($_GET[$key]) ? trim((string) $_GET[$key]) : $default;
|
||||
}
|
||||
|
||||
function clean_text($str, $max = 255) {
|
||||
$str = trim((string) $str);
|
||||
if (mb_strlen($str) > $max) $str = mb_substr($str, 0, $max);
|
||||
return $str;
|
||||
}
|
||||
|
||||
function valid_enum($value, $allowed) {
|
||||
return in_array($value, $allowed, true);
|
||||
}
|
||||
|
||||
function valid_latlng($lat, $lng) {
|
||||
return is_numeric($lat) && is_numeric($lng) && $lat >= -90 && $lat <= 90 && $lng >= -180 && $lng <= 180;
|
||||
}
|
||||
|
||||
function haversine_meter($lat1, $lon1, $lat2, $lon2) {
|
||||
$R = 6371000; // meter
|
||||
$dLat = deg2rad($lat2 - $lat1);
|
||||
$dLon = deg2rad($lon2 - $lon1);
|
||||
$a = sin($dLat / 2) * sin($dLat / 2) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLon / 2) * sin($dLon / 2);
|
||||
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
|
||||
return $R * $c;
|
||||
}
|
||||
|
||||
function stmt_bind($stmt, $types, $params) {
|
||||
if ($types === '' || empty($params)) return true;
|
||||
$refs = [];
|
||||
$refs[] = $types;
|
||||
foreach ($params as $k => $v) {
|
||||
$refs[] = &$params[$k];
|
||||
}
|
||||
return call_user_func_array([$stmt, 'bind_param'], $refs);
|
||||
}
|
||||
|
||||
function fetch_all_stmt($stmt) {
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$rows = [];
|
||||
while ($row = $result->fetch_assoc()) $rows[] = $row;
|
||||
return $rows;
|
||||
}
|
||||
|
||||
function build_in_condition($column, $values, &$types, &$params) {
|
||||
$ids = [];
|
||||
foreach ((array)$values as $v) {
|
||||
$iv = (int)$v;
|
||||
if ($iv > 0) $ids[] = $iv;
|
||||
}
|
||||
$ids = array_values(array_unique($ids));
|
||||
if (empty($ids)) return '1=0';
|
||||
$placeholders = implode(',', array_fill(0, count($ids), '?'));
|
||||
$types .= str_repeat('i', count($ids));
|
||||
foreach ($ids as $id) $params[] = $id;
|
||||
return "$column IN ($placeholders)";
|
||||
}
|
||||
|
||||
function get_admin_rumah_ibadah_list($user_id = null, $only_diterima = true) {
|
||||
global $koneksi;
|
||||
if ($user_id === null) $user_id = (int) $_SESSION['user_id'];
|
||||
$sql = "SELECT * FROM rumah_ibadah WHERE user_id=? AND COALESCE(status_hapus,'normal')<>'disetujui'";
|
||||
if ($only_diterima) $sql .= " AND status_pengajuan='diterima'";
|
||||
$sql .= " ORDER BY id ASC";
|
||||
$stmt = $koneksi->prepare($sql);
|
||||
$stmt->bind_param('i', $user_id);
|
||||
return fetch_all_stmt($stmt);
|
||||
}
|
||||
|
||||
function get_admin_rumah_ibadah_ids($user_id = null, $only_diterima = true) {
|
||||
$rows = get_admin_rumah_ibadah_list($user_id, $only_diterima);
|
||||
return array_map('intval', array_column($rows, 'id'));
|
||||
}
|
||||
|
||||
function get_admin_rumah_ibadah($user_id = null) {
|
||||
// Dipertahankan untuk kompatibilitas lama. Untuk logic baru, pakai get_admin_rumah_ibadah_list()/ids().
|
||||
$rows = get_admin_rumah_ibadah_list($user_id, true);
|
||||
return $rows[0] ?? null;
|
||||
}
|
||||
|
||||
function is_admin_rumah_ibadah_id($rumah_ibadah_id, $user_id = null, $only_diterima = true) {
|
||||
if ($user_id === null) $user_id = (int) $_SESSION['user_id'];
|
||||
$ids = get_admin_rumah_ibadah_ids($user_id, $only_diterima);
|
||||
return in_array((int)$rumah_ibadah_id, $ids, true);
|
||||
}
|
||||
|
||||
function get_nearest_rumah_ibadah($lat, $lng, $max_meter = 300, $admin_user_id = null) {
|
||||
global $koneksi;
|
||||
$rows = [];
|
||||
if ($admin_user_id !== null) {
|
||||
$stmt = $koneksi->prepare("SELECT * FROM rumah_ibadah WHERE user_id=? AND status_pengajuan='diterima' AND COALESCE(status_hapus,'normal')<>'disetujui'");
|
||||
$admin_user_id = (int)$admin_user_id;
|
||||
$stmt->bind_param('i', $admin_user_id);
|
||||
$rumahRows = fetch_all_stmt($stmt);
|
||||
} else {
|
||||
$rumahRows = [];
|
||||
$res = $koneksi->query("SELECT * FROM rumah_ibadah WHERE status_pengajuan='diterima' AND COALESCE(status_hapus,'normal')<>'disetujui'");
|
||||
while ($row = $res->fetch_assoc()) $rumahRows[] = $row;
|
||||
}
|
||||
|
||||
foreach ($rumahRows as $row) {
|
||||
$jarak = haversine_meter((float) $lat, (float) $lng, (float) $row['latitude'], (float) $row['longitude']);
|
||||
if ($jarak <= $max_meter) {
|
||||
$row['jarak_meter'] = round($jarak, 2);
|
||||
$rows[] = $row;
|
||||
}
|
||||
}
|
||||
usort($rows, fn($a, $b) => $a['jarak_meter'] <=> $b['jarak_meter']);
|
||||
return $rows[0] ?? null;
|
||||
}
|
||||
|
||||
function get_penerima_by_id($id) {
|
||||
global $koneksi;
|
||||
$stmt = $koneksi->prepare("SELECT pb.*, ri.nama_rumah_ibadah, ri.user_id AS admin_rumah_user_id, ri.latitude AS ri_latitude, ri.longitude AS ri_longitude FROM penerima_bantuan pb LEFT JOIN rumah_ibadah ri ON ri.id=pb.rumah_ibadah_id WHERE pb.id=? LIMIT 1");
|
||||
$stmt->bind_param('i', $id);
|
||||
$stmt->execute();
|
||||
return $stmt->get_result()->fetch_assoc();
|
||||
}
|
||||
|
||||
function get_rumah_ibadah_by_id($id) {
|
||||
global $koneksi;
|
||||
$stmt = $koneksi->prepare("SELECT ri.*, u.nama AS nama_admin, u.username AS username_admin FROM rumah_ibadah ri LEFT JOIN users u ON u.id=ri.user_id WHERE ri.id=? LIMIT 1");
|
||||
$stmt->bind_param('i', $id);
|
||||
$stmt->execute();
|
||||
return $stmt->get_result()->fetch_assoc();
|
||||
}
|
||||
|
||||
function can_manage_rumah_ibadah($rumah) {
|
||||
if (!$rumah || !is_logged_in()) return false;
|
||||
if ($_SESSION['role'] === 'super_admin') return true;
|
||||
if ($_SESSION['role'] === 'admin_rumah_ibadah') {
|
||||
return (int)$rumah['user_id'] === (int)$_SESSION['user_id'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function can_manage_penerima($penerima) {
|
||||
if (!$penerima || !is_logged_in()) return false;
|
||||
if ($_SESSION['role'] === 'super_admin') return true;
|
||||
if ($_SESSION['role'] === 'penerima' && (int) $penerima['user_id'] === (int) $_SESSION['user_id']) return true;
|
||||
if ($_SESSION['role'] === 'admin_rumah_ibadah') {
|
||||
return !empty($penerima['rumah_ibadah_id']) && is_admin_rumah_ibadah_id((int)$penerima['rumah_ibadah_id'], null, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function insert_riwayat_status($penerima_id, $status_lama, $status_baru, $catatan) {
|
||||
global $koneksi;
|
||||
$uid = (int) $_SESSION['user_id'];
|
||||
$stmt = $koneksi->prepare("INSERT INTO riwayat_status (penerima_id, user_id, status_lama, status_baru, catatan) VALUES (?,?,?,?,?)");
|
||||
$stmt->bind_param('iisss', $penerima_id, $uid, $status_lama, $status_baru, $catatan);
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
function get_user_by_username_role($username, $roles) {
|
||||
global $koneksi;
|
||||
if (!is_array($roles)) $roles = [$roles];
|
||||
$username = clean_text($username, 50);
|
||||
if ($username === '') return null;
|
||||
$placeholders = implode(',', array_fill(0, count($roles), '?'));
|
||||
$types = 's' . str_repeat('s', count($roles));
|
||||
$params = array_merge([$username], $roles);
|
||||
$stmt = $koneksi->prepare("SELECT id, nama, username, role, status_akun FROM users WHERE username=? AND role IN ($placeholders) AND status_akun='aktif' LIMIT 1");
|
||||
stmt_bind($stmt, $types, $params);
|
||||
$stmt->execute();
|
||||
return $stmt->get_result()->fetch_assoc();
|
||||
}
|
||||
|
||||
function has_active_penerima_pin($user_id, $exclude_penerima_id = 0) {
|
||||
global $koneksi;
|
||||
$user_id = (int)$user_id;
|
||||
$exclude_penerima_id = (int)$exclude_penerima_id;
|
||||
if ($user_id <= 0) return false;
|
||||
$sql = "SELECT id FROM penerima_bantuan
|
||||
WHERE user_id=?
|
||||
AND status_pengajuan IN ('menunggu','diterima')
|
||||
AND COALESCE(status_hapus,'normal')<>'disetujui'";
|
||||
$types = 'i';
|
||||
$params = [$user_id];
|
||||
if ($exclude_penerima_id > 0) {
|
||||
$sql .= " AND id<>?";
|
||||
$types .= 'i';
|
||||
$params[] = $exclude_penerima_id;
|
||||
}
|
||||
$sql .= " LIMIT 1";
|
||||
$stmt = $koneksi->prepare($sql);
|
||||
stmt_bind($stmt, $types, $params);
|
||||
$stmt->execute();
|
||||
return (bool)$stmt->get_result()->fetch_assoc();
|
||||
}
|
||||
|
||||
function sync_single_penerima_area($penerima_id) {
|
||||
global $koneksi;
|
||||
$penerima_id = (int)$penerima_id;
|
||||
$stmt = $koneksi->prepare("SELECT id, latitude, longitude FROM penerima_bantuan WHERE id=? AND status_pengajuan IN ('menunggu','diterima') AND COALESCE(status_hapus,'normal')<>'disetujui' LIMIT 1");
|
||||
$stmt->bind_param('i', $penerima_id);
|
||||
$stmt->execute();
|
||||
$pb = $stmt->get_result()->fetch_assoc();
|
||||
if (!$pb) return false;
|
||||
|
||||
$nearest = get_nearest_rumah_ibadah((float)$pb['latitude'], (float)$pb['longitude'], 300);
|
||||
if ($nearest) {
|
||||
$riId = (int)$nearest['id'];
|
||||
$jarak = (float)$nearest['jarak_meter'];
|
||||
$stmtUp = $koneksi->prepare("UPDATE penerima_bantuan SET rumah_ibadah_id=?, jarak_meter=? WHERE id=?");
|
||||
$stmtUp->bind_param('idi', $riId, $jarak, $penerima_id);
|
||||
} else {
|
||||
$stmtUp = $koneksi->prepare("UPDATE penerima_bantuan SET rumah_ibadah_id=NULL, jarak_meter=NULL WHERE id=?");
|
||||
$stmtUp->bind_param('i', $penerima_id);
|
||||
}
|
||||
return $stmtUp->execute();
|
||||
}
|
||||
|
||||
function sync_all_penerima_area() {
|
||||
global $koneksi;
|
||||
$ids = [];
|
||||
$res = $koneksi->query("SELECT id FROM penerima_bantuan WHERE status_pengajuan IN ('menunggu','diterima') AND COALESCE(status_hapus,'normal')<>'disetujui'");
|
||||
while ($row = $res->fetch_assoc()) $ids[] = (int)$row['id'];
|
||||
$updated = 0;
|
||||
foreach ($ids as $id) {
|
||||
if (sync_single_penerima_area($id)) $updated++;
|
||||
}
|
||||
return $updated;
|
||||
}
|
||||
|
||||
function sync_penerima_area_by_rumah_ibadah($rumah_ibadah_id) {
|
||||
// Tetap menerima parameter lama, tetapi sinkronisasi dihitung ulang secara global agar radius beririsan memilih RI terdekat.
|
||||
return sync_all_penerima_area();
|
||||
}
|
||||
|
||||
function detach_penerima_from_rumah_ibadah($rumah_ibadah_id) {
|
||||
global $koneksi;
|
||||
$rumah_ibadah_id = (int) $rumah_ibadah_id;
|
||||
$stmt = $koneksi->prepare("UPDATE penerima_bantuan SET rumah_ibadah_id=NULL, jarak_meter=NULL WHERE rumah_ibadah_id=? AND status_pengajuan IN ('menunggu','diterima')");
|
||||
$stmt->bind_param('i', $rumah_ibadah_id);
|
||||
$stmt->execute();
|
||||
$affected = $stmt->affected_rows;
|
||||
// Setelah dilepas, cari ulang rumah ibadah aktif terdekat lain jika ada.
|
||||
sync_all_penerima_area();
|
||||
return $affected;
|
||||
}
|
||||
|
||||
?>
|
||||
Reference in New Issue
Block a user