Fix: Convert 03PovertyMapping from submodule to regular folder

This commit is contained in:
cindy
2026-06-10 19:36:55 +07:00
parent 1a9534757e
commit aed321d490
42 changed files with 11130 additions and 1 deletions
+94
View File
@@ -0,0 +1,94 @@
<?php
// ============================================================
// config/bootstrap.php — with session support
// ============================================================
declare(strict_types=1);
require_once __DIR__ . '/config.php';
require_once __DIR__ . '/database.php';
require_once __DIR__ . '/../middleware/Response.php';
require_once __DIR__ . '/../middleware/Validator.php';
require_once __DIR__ . '/../models/AuditLog.php';
require_once __DIR__ . '/../models/PovertyCalculator.php';
// ---- Error handling ----------------------------------------
if (APP_DEBUG) {
error_reporting(E_ALL);
ini_set('display_errors', '1');
} else {
error_reporting(0);
ini_set('display_errors', '0');
}
set_exception_handler(function (Throwable $e) {
$message = APP_DEBUG ? $e->getMessage() : 'Internal server error';
Response::error($message, 500);
});
// ---- CORS & Security Headers --------------------------------
header('Content-Type: application/json; charset=utf-8');
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
if (APP_ENV === 'development') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
}
$requestMethod = $_SERVER['REQUEST_METHOD'] ?? '';
if ($requestMethod === 'OPTIONS') {
http_response_code(204);
exit;
}
ob_start();
// ---- Session bootstrap (shared by all APIs) -----------------
if (session_status() === PHP_SESSION_NONE) {
session_name('webgis_sess');
session_set_cookie_params([
'lifetime' => 0, // until browser closes
'path' => '/',
'secure' => false, // set true if using HTTPS
'httponly' => true,
'samesite' => 'Lax',
]);
session_start();
}
// ---- Session helper functions --------------------------------
/** Return current logged-in user array or null */
function currentUser(): ?array
{
if (empty($_SESSION['user_id']) || empty($_SESSION['role'])) {
return null;
}
return [
'id' => (int)$_SESSION['user_id'],
'name' => $_SESSION['name'] ?? '',
'email' => $_SESSION['email'] ?? '',
'role' => $_SESSION['role'],
];
}
/** Require authentication — returns user or sends 401 */
function requireAuth(): array
{
$user = currentUser();
if (!$user) {
Response::error('Silakan login terlebih dahulu.', 401);
}
return $user;
}
/** Require admin role — returns user or sends 403 */
function requireAdmin(): array
{
$user = requireAuth();
if ($user['role'] !== 'admin') {
Response::error('Akses ditolak. Hanya admin yang dapat melakukan tindakan ini.', 403);
}
return $user;
}
+28
View File
@@ -0,0 +1,28 @@
<?php
// ============================================================
// config/config.php
// ============================================================
declare(strict_types=1);
// ---- Environment -------------------------------------------
// SET TO 'development' TEMPORARILY TO SEE ERROR DETAILS
define('APP_ENV', getenv('APP_ENV') ?: 'development');
define('APP_DEBUG', true); // <--- SET TRUE TO SEE ERRORS
define('APP_NAME', 'WebGIS Poverty Mapping v2');
define('BASE_URL', getenv('BASE_URL') ?: 'http://localhost/webgis-v2');
// ---- Database ----------------------------------------------
define('DB_HOST', getenv('DB_HOST') ?: 'localhost');
define('DB_PORT', getenv('DB_PORT') ?: '3306');
define('DB_NAME', getenv('DB_NAME') ?: 'poverty_mapping');
define('DB_USER', getenv('DB_USER') ?: 'root');
define('DB_PASS', getenv('DB_PASS') ?: '');
define('DB_CHARSET', 'utf8mb4');
// ---- Pagination --------------------------------------------
define('PAGE_SIZE', 500);
// ---- Poverty scoring thresholds ----------------------------
define('POVERTY_THRESHOLD_NEAR', 30);
define('POVERTY_THRESHOLD_POOR', 55);
define('POVERTY_THRESHOLD_SEVERE', 75);
+32
View File
@@ -0,0 +1,32 @@
<?php
// ============================================================
// config/database.php — PDO singleton
// ============================================================
declare(strict_types=1);
require_once __DIR__ . '/config.php';
class Database
{
private static ?PDO $instance = null;
public static function get(): PDO
{
if (self::$instance === null) {
$dsn = sprintf(
'mysql:host=%s;port=%s;dbname=%s;charset=%s',
DB_HOST, DB_PORT, DB_NAME, DB_CHARSET
);
self::$instance = new PDO($dsn, DB_USER, DB_PASS, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
}
return self::$instance;
}
/** Prevent cloning / serialisation */
private function __clone() {}
public function __wakeup(): never { throw new \Exception('Cannot unserialize singleton.'); }
}