feat : first commit
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
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
|
||||
};
|
||||
Reference in New Issue
Block a user