Files
UAS-SIG/controllers/survey_controller.js
T
2026-06-03 20:11:40 +07:00

148 lines
6.5 KiB
JavaScript

const db = require('../config/database');
// Mengambil data status bantuan warga berdasarkan pencarian NIK dari halaman publik
const cek_status_nik = (req, res) => {
const nik_warga = req.params.nik;
// Praktik keamanan: Memastikan input NIK murni berupa 16 digit angka untuk mencegah manipulasi query
if (!/^\d{16}$/.test(nik_warga)) {
return res.status(400).json({ error: 'Format NIK tidak valid.' });
}
const kueri_pencarian = `SELECT nik, nama_kk, status_validasi, lat, lng FROM MUSTAHIK WHERE nik = ?`;
// Baris kompleks: Penggunaan parameter '?' (parameterized query) memastikan bahwa mesin SQLite menganggap variabel 'nik_warga' murni sebagai nilai data, bukan sebagai perintah yang bisa dieksekusi, sehingga secara absolut mencegah serangan SQL Injection.
db.get(kueri_pencarian, [nik_warga], (error_sistem, baris_data) => {
if (error_sistem) {
console.error('Sistem gagal membaca tabel:', error_sistem.message);
return res.status(500).json({ error: 'Terjadi kegagalan server internal.' });
}
if (!baris_data) {
return res.status(404).json({ error: 'Data tidak ditemukan.' });
}
res.status(200).json(baris_data);
});
};
// Mengontrol alur penerimaan data survei lapangan secara transaksional
const submit_survey_data = async (req, res) => {
try {
const {
nik,
nama_kk,
no_kk,
jumlah_tanggungan,
lat,
lng,
indikator_bps
} = req.body;
// Praktik keamanan: Validasi input dasar untuk mencegah insersi data kosong (null pointer exception)
if (!nik || !nama_kk || !lat || !lng || !indikator_bps) {
return res.status(400).json({ error: 'Payload data survei tidak lengkap dari klien.' });
}
// Memulai transaksi basis data untuk menjaga integritas penyimpanan parsial
db.serialize(() => {
db.run('BEGIN TRANSACTION');
// 1. Menyimpan data identitas ke tabel MUSTAHIK
const kueri_mustahik = `INSERT INTO MUSTAHIK (nik, nama_kk, no_kk, jumlah_tanggungan, lat, lng) VALUES (?, ?, ?, ?, ?, ?)`;
db.run(kueri_mustahik, [nik, nama_kk, no_kk, jumlah_tanggungan, lat, lng], function(error_mustahik) {
// Baris kompleks: Jika terjadi kegagalan pada tahap pertama ini, perintah ROLLBACK membatalkan status transaksi secara keseluruhan, mencegah adanya data terisolasi di memori.
if (error_mustahik) {
db.run('ROLLBACK');
console.error('Gagal menyimpan DML MUSTAHIK:', error_mustahik.message);
return res.status(500).json({ error: 'Gagal menyimpan data identitas warga, NIK mungkin sudah terdaftar.' });
}
// Mengekstrak ID yang otomatis digenerate (Auto Increment) untuk digunakan sebagai Foreign Key
const id_mustahik_baru = this.lastID;
const {
luas_lantai_per_kapita,
material_lantai,
material_dinding,
fasilitas_sanitasi,
sumber_air_minum,
sumber_penerangan,
pekerjaan_utama,
pendapatan_bulanan,
frekuensi_makan,
kepemilikan_aset
} = indikator_bps;
// 2. Menyimpan 10 parameter kondisi ke tabel INDIKATOR_BPS
const kueri_indikator = `
INSERT INTO INDIKATOR_BPS (
id_mustahik, luas_lantai_per_kapita, material_lantai, material_dinding,
fasilitas_sanitasi, sumber_air_minum, sumber_penerangan,
pekerjaan_utama, pendapatan_bulanan, frekuensi_makan, kepemilikan_aset
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`;
db.run(kueri_indikator, [
id_mustahik_baru,
luas_lantai_per_kapita,
material_lantai,
material_dinding,
fasilitas_sanitasi,
sumber_air_minum,
sumber_penerangan,
pekerjaan_utama,
pendapatan_bulanan,
frekuensi_makan,
kepemilikan_aset
], function(error_indikator) {
if (error_indikator) {
db.run('ROLLBACK');
console.error('Gagal menyimpan DML INDIKATOR_BPS:', error_indikator.message);
return res.status(500).json({ error: 'Gagal merekam indikator ekonomi BPS.' });
}
// Secara permanen menerapkan semua kueri yang tertunda ke dalam file SQLite
db.run('COMMIT');
res.status(201).json({
message: 'Data survei kriteria BPS berhasil disubmit',
id_mustahik: id_mustahik_baru
});
});
});
});
} catch (error_sistem) {
console.error('Kesalahan eksekusi sistem:', error_sistem);
res.status(500).json({ error: 'Kegagalan pemrosesan internal server.' });
}
};
// Menarik agregasi data statistik untuk ditampilkan di halaman publik
const ambil_statistik_publik = (req, res) => {
/* Baris kompleks: Kueri ini menggunakan fungsi agregasi COUNT dikombinasikan dengan ekspresi
kondisional CASE WHEN. Pendekatan ini sangat optimal karena mesin SQLite hanya perlu
memindai tabel MUSTAHIK satu kali untuk mendapatkan dua nilai hitungan yang berbeda,
sehingga menghemat alokasi memori dan waktu eksekusi server backend. */
const kueri_statistik = `
SELECT
COUNT(CASE WHEN status_validasi = 'Verified' THEN 1 END) AS terverifikasi,
COUNT(CASE WHEN status_validasi = 'Pending' THEN 1 END) AS diproses
FROM MUSTAHIK
`;
db.get(kueri_statistik, [], (error_sql, baris_data) => {
if (error_sql) {
console.error('Gagal menarik agregasi statistik:', error_sql.message);
return res.status(500).json({ error: 'Gagal memuat statistik.' });
}
res.status(200).json(baris_data);
});
};
// Mengekspor semua fungsi agar dapat diakses oleh file router
module.exports = {
cek_status_nik,
submit_survey_data,
ambil_statistik_publik
};