fix: update final code deployment
This commit is contained in:
@@ -2,6 +2,10 @@ FROM php:8.2-apache
|
||||
|
||||
RUN a2enmod rewrite
|
||||
|
||||
# The sub-projects connect via mysqli, which isn't bundled in the base image
|
||||
RUN docker-php-ext-install mysqli pdo_mysql \
|
||||
&& echo "date.timezone = Asia/Jakarta" > /usr/local/etc/php/conf.d/timezone.ini
|
||||
|
||||
COPY . /var/www/html/
|
||||
|
||||
RUN chown -R www-data:www-data /var/www/html \
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
FROM mysql:8.0
|
||||
|
||||
# Bake all three sub-project schemas + seed data into one database.
|
||||
# No table-name collisions across them, and config.php reads the DB name
|
||||
# from the DB_NAME env var, so a single shared database is fine.
|
||||
# Files in initdb.d run alphabetically against $MYSQL_DATABASE on first boot.
|
||||
COPY spbu/webgis.sql /docker-entrypoint-initdb.d/01_spbu.sql
|
||||
COPY parsiljalan/webgis2.sql /docker-entrypoint-initdb.d/02_jalantanah.sql
|
||||
COPY povertymap/gis_penduduk_miskin.sql /docker-entrypoint-initdb.d/03_miskin.sql
|
||||
@@ -0,0 +1,60 @@
|
||||
name: muthia-webgis
|
||||
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
image: muthia-webgis-app
|
||||
container_name: muthia-webgis-app
|
||||
ports:
|
||||
- "127.0.0.1:8089:80"
|
||||
environment:
|
||||
DB_HOST: db
|
||||
DB_USER: webgis_user
|
||||
DB_PASS: webgis_password
|
||||
DB_NAME: webgis_muthia
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
|
||||
db:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.db
|
||||
image: muthia-webgis-db
|
||||
container_name: muthia-webgis-db
|
||||
environment:
|
||||
MYSQL_DATABASE: webgis_muthia
|
||||
MYSQL_USER: webgis_user
|
||||
MYSQL_PASSWORD: webgis_password
|
||||
MYSQL_ROOT_PASSWORD: root_password
|
||||
expose:
|
||||
- "3306"
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -uroot -p$$MYSQL_ROOT_PASSWORD --silent"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
restart: unless-stopped
|
||||
|
||||
phpmyadmin:
|
||||
image: phpmyadmin:latest
|
||||
container_name: muthia-webgis-phpmyadmin
|
||||
ports:
|
||||
- "127.0.0.1:8090:80"
|
||||
environment:
|
||||
PMA_HOST: db
|
||||
PMA_PORT: 3306
|
||||
PMA_ABSOLUTE_URI: https://muthia.webgis-untan.xyz/db/
|
||||
UPLOAD_LIMIT: 64M
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
// Semua project di-deploy dalam satu folder — gunakan relative path
|
||||
$url_spbu = 'SIG_spbu/';
|
||||
$url_miskin = 'SIG_miskin/gis/';
|
||||
$url_jalantanah = 'SIG2_jalantanah/';
|
||||
$url_choropleth = 'Choropleth/ptk.html';
|
||||
$url_spbu = 'spbu/';
|
||||
$url_miskin = 'povertymap/';
|
||||
$url_jalantanah = 'parsiljalan/';
|
||||
$url_choropleth = 'choropleth/';
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
|
||||
@@ -15,12 +15,58 @@ function toGeoJsonPoint($lat, $lng) {
|
||||
return json_encode(['type' => 'Point', 'coordinates' => [(float)$lng, (float)$lat]]);
|
||||
}
|
||||
|
||||
// Deteksi POST yang melebihi post_max_size: PHP mengosongkan $_POST/$_FILES
|
||||
// padahal CONTENT_LENGTH > 0. Tanpa ini respons jadi kosong -> "Koneksi gagal!".
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST'
|
||||
&& empty($_POST) && empty($_FILES)
|
||||
&& (int)($_SERVER['CONTENT_LENGTH'] ?? 0) > 0) {
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
http_response_code(413);
|
||||
echo json_encode([
|
||||
'ok' => false,
|
||||
'msg' => 'Data terlalu besar (melebihi post_max_size=' . ini_get('post_max_size')
|
||||
. '). Kecilkan ukuran foto atau naikkan post_max_size.'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$action = $_GET['action'] ?? $_POST['action'] ?? null;
|
||||
if (!$action) return;
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
$a = $action;
|
||||
|
||||
if ($a === 'reverse') {
|
||||
$lat = (float)($_GET['lat'] ?? 0);
|
||||
$lon = (float)($_GET['lon'] ?? $_GET['lng'] ?? 0);
|
||||
if ($lat == 0 && $lon == 0) { echo json_encode(['error' => 'koordinat kosong']); exit; }
|
||||
$url = 'https://nominatim.openstreetmap.org/reverse?format=jsonv2&zoom=17&accept-language=id'
|
||||
. '&lat=' . urlencode($lat) . '&lon=' . urlencode($lon);
|
||||
// Nominatim mewajibkan User-Agent yang valid; browser tak bisa set ini, jadi diproxy dari server
|
||||
$ua = 'SIG2-JalanTanah/1.0 (kontak: webmaster@webgis-untan.xyz)';
|
||||
$body = false;
|
||||
if (function_exists('curl_init')) {
|
||||
$ch = curl_init($url);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_USERAGENT => $ua,
|
||||
CURLOPT_TIMEOUT => 8,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
]);
|
||||
$body = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
}
|
||||
if ($body === false) {
|
||||
$ctx = stream_context_create(['http' => [
|
||||
'header' => "User-Agent: $ua\r\n",
|
||||
'timeout' => 8,
|
||||
]]);
|
||||
$body = @file_get_contents($url, false, $ctx);
|
||||
}
|
||||
if ($body === false) { echo json_encode(['error' => 'gagal hubungi nominatim']); exit; }
|
||||
echo $body; exit;
|
||||
}
|
||||
|
||||
if ($a === 'search') {
|
||||
$q = '%' . $conn->real_escape_string($_GET['q'] ?? '') . '%';
|
||||
$tipe = $_GET['tipe'] ?? 'semua';
|
||||
@@ -250,11 +250,12 @@ function openRusakModal(latlng) {
|
||||
document.getElementById('rusak-ket').value = '';
|
||||
clearFoto();
|
||||
|
||||
fetch('https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=' + latlng.lat + '&lon=' + latlng.lng + '&zoom=17&accept-language=id')
|
||||
fetch('api.php?action=reverse&lat=' + latlng.lat + '&lon=' + latlng.lng)
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (geo) {
|
||||
var road = geo.address && (geo.address.road || geo.address.residential || geo.address.path || geo.address.pedestrian || geo.address.footway || '');
|
||||
document.getElementById('rusak-nama-jalan').value = road || '(Jalan tidak teridentifikasi)';
|
||||
var a = geo.address || {};
|
||||
var road = a.road || a.residential || a.path || a.pedestrian || a.footway || a.track || a.cycleway || a.neighbourhood || a.hamlet || a.village || a.suburb || '';
|
||||
document.getElementById('rusak-nama-jalan').value = road || geo.display_name || '(Jalan tidak teridentifikasi)';
|
||||
})
|
||||
.catch(function () {
|
||||
document.getElementById('rusak-nama-jalan').value = '(Gagal deteksi nama jalan)';
|
||||
@@ -327,10 +328,11 @@ function handleFoto(input) {
|
||||
badge.textContent = 'GPS dari Foto';
|
||||
}
|
||||
|
||||
fetch('https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=' + latDec + '&lon=' + lonDec + '&zoom=17&accept-language=id')
|
||||
fetch('api.php?action=reverse&lat=' + latDec + '&lon=' + lonDec)
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (geo) {
|
||||
var road = geo.address && (geo.address.road || geo.address.residential || geo.address.path || geo.address.pedestrian || geo.address.footway || '');
|
||||
var a = geo.address || {};
|
||||
var road = a.road || a.residential || a.path || a.pedestrian || a.footway || a.track || a.cycleway || a.neighbourhood || a.hamlet || a.village || a.suburb || '';
|
||||
document.getElementById('rusak-nama-jalan').value = road || geo.display_name || '(Jalan tidak teridentifikasi)';
|
||||
});
|
||||
}
|
||||
@@ -339,12 +341,32 @@ function handleFoto(input) {
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
// Kompres & resize foto agar payload kecil (hindari post_max_size & batas kolom DB)
|
||||
var img = new Image();
|
||||
img.onload = function () {
|
||||
var maxDim = 1280;
|
||||
var w = img.width, h = img.height;
|
||||
if (w > h && w > maxDim) { h = Math.round(h * maxDim / w); w = maxDim; }
|
||||
else if (h >= w && h > maxDim) { w = Math.round(w * maxDim / h); h = maxDim; }
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = w; canvas.height = h;
|
||||
canvas.getContext('2d').drawImage(img, 0, 0, w, h);
|
||||
fotoBase64 = canvas.toDataURL('image/jpeg', 0.7);
|
||||
var preview = document.getElementById('photo-preview');
|
||||
preview.src = fotoBase64;
|
||||
preview.style.display = 'block';
|
||||
document.getElementById('foto-clear-btn').style.display = 'flex';
|
||||
};
|
||||
img.onerror = function () {
|
||||
// Fallback bila gambar tak bisa di-decode (mis. format tak didukung canvas)
|
||||
fotoBase64 = e.target.result;
|
||||
var preview = document.getElementById('photo-preview');
|
||||
preview.src = fotoBase64;
|
||||
preview.style.display = 'block';
|
||||
document.getElementById('foto-clear-btn').style.display = 'flex';
|
||||
};
|
||||
img.src = e.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
@@ -381,27 +403,40 @@ function saveRusak() {
|
||||
formData.append('foto', fotoBase64);
|
||||
|
||||
fetch('api.php', { method: 'POST', body: formData })
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (r) {
|
||||
return r.text().then(function (txt) {
|
||||
var res;
|
||||
try { res = JSON.parse(txt); }
|
||||
catch (e) {
|
||||
// Respons bukan JSON: tampilkan status & potongan isi supaya jelas penyebabnya
|
||||
var info = txt.trim() ? txt.trim().slice(0, 200) : '(respons kosong)';
|
||||
throw new Error('HTTP ' + r.status + ' — ' + info);
|
||||
}
|
||||
return res;
|
||||
});
|
||||
})
|
||||
.then(function (res) {
|
||||
btn.textContent = 'Simpan Titik';
|
||||
btn.disabled = false;
|
||||
if (res.ok) {
|
||||
showToast('Titik jalan rusak disimpan!', 'success');
|
||||
var savedFoto = fotoBase64; // simpan dulu: closeRusakModal() me-reset fotoBase64
|
||||
closeRusakModal();
|
||||
var id = res.id;
|
||||
var nama = res.nama || pelapor;
|
||||
var layer = makeRusakLayer(id, nama, tanggal, lat, lng, ket, fotoBase64, 'recent', false);
|
||||
var layer = makeRusakLayer(id, nama, tanggal, lat, lng, ket, savedFoto, 'recent', false);
|
||||
rusakLayers[id] = layer;
|
||||
rusakData[id] = { id: id, nama: nama, tgl: tanggal, lat: lat, lng: lng, ket: ket, foto: fotoBase64, age: 'recent', recurring: false };
|
||||
rusakData[id] = { id: id, nama: nama, tgl: tanggal, lat: lat, lng: lng, ket: ket, foto: savedFoto, age: 'recent', recurring: false };
|
||||
if (res.tr !== undefined) updateStats(res);
|
||||
cancelDraw();
|
||||
} else {
|
||||
showToast('Gagal: ' + (res.msg || 'unknown'), 'error');
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
.catch(function (err) {
|
||||
btn.textContent = 'Simpan Titik';
|
||||
btn.disabled = false;
|
||||
showToast('Koneksi gagal!', 'error');
|
||||
showToast('Gagal simpan: ' + (err && err.message ? err.message : 'koneksi gagal'), 'error');
|
||||
console.error('saveRusak error:', err);
|
||||
});
|
||||
}
|
||||
@@ -1080,7 +1080,7 @@ function exitFloatingGeoEdit(save) {
|
||||
}
|
||||
}
|
||||
|
||||
function spHandleFoto(input){var f=input.files[0];if(!f)return;if(f.size>5*1024*1024){showToast('Foto maks 5MB!','error');return;}var r=new FileReader();r.onload=function(e){spFotoBase64=e.target.result;el('sp-foto-preview').src=spFotoBase64;el('sp-foto-preview').style.display='block';el('sp-foto-clear').style.display='flex';};r.readAsDataURL(f);}
|
||||
function spHandleFoto(input){var f=input.files[0];if(!f)return;if(f.size>5*1024*1024){showToast('Foto maks 5MB!','error');return;}var r=new FileReader();r.onload=function(e){var img=new Image();img.onload=function(){var maxDim=1280,w=img.width,h=img.height;if(w>h&&w>maxDim){h=Math.round(h*maxDim/w);w=maxDim;}else if(h>=w&&h>maxDim){w=Math.round(w*maxDim/h);h=maxDim;}var c=document.createElement('canvas');c.width=w;c.height=h;c.getContext('2d').drawImage(img,0,0,w,h);spFotoBase64=c.toDataURL('image/jpeg',0.7);el('sp-foto-preview').src=spFotoBase64;el('sp-foto-preview').style.display='block';el('sp-foto-clear').style.display='flex';};img.onerror=function(){spFotoBase64=e.target.result;el('sp-foto-preview').src=spFotoBase64;el('sp-foto-preview').style.display='block';el('sp-foto-clear').style.display='flex';};img.src=e.target.result;};r.readAsDataURL(f);}
|
||||
function spClearFoto(){spFotoBase64='';el('sp-foto-preview').style.display='none';el('sp-foto-file').value='';el('sp-foto-clear').style.display='none';}
|
||||
|
||||
/* ══ GEOMETRY EDIT ═══════════════════════════════════ */
|
||||
@@ -1410,7 +1410,7 @@ if (document.getElementById('lnav-list')) {
|
||||
}
|
||||
</script>
|
||||
<?php if ($mode === 'input'): ?>
|
||||
<script src="assets/jalan-input.js"></script>
|
||||
<script src="assets/jalan-input.js?v=<?= @filemtime(__DIR__ . '/assets/jalan-input.js') ?: time() ?>"></script>
|
||||
<?php endif; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -56,7 +56,7 @@ CREATE TABLE `jalan_rusak` (
|
||||
`tanggal` date NOT NULL,
|
||||
`latitude` double NOT NULL DEFAULT 0,
|
||||
`longitude` double NOT NULL DEFAULT 0,
|
||||
`foto` text DEFAULT NULL COMMENT 'base64 atau path file foto',
|
||||
`foto` mediumtext DEFAULT NULL COMMENT 'base64 atau path file foto',
|
||||
`keterangan` text DEFAULT NULL,
|
||||
`koordinat` text NOT NULL COMMENT 'GeoJSON Point string',
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp()
|
||||
@@ -138,7 +138,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
<body>
|
||||
|
||||
<header class="login-header">
|
||||
<a href="../../index.php">
|
||||
<a href="../index.php">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>
|
||||
Portal WebGIS
|
||||
</a>
|
||||
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 109 KiB |
Reference in New Issue
Block a user