Skip to content

feat: tambahkan parameter identitas openkab#1007

Open
pandigresik wants to merge 1 commit intorilis-devfrom
feat/set_identitas_openkab
Open

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

Conversation

@pandigresik
Copy link
Copy Markdown
Contributor

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.

Perubahan yang dilakukan:

  1. .gitignore

    • Menambahkan /template_ai/ ke daftar ignore untuk menjaga file template AI tidak masuk ke version control
  2. public/build-web/assets/vendor-02370d6c.js

    • Menghapus file vendor JavaScript yang sudah tidak terpakai (optimasi build)
  3. resources/views/layouts/presisi/index.blade.php

    • Menambahkan meta tag identitas-openkab yang berisi kode kabupaten:
    <meta name="identitas-openkab" content="{{ str_replace('.','',$identitasAplikasi['kode_kabupaten'] ?? '') }}">
  4. resources/views/layouts/presisi/partials/javascript.blade.php

    • Menambahkan konfigurasi AJAX global untuk menyuntikkan parameter kode_kabupaten dan filter[kode_kabupaten] ke setiap request AJAX:
    $.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;
            }
        }
    });
  5. resources/views/layouts/web.blade.php

    • Menambahkan meta tag identitas-openkab yang sama untuk layout web utama
  6. resources/views/web/partials/property.blade.php

    • Memodifikasi AJAX call untuk menyertakan parameter pagination:
    $.get(urlDesaAktif+'?page[size]=6', {}, function(result) {

Alasan perubahan:

  • Integrasi API-Database-Gabungan: Membutuhkan identifikasi kabupaten yang unik untuk setiap request agar data yang dikembalikan sesuai dengan kabupaten yang sedang aktif
  • Otomatisasi Parameter: Menghindari penambahan manual parameter kode_kabupaten di setiap AJAX call yang ada di aplikasi
  • Konsistensi Data: Memastikan semua request API selalu menyertakan filter kabupaten untuk mencegah data dari kabupaten lain tampil secara tidak sengaja
  • Pembersihan Build: Menghapus file vendor yang tidak terpakai untuk mengurangi ukuran build

Dampak perubahan:

  • Positif:

    • Semua request AJAX otomatis menyertakan parameter kode_kabupaten
    • Data yang ditampilkan lebih terkontrol dan sesuai dengan kabupaten aktif
    • Mengurangi risiko IDOR (Insecure Direct Object Reference) karena data difilter berdasarkan kabupaten
    • Ukuran build menjadi lebih kecil
  • Perlu diperhatikan:

    • Semua endpoint API yang menerima request dari frontend harus siap menerima parameter kode_kabupaten dan filter[kode_kabupaten]
    • Jika ada endpoint yang tidak memerlukan filter kabupaten, perlu ditangani secara khusus

Masalah Terkait (Related Issue)

Closes #996

Sebelum perbaikan (masalah):

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

Setelah perbaikan (fix):

  • Request AJAX otomatis menyertakan parameter kode_kabupaten dan filter[kode_kabupaten]
  • Data yang ditampilkan terfilter sesuai kabupaten aktif
  • Tidak perlu menambahkan parameter secara manual di setiap AJAX call
  • Data lebih aman karena terisolasi per kabupaten

Testing pada fitur lain yang terkait:

  • Fitur statistik presisi
  • Fitur data desa aktif
  • Fitur artikel dan konten web
  • Fitur dashboard

Daftar Periksa (Checklist)

Code Review

  • Code mengikuti standar coding yang berlaku
  • Tidak ada kode yang di-hardcode (kecuali memang diperlukan)
  • Nama variabel dan fungsi menggunakan bahasa yang konsisten
  • Tidak ada debugging code (console.log, dd, var_dump, dll) yang tertinggal
  • Code sudah diformat dengan rapi

Dependencies yang ditambahkan

Manual Testing

Testing Identitas Meta Tag

  • Buka halaman presisi dan verifikasi meta tag identitas-openkab ada di HTML
  • Buka halaman web utama dan verifikasi meta tag identitas-openkab ada di HTML
  • Pastikan nilai meta tag sesuai dengan kode kabupaten yang dikonfigurasi

Testing AJAX Parameter Injection

  • Buka browser developer tools (Network tab)
  • Lakukan aksi yang memicu AJAX request (misalnya load data statistik)
  • Verifikasi parameter kode_kabupaten dan filter[kode_kabupaten] ada di request URL
  • Pastikan nilai parameter sesuai dengan kode kabupaten yang dikonfigurasi

Testing Fitur Statistik Presisi

  • Buka halaman statistik presisi
  • Verifikasi data yang ditampilkan sesuai dengan kabupaten aktif
  • Coba filter berbagai tahun dan pastikan data tetap terfilter per kabupaten

Testing Fitur Data Desa Aktif

  • Buka halaman web yang menampilkan data desa aktif
  • Verifikasi parameter page[size]=6 ada di request
  • Pastikan data desa yang ditampilkan sesuai dengan kabupaten aktif

Testing Fitur Artikel dan Konten Web

  • Buka halaman artikel
  • Verifikasi request AJAX menyertakan parameter kabupaten
  • Pastikan konten yang ditampilkan sesuai dengan kabupaten aktif (ini tidak bisa dikarenakan artikel dari openkab kolom config_id selalu bernilai null)

Automated Testing

  • Semua test yang ada tetap passing
  • Tidak ada test yang perlu diupdate karena perubahan ini

Screenshots / Video

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

(Tambahkan screenshot atau video jika diperlukan untuk mendemonstrasikan perubahan)

Contoh Meta Tag di HTML:

<meta name="identitas-openkab" content="3201">

Contoh Request URL dengan Parameter:

/api/statistik?kode_kabupaten=3201&filter[kode_kabupaten]=3201&tahun=2024

Teknis Detail

Cara Kerja AJAX Setup

  1. Meta Tag Storage: Kode kabupaten disimpan dalam meta tag dengan nama identitas-openkab
  2. AJAX Interception: Menggunakan $.ajaxSetup() untuk menangkap semua request AJAX sebelum dikirim
  3. Parameter Injection: Sebelum request dikirim, parameter kode_kabupaten dan filter[kode_kabupaten] ditambahkan ke URL
  4. URL Handling: Kode mengecek apakah URL sudah memiliki parameter query (?) untuk menentukan apakah menggunakan ? atau &

Format Kode Kabupaten

Kode kabupaten diambil dari $identitasAplikasi['kode_kabupaten'] dan karakter titik (.) dihapus menggunakan str_replace('.',''). Ini untuk memastikan format kode kabupaten konsisten.

Parameter yang Ditambahkan

Setiap request AJAX akan menerima dua parameter tambahan:

  • kode_kabupaten: Parameter utama untuk identifikasi kabupaten
  • filter[kode_kabupaten]: Parameter dalam format filter untuk kompatibilitas dengan API yang menggunakan format filter

Testing

Unit Testing

Tidak ada unit test baru yang ditambahkan karena perubahan ini terutama pada view dan JavaScript.

Breaking Changes

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

  • Endpoint API yang tidak mengharapkan parameter kode_kabupaten dan filter[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 perubahan ini.

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 di AJAX call
  3. Jika perlu menonaktifkan parameter injection untuk request tertentu, gunakan global: false di options AJAX:
    $.ajax({
        url: '/api/endpoint',
        global: false, // Ini akan menonaktifkan ajaxSetup
        // ...
    });

References


✅ DO's (Hal yang harus dilakukan)

  • Selalu sertakan parameter kode_kabupaten di endpoint API yang membutuhkan filter kabupaten
  • Gunakan format filter[kode_kabupaten] untuk endpoint yang menggunakan format filter
  • Pastikan kode kabupaten diambil dari meta tag identitas-openkab jika perlu diakses dari JavaScript
  • Test semua fitur yang menggunakan AJAX setelah perubahan ini

❌ DON'Ts (Hal yang tidak boleh dilakukan)

  • Jangan hardcode kode kabupaten di JavaScript
  • Jangan menambahkan parameter kode_kabupaten secara manual di AJAX call (sudah otomatis)
  • Jangan menghapus atau memodifikasi $.ajaxSetup() tanpa alasan yang jelas
  • Jangan mengubah format kode kabupaten tanpa koordinasi dengan tim backend

@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
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
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
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
$.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
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