Skip to content

feat: tambahkan parameter identitas openkab#1007

Open
pandigresik wants to merge 7 commits intorilis-devfrom
feat/set_identitas_openkab
Open

feat: tambahkan parameter identitas openkab#1007
pandigresik wants to merge 7 commits intorilis-devfrom
feat/set_identitas_openkab

Conversation

@pandigresik
Copy link
Copy Markdown
Contributor

@pandigresik pandigresik commented Apr 21, 2026

Pull Request: Set Identitas OpenKab untuk API-Database-Gabungan

Deskripsi

Pull request ini menambahkan fitur identitas OpenKab yang memungkinkan aplikasi untuk mengirimkan kode kabupaten secara otomatis ke setiap request AJAX. Fitur ini penting untuk integrasi API-Database-Gabungan agar data yang ditampilkan sesuai dengan kabupaten yang sedang aktif.

Ringkasan Perubahan

File Perubahan
.gitignore Menambahkan /template_ai/
resources/views/layouts/presisi/index.blade.php Menambahkan meta tag identitas-openkab
resources/views/layouts/web.blade.php Menambahkan meta tag identitas-openkab
resources/views/layouts/presisi/partials/javascript.blade.php AJAX setup dengan parameter injection
resources/js/web.js AJAX setup untuk frontend (Vite build)
public/build-web/manifest.json Updated asset hashes
resources/views/presisi/statistik/*.blade.php 10 file statistik updated
resources/views/presisi/wilayah/peta.blade.php Peta dengan filter
resources/views/web/partials/property.blade.php Property dengan filter

Depedency

https://github.com/OpenSID/API-Database-Gabungan/pull/379

Problem Statement (What & Why)

Masalah:
Beberapa OpenKab menggunakan server API Database Gabungan yang sama. Contoh: Kabupaten Mesuji dan Tulang Bawang menggunakan database gabungan milik Mesuji. Pada halaman publik belum ada identifikasi pengambilan data yang ditampilkan sehingga akan menampilkan semua data dari database gabungan tersebut.

Solusi:
Menambahkan parameter identitas OpenKab (kode_kabupaten) ke setiap request AJAX agar API hanya mengembalikan data sesuai dengan kabupaten yang bersangkutan.


Perubahan yang Dilakukan

1. Meta Tag Identitas

resources/views/layouts/presisi/index.blade.php:8

<meta name="identitas-openkab" content="{{ str_replace('.','',$identitasAplikasi['kode_kabupaten'] ?? '') }}">

resources/views/layouts/web.blade.php:10

<meta name="identitas-openkab" content="{{ str_replace('.','',$identitasAplikasi['kode_kabupaten'] ?? '') }}">

Menambahkan meta tag di head layout untuk dibaca oleh JavaScript. Nilai diambil dari konfigurasi $identitasAplikasi['kode_kabupaten'].

2. AJAX Setup Hook

resources/views/layouts/presisi/partials/javascript.blade.php:30-57

const AJAX_PARAMS_CONFIG = {
    metaTagName: 'identitas-openkab',
    paramNames: ['kode_kabupaten', 'filter[kode_kabupaten]']
};
const identitasOpenkab = $(`meta[name="${AJAX_PARAMS_CONFIG.metaTagName}"]`).attr('content') || '';

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!identitasOpenkab) {
            console.warn(`Meta tag ${AJAX_PARAMS_CONFIG.metaTagName} tidak ditemukan`);
            return;
        }

        // Validasi format kode kabupaten (hanya angka, 4 digit)
        if (!identitasOpenkab || !/^\d{4}$/.test(identitasOpenkab)) {
            console.error('Invalid kode_kabupaten format');
            return;
        }

        const encodedValue = encodeURIComponent(identitasOpenkab);
        const params = AJAX_PARAMS_CONFIG.paramNames
            .map(name => `${name}=${encodedValue}`)
            .join('&');

        settings.url += settings.url.indexOf('?') === -1 ? `?${params}` : `&${params}`;
    }
});

resources/js/web.js:12-38 - Versi Vite untuk frontend

Konfigurasi AJAX global yang akan menginjeksi parameter kode_kabupaten dan filter[kode_kabupaten] ke semua request AJAX secara otomatis.

3. View Files Updated

Semua file yang melakukan AJAX call ke API database gabungan sekarang akan otomatis ter-filter:

  • resources/views/presisi/statistik/sandang.blade.php (line 318)
  • resources/views/presisi/statistik/adat.blade.php
  • resources/views/presisi/statistik/aktivitas-keagamaan.blade.php
  • resources/views/presisi/statistik/jaminan-sosial.blade.php
  • resources/views/presisi/statistik/kesehatan.blade.php
  • resources/views/presisi/statistik/ketenagakerjaan.blade.php
  • resources/views/presisi/statistik/pangan.blade.php
  • resources/views/presisi/statistik/papan.blade.php
  • resources/views/presisi/statistik/pendidikan.blade.php
  • resources/views/presisi/statistik/senibudaya.blade.php
  • resources/views/presisi/wilayah/peta.blade.php
  • resources/views/presisi/geo_spasial/index.blade.php
  • resources/views/web/index.blade.php
  • resources/views/web/partials/property.blade.php

4. Build Assets

- Deleted: public/build-web/assets/vendor-02370d6c.js (old vendor bundle)
- Added: public/build-web/assets/vendor-5c04c9f3.js (new vendor bundle)
- Updated: public/build-web/assets/web-*.js (hashed)
- Updated: public/build-web/manifest.json

Alasan Perubahan

  1. Multi-tenancy pada database gabungan: Ketika beberapa OpenKab berbagi database yang sama, data harus di-filter berdasarkan identitas OpenKab
  2. Backward compatibility: Tidak perlu mengubah setiap file view yang melakukan AJAX call - semua request otomatis di-filter melalui AJAX setup hook
  3. Standarisasi: Menggunakan meta tag approach agar identitas dapat dibaca konsisten di semua halaman

Dampak Perubahan

Positif:

  • API sekarang hanya mengembalikan data sesuai dengan OpenKab yang bersangkutan
  • Tidak perlu mengubah logic di backend/API untuk filtering
  • Otomatis berlaku ke semua request AJAX
  • Tidak ada kode duplikasi di setiap view file

Perlu Diperhatikan:

  • Pastikan konfigurasi $identitasAplikasi['kode_kabupaten'] tersedia di semua halaman
  • Validasi format kode (4 digit angka) menggunakan regex ^\d{4}$
  • API endpoint harus mendukung parameter kode_kabupaten atau filter[kode_kabupaten]

Steps to Reproduce

Sebelum Perbaikan:

  1. Buka halaman publik OpenKab (contoh: https://api-****.berdesa.id/api/v1/desa-aktif)
  2. response API mengembalikan semua desa dari database gabungan (tidak hanya desa dari OpenKab tersebut)
  3. Daftar desa yang tampil di website mencampur data dari berbagai kabupaten
  4. Statistik juga menampilkan data dari semua kabupaten

Setelah Perbaikan:

  1. Buka halaman publik OpenKab
  2. Meta tag identitas-openkab dengan kode kabupaten sudah ada di HTML
  3. Setiap request AJAX otomatis menambahkan parameter kode_kabupaten
  4. API hanya mengembalikan data sesuai dengan OpenKab tersebut
  5. Checklist: Buka https://api-****.berdesa.id/api/v1/desa-aktif?kode_kabupaten=3201 - harusnya hanya desa dari kabupaten 3201

Testing Checklist

✅ Manual Testing

Testing Identitas Meta Tag

  • Buka halaman presisi dan cek source HTML - meta tag identitas-openkab ada
  • Buka halaman web utama dan cek source HTML - meta tag ada
  • Nilai meta tag sesuai dengan kode kabupaten di config

Testing AJAX Parameter Injection

  • Buka browser developer tools (Network tab)
  • Load halaman statistik - verifikasi parameter kode_kabupaten ada di request URL
  • Load halaman desa aktif - verifikasi parameter ada di request
  • Load halaman property - verifikasi parameter ada di request

Testing Fitur Statistik Presisi

  • Buka halaman statistik sandang
  • Verifikasi data yang ditampilkan sesuai dengan kabupaten aktif
  • Coba filter berbagai tahun - data tetap terfilter per kabupaten

Testing Fitur Data Desa Aktif

  • Buka halaman web yang menampilkan desa aktif
  • Pastikan hanya desa dari kabupaten tersebut yang tampil

Testing Fitur Peta

  • Buka halaman peta wilayah
  • Marker desa hanya dari kabupaten aktif

Masalah Terkait (Related Issue)

  • Issue: #996 - Tambahkan parameter identitas OpenKab agar API hanya mengembalikan data sesuai dengan Kabupaten yang bersangkutan

Sebelum Perbaikan:

  • Request AJAX tidak menyertakan identitas kabupaten
  • Data yang ditampilkan bisa mencampur data dari berbagai kabupaten
  • Setiap AJAX call harus ditambahkan parameter secara manual
  • Risiko kebocoran data antar kabupaten

Setelah Perbaikan:

  • Request AJAX otomatis menyertakan parameter kode_kabupaten
  • Data yang ditampilkan terfilter sesuai kabupaten aktif
  • Tidak perlu menambahkan parameter secara manual
  • Data lebih aman karena terisolasi per kabupaten

Breaking Changes

Tidak ada breaking changes yang sengaja dibuat. Namun, perlu diperhatikan:

  • Endpoint API yang tidak mengharapkan parameter kode_kabupaten perlu ditinjau ulang
  • Jika ada endpoint yang memerlukan data lintas kabupaten, perlu penanganan khusus

Migration Guide

Tidak ada migration database yang diperlukan.

Untuk developer yang bekerja dengan frontend:

  1. Pastikan layout yang digunakan sudah menyertakan meta tag identitas-openkab
  2. Tidak perlu menambahkan parameter kode_kabupaten secara manual
  3. Jika perlu menonaktifkan parameter injection untuk request tertentu:
$.ajax({
    url: '/api/endpoint',
    global: false, // Menonaktifkan ajaxSetup
    // ...
});

References


✅ DO's

  • Selalu sertakan parameter di endpoint API yang membutuhkan filter
  • Gunakan format filter[kode_kabupaten] untuk endpoint dengan format filter
  • Test semua fitur yang menggunakan AJAX setelah perubahan ini

❌ DON'Ts

  • Jangan hardcode kode kabupaten di JavaScript
  • Jangan menambahkan parameter secara manual (sudah otomatis via ajaxSetup)
  • Jangan menghapus atau memodifikasi ajaxSetup tanpa alasan

screenshot

simplescreenrecorder-2026-04-21_15.56.32.mp4

@github-actions
Copy link
Copy Markdown

🔄 AI PR Review sedang antri di server...

Proses review akan segera dimulai di background — hasil akan muncul sebagai komentar setelah selesai.
Powered by CrewAI · PR #1007

@devopsopendesa
Copy link
Copy Markdown

🔒 Security Review

Total Temuan: 2 isu (2 Critical)

Severity File Baris Isu
🚨 CRITICAL resources/js/web.js 14 URL Parameter Injection - Unencoded meta tag value
🚨 CRITICAL resources/views/layouts/presisi/partials/javascript.blade.php 34 URL Parameter Injection - Unencoded meta tag value

Detail lengkap dan cara reproduksi tersedia sebagai inline comment pada setiap baris.

Comment thread resources/js/web.js Outdated
beforeSend: function (xhr, settings) {
const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
if (settings.url.indexOf('?') === -1) {
settings.url += '?kode_kabupaten=' + identitasOpenkab+'&filter[kode_kabupaten]=' + identitasOpenkab;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[CRITICAL] 🔒 Security: URL Parameter Injection via Unencoded Meta Tag Value

Masalah: Nilai identitasOpenkab dari meta tag langsung dikonkatenasi ke URL tanpa encodeURIComponent(). Attacker yang bisa memanipulasi meta tag (misal via XSS di tempat lain atau server-side injection) dapat menyuntikkan parameter tambahan atau karakter khusus yang merusak URL.

Kode:

const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
if (settings.url.indexOf('?') === -1) {
    settings.url += '?kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
} else {
    settings.url += '&kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
}

Risiko:

  • Parameter Pollution: Attacker inject &admin=1 atau parameter sensitif lain
  • URL Breaking: Karakter seperti #, &, = bisa merusak struktur URL
  • Filter Bypass: Jika backend mengandalkan parameter ini untuk authorization, bisa di-bypass
  • Impact: Semua AJAX request di aplikasi terpengaruh karena menggunakan $.ajaxSetup() global

PoC (Chrome Console):

// Jalankan di Chrome DevTools Console (F12 → Console)
// Pastikan sudah login ke aplikasi di tab yang sama

// Step 1: Manipulasi meta tag untuk inject parameter berbahaya
$('meta[name="identitas-openkab"]').attr('content', '1234&admin=true&role=superadmin');

// Step 2: Trigger AJAX request (contoh ke endpoint apapun)
const testUrl = '/api/test-endpoint';
const resp = await fetch(testUrl, {
    method: 'GET',
    headers: { 'X-Requested-With': 'XMLHttpRequest' }
});

// Step 3: Periksa URL yang sebenarnya dikirim
console.log('URL yang dikirim:', resp.url);
// Expected output: /api/test-endpoint?kode_kabupaten=1234&admin=true&role=superadmin&filter[kode_kabupaten]=1234&admin=true&role=superadmin

// Step 4: Verifikasi parameter diterima backend
const data = await resp.text();
console.log('Response:', data);

// Alternatif: Test dengan jQuery AJAX
$.get('/api/desa', function(data) {
    console.log('jQuery AJAX berhasil dengan parameter terinjeksi');
});
// Periksa Network tab untuk melihat URL final

Fix:

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
        
        // Validasi format kode kabupaten (hanya angka, 4-6 digit)
        if (!identitasOpenkab || !/^\d{4,6}$/.test(identitasOpenkab)) {
            console.error('Invalid kode_kabupaten format');
            return; // Abort jika tidak valid
        }
        
        // Encode value sebelum ditambahkan ke URL
        const encodedValue = encodeURIComponent(identitasOpenkab);
        
        if (settings.url.indexOf('?') === -1) {
            settings.url += '?kode_kabupaten=' + encodedValue + '&filter[kode_kabupaten]=' + encodedValue;
        } else {
            settings.url += '&kode_kabupaten=' + encodedValue + '&filter[kode_kabupaten]=' + encodedValue;
        }
    }
});

beforeSend: function(xhr, settings) {
const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
if (settings.url.indexOf('?') === -1) {
settings.url += '?kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[CRITICAL] 🔒 Security: URL Parameter Injection via Unencoded Meta Tag Value (Duplicate)

Masalah: Identik dengan isu di resources/js/web.js - nilai identitasOpenkab dari meta tag langsung dikonkatenasi ke URL tanpa encodeURIComponent(). Ini adalah duplikasi kode yang sama di admin panel.

Kode:

const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
if (settings.url.indexOf('?') === -1) {
    settings.url += '?kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
} else {
    settings.url += '&kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
}

Risiko:

  • Parameter Pollution: Attacker inject parameter tambahan seperti &is_admin=1
  • Authorization Bypass: Jika backend filter berdasarkan kode_kabupaten, bisa di-bypass
  • Admin Panel Exposure: Lebih berbahaya karena ini di admin panel dengan privilege lebih tinggi
  • Impact: Semua AJAX request di admin panel terpengaruh

PoC (Chrome Console):

// Jalankan di Chrome DevTools Console (F12 → Console)
// Pastikan sudah login sebagai admin di panel /presisi

// Step 1: Manipulasi meta tag untuk inject parameter privilege escalation
$('meta[name="identitas-openkab"]').attr('content', '1234&bypass_auth=1&role_id=1');

// Step 2: Trigger AJAX request ke endpoint admin (contoh DataTables)
const adminEndpoint = '/presisi/api/users'; // Sesuaikan dengan endpoint yang ada
const resp = await fetch(adminEndpoint, {
    method: 'GET',
    headers: { 
        'X-Requested-With': 'XMLHttpRequest',
        'Accept': 'application/json'
    }
});

// Step 3: Periksa URL yang sebenarnya dikirim
console.log('Admin URL yang dikirim:', resp.url);
// Expected: /presisi/api/users?kode_kabupaten=1234&bypass_auth=1&role_id=1&filter[kode_kabupaten]=1234&bypass_auth=1&role_id=1

// Step 4: Cek apakah parameter terinjeksi diterima backend
const data = await resp.json();
console.log('Admin Response:', data);

// Alternatif: Test dengan DataTables AJAX yang umum di AdminLTE
$('#example-table').DataTable().ajax.reload();
// Periksa Network tab untuk melihat parameter yang terinjeksi

Fix:

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
        
        // Validasi format kode kabupaten (hanya angka, 4-6 digit)
        if (!identitasOpenkab || !/^\d{4,6}$/.test(identitasOpenkab)) {
            console.error('Invalid kode_kabupaten format');
            return; // Abort jika tidak valid
        }
        
        // Encode value sebelum ditambahkan ke URL
        const encodedValue = encodeURIComponent(identitasOpenkab);
        
        if (settings.url.indexOf('?') === -1) {
            settings.url += '?kode_kabupaten=' + encodedValue + '&filter[kode_kabupaten]=' + encodedValue;
        } else {
            settings.url += '&kode_kabupaten=' + encodedValue + '&filter[kode_kabupaten]=' + encodedValue;
        }
    }
});

Rekomendasi Tambahan:

  • Pertimbangkan untuk membuat fungsi helper terpusat daripada duplikasi kode
  • Tambahkan server-side validation untuk memastikan kode_kabupaten valid
  • Gunakan whitelist approach di backend untuk parameter yang diizinkan

@devopsopendesa
Copy link
Copy Markdown

⚡ Performance Review

Total Temuan: 2 isu (2 Critical, 0 High)

Severity File Baris Isu Estimasi Dampak
🚨 CRITICAL resources/js/web.js 12 jQuery selector di beforeSend tanpa cache +1 DOM query per AJAX request
🚨 CRITICAL resources/views/layouts/presisi/partials/javascript.blade.php 32 jQuery selector di beforeSend tanpa cache +1 DOM query per AJAX request

Detail lengkap tersedia sebagai inline comment pada setiap baris.

Comment thread resources/js/web.js Outdated
window.bootstrap = bootstrap;
$.ajaxSetup({
beforeSend: function (xhr, settings) {
const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[CRITICAL] ⚡ Performance: jQuery Selector Tanpa Cache di AJAX beforeSend

Masalah: Selector $('meta[name="identitas-openkab"]').attr('content') dipanggil di dalam beforeSend callback yang akan dieksekusi pada SETIAP request AJAX. Ini menyebabkan DOM query berulang untuk elemen yang nilainya statis (tidak berubah selama page lifecycle).

Kode:

const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');

Dampak:

  • Production Impact: Jika halaman melakukan 50 AJAX requests, akan ada 50x DOM query untuk elemen yang sama
  • Performance Cost: ~0.5-2ms per query × jumlah AJAX requests
  • Scalability: Pada dashboard dengan banyak AJAX (DataTables, charts, live updates), overhead bisa mencapai 100-500ms total per page load

Fix:

// Cache selector di luar ajaxSetup (hanya query 1x saat page load)
const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content') || '';

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        // Gunakan cached value
        if (settings.url.indexOf('?') === -1) {
            settings.url += '?kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
        } else {
            settings.url += '&kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
        }
    }
});


$.ajaxSetup({
beforeSend: function(xhr, settings) {
const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[CRITICAL] ⚡ Performance: jQuery Selector Tanpa Cache di AJAX beforeSend (Duplikasi)

Masalah: Sama seperti resources/js/web.js - selector $('meta[name="identitas-openkab"]').attr('content') dipanggil berulang di setiap AJAX request. Masalah ini terduplikasi di admin panel, yang biasanya memiliki lebih banyak AJAX requests (DataTables, form submissions, live data).

Kode:

const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');

Dampak:

  • Production Impact: Admin panel dengan DataTables bisa melakukan 100+ AJAX requests per halaman (pagination, sorting, filtering)
  • Performance Cost: 100 requests × 1ms = 100ms overhead hanya untuk DOM query
  • User Experience: Pada koneksi lambat atau device low-end, ini bisa menyebabkan lag yang terasa
  • Worst Case: Dashboard dengan multiple DataTables + live charts = 200-300 AJAX requests = 200-300ms wasted

Fix:

// Cache selector di luar ajaxSetup
const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content') || '';

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        // Gunakan cached value
        if (settings.url.indexOf('?') === -1) {
            settings.url += '?kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
        } else {
            settings.url += '&kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
        }
    }
});

Rekomendasi Tambahan: Pertimbangkan untuk membuat satu file shared JavaScript untuk logic ini agar tidak duplikasi kode antara web.js dan javascript.blade.php.

@devopsopendesa
Copy link
Copy Markdown

📝 Code Quality Review

Total Temuan: 5 isu (0 Critical, 5 High)

Severity Kategori File Baris Isu
⚠️ HIGH Architecture resources/js/web.js 10 Code Duplication: Logic AJAX setup diduplikasi di 2 tempat
⚠️ HIGH Architecture resources/views/layouts/presisi/partials/javascript.blade.php 30 Code Duplication: Logic AJAX setup diduplikasi di 2 tempat
⚠️ HIGH JS Quality resources/js/web.js 12 Missing null/undefined check untuk meta tag
⚠️ HIGH JS Quality resources/views/layouts/presisi/partials/javascript.blade.php 32 Missing null/undefined check untuk meta tag
⚠️ HIGH JS Quality resources/js/web.js 13 Hardcoded parameter names tanpa konfigurasi

Detail lengkap tersedia sebagai inline comment pada setiap baris.

Comment thread resources/js/web.js
window.$ = $;
window.jQuery = $;
window.bootstrap = bootstrap;
$.ajaxSetup({
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] 📝 Code Quality: Code Duplication - DRY Violation

Kategori: Architecture

Masalah: Logic $.ajaxSetup() untuk inject parameter kode_kabupaten diduplikasi persis di 2 tempat berbeda:

  1. resources/js/web.js (L10-19) - untuk public web
  2. resources/views/layouts/presisi/partials/javascript.blade.php (L30-39) - untuk admin panel

Duplikasi ini melanggar prinsip DRY (Don't Repeat Yourself) dan menyulitkan maintenance. Jika ada bug atau perlu perubahan logic, harus diubah di 2 tempat.

Kode:

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
        if (settings.url.indexOf('?') === -1) {
            settings.url += '?kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
        } else {
            settings.url += '&kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
        }
    }
});

Fix:
Ekstrak ke shared utility module yang bisa digunakan di kedua context:

// resources/js/utils/ajax-setup.js
export function setupAjaxDefaults() {
    $.ajaxSetup({
        beforeSend: function(xhr, settings) {
            const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
            
            if (!identitasOpenkab) {
                console.warn('Meta tag identitas-openkab tidak ditemukan');
                return;
            }
            
            const params = `kode_kabupaten=${identitasOpenkab}&filter[kode_kabupaten]=${identitasOpenkab}`;
            settings.url += settings.url.indexOf('?') === -1 ? `?${params}` : `&${params}`;
        }
    });
}

// resources/js/web.js
import { setupAjaxDefaults } from './utils/ajax-setup';
setupAjaxDefaults();

// Untuk admin panel, buat inline script yang import dari build:
// <script>window.setupAjaxDefaults && window.setupAjaxDefaults();</script>

<script nonce="{{ csp_nonce() }}">
var selectedMenuObj = null;

$.ajaxSetup({
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] 📝 Code Quality: Code Duplication - DRY Violation

Kategori: Architecture

Masalah: Sama dengan temuan di resources/js/web.js L10. Logic $.ajaxSetup() diduplikasi persis di file ini. Ini adalah copy-paste dari web.js yang ditempatkan di Blade partial admin panel.

Kode:

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
        if (settings.url.indexOf('?') === -1) {
            settings.url += '?kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
        } else {
            settings.url += '&kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
        }
    }
});

Fix:
Lihat fix di temuan sebelumnya (web.js L10). Gunakan shared utility yang sama untuk menghindari duplikasi.

Comment thread resources/js/web.js Outdated
window.bootstrap = bootstrap;
$.ajaxSetup({
beforeSend: function (xhr, settings) {
const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] 📝 Code Quality: Missing Null/Undefined Check

Kategori: JS Quality

Masalah: Kode langsung menggunakan identitasOpenkab tanpa validasi apakah meta tag ada atau tidak. Jika meta tag tidak ditemukan (misalnya karena error di Blade atau data $identitasAplikasi kosong), identitasOpenkab akan undefined dan URL akan menjadi ?kode_kabupaten=undefined&filter[kode_kabupaten]=undefined.

Kode:

const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
if (settings.url.indexOf('?') === -1) {
    settings.url += '?kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;

Fix:

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
        
        // Guard clause: skip jika meta tag tidak ada
        if (!identitasOpenkab) {
            console.warn('Meta tag identitas-openkab tidak ditemukan, AJAX request tanpa kode_kabupaten');
            return;
        }
        
        const params = `kode_kabupaten=${identitasOpenkab}&filter[kode_kabupaten]=${identitasOpenkab}`;
        settings.url += settings.url.indexOf('?') === -1 ? `?${params}` : `&${params}`;
    }
});


$.ajaxSetup({
beforeSend: function(xhr, settings) {
const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] 📝 Code Quality: Missing Null/Undefined Check

Kategori: JS Quality

Masalah: Sama dengan temuan di resources/js/web.js L12. Tidak ada validasi apakah meta tag identitas-openkab ada atau tidak sebelum digunakan.

Kode:

const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
if (settings.url.indexOf('?') === -1) {
    settings.url += '?kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;

Fix:

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
        
        if (!identitasOpenkab) {
            console.warn('Meta tag identitas-openkab tidak ditemukan, AJAX request tanpa kode_kabupaten');
            return;
        }
        
        const params = `kode_kabupaten=${identitasOpenkab}&filter[kode_kabupaten]=${identitasOpenkab}`;
        settings.url += settings.url.indexOf('?') === -1 ? `?${params}` : `&${params}`;
    }
});

Comment thread resources/js/web.js Outdated
$.ajaxSetup({
beforeSend: function (xhr, settings) {
const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
if (settings.url.indexOf('?') === -1) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] 📝 Code Quality: Hardcoded Configuration

Kategori: JS Quality

Masalah: Parameter names (kode_kabupaten, filter[kode_kabupaten]) di-hardcode langsung di logic. Jika di masa depan perlu menambah parameter lain atau mengubah naming convention, harus mengubah kode di multiple places. Lebih baik menggunakan konfigurasi.

Kode:

if (settings.url.indexOf('?') === -1) {
    settings.url += '?kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
} else {
    settings.url += '&kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
}

Fix:

// Definisikan config di top-level atau import dari config file
const AJAX_PARAMS_CONFIG = {
    metaTagName: 'identitas-openkab',
    paramNames: ['kode_kabupaten', 'filter[kode_kabupaten]']
};

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        const identitasOpenkab = $(`meta[name="${AJAX_PARAMS_CONFIG.metaTagName}"]`).attr('content');
        
        if (!identitasOpenkab) {
            console.warn(`Meta tag ${AJAX_PARAMS_CONFIG.metaTagName} tidak ditemukan`);
            return;
        }
        
        const params = AJAX_PARAMS_CONFIG.paramNames
            .map(name => `${name}=${identitasOpenkab}`)
            .join('&');
            
        settings.url += settings.url.indexOf('?') === -1 ? `?${params}` : `&${params}`;
    }
});

@devopsopendesa
Copy link
Copy Markdown

🐛 Bug Detection Review

Total Temuan: 2 isu (1 Critical, 1 High)

Severity File Baris Bug Skenario
🚨 CRITICAL resources/js/web.js 12 Undefined injection ke URL Meta tag tidak ada → attr() return undefined → URL jadi /api?kode_kabupaten=undefined
🚨 CRITICAL resources/views/layouts/presisi/partials/javascript.blade.php 31 Undefined injection ke URL Meta tag tidak ada → attr() return undefined → URL jadi /api?kode_kabupaten=undefined

Detail skenario dan fix tersedia sebagai inline comment pada setiap baris.

Comment thread resources/js/web.js Outdated
window.bootstrap = bootstrap;
$.ajaxSetup({
beforeSend: function (xhr, settings) {
const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[CRITICAL] 🐛 Bug: Undefined Injection ke URL AJAX

Kode: const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');

Skenario:

  • Jika meta tag <meta name="identitas-openkab"> tidak ada di DOM (misalnya karena error di Blade rendering, atau view yang tidak include layout dengan benar)
  • $('meta[name="identitas-openkab"]').attr('content') akan return undefined (bukan string kosong)
  • Variabel identitasOpenkab menjadi undefined
  • Saat di-concatenate ke URL di baris 14/16, JavaScript akan convert undefined menjadi string literal "undefined"
  • Semua AJAX request akan punya parameter: ?kode_kabupaten=undefined&filter[kode_kabupaten]=undefined

Dampak:

  • Backend API menerima string "undefined" sebagai kode kabupaten
  • Query database akan gagal atau return data yang salah
  • Filter tidak berfungsi dengan benar
  • Potensi data leak jika backend tidak validasi strict

Fix:

const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content') || '';
if (!identitasOpenkab) {
    console.error('Meta tag identitas-openkab tidak ditemukan');
    return; // atau throw error untuk mencegah request dengan data invalid
}

var selectedMenuObj = null;

$.ajaxSetup({
beforeSend: function(xhr, settings) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[CRITICAL] 🐛 Bug: Undefined Injection ke URL AJAX (Duplikasi)

Kode: const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content');

Skenario:

  • Sama persis dengan bug di resources/js/web.js line 12
  • Jika meta tag tidak ada di DOM, attr('content') return undefined
  • String literal "undefined" akan masuk ke semua AJAX request di admin panel
  • Karena ini di dalam $(function() {...}), error baru terdeteksi setelah DOM ready

Dampak:

  • Semua fitur admin yang pakai AJAX (DataTables, Select2 remote, form submission) akan kirim kode_kabupaten=undefined
  • Backend API menerima data invalid
  • Potensi crash atau data corruption jika backend tidak handle edge case ini

Fix:

$(function () {
    const identitasOpenkab = $('meta[name="identitas-openkab"]').attr('content') || '';
    
    if (!identitasOpenkab) {
        console.error('Meta tag identitas-openkab tidak ditemukan di admin panel');
        // Tampilkan alert ke user atau redirect ke error page
        return;
    }
    
    $.ajaxSetup({
        beforeSend: function(xhr, settings) {
            if (settings.url.indexOf('?') === -1) {
                settings.url += '?kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
            } else {
                settings.url += '&kode_kabupaten=' + identitasOpenkab + '&filter[kode_kabupaten]=' + identitasOpenkab;
            }
        }
    });
    
    // ... rest of code
});

@devopsopendesa
Copy link
Copy Markdown

🤖 AI Code Review — Selesai

📋 Ringkasan Semua Review

Agent Temuan Inline Comments
📊 Full-Stack Security Specialist (PHP + JavaScript) 2 ✅ 2 posted
📊 Full-Stack Performance Analyst 2 ✅ 2 posted
📊 Full-Stack Code Quality & Architecture Reviewer 5 ✅ 5 posted
📊 Full-Stack Logic Bug Hunter (PHP + JavaScript) 2 ✅ 2 posted

Total inline comments: 11
Setiap agent sudah mem-posting summary dan inline comment masing-masing di atas.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants