<?php
/**
* Plugin Name: DHCP Guardian Pro
* Description: Endpoint webhook Fonnte untuk monitoring jaringan MikroTik via WhatsApp
* Version: 1.0.0
* Author: DHCP Guardian Pro
*/
if (!defined('ABSPATH')) exit;
// =============================================================
// KONFIGURASI — Sesuaikan sebelum diaktifkan
// =============================================================
define('DGP_FONNTE_TOKEN', '2gHRRtCr4CqPZ1ZGmLMq'); // token Fonnte Anda
define('DGP_FONNTE_SEND', 'https://api.fonnte.com/send');
define('DGP_API_SECRET', 'mikpanpakdong'); // kunci rahasia MikroTik ↔ server
define('DGP_TABLE', 'dhcp_guardian_perintah');
// Nomor teknisi yang diizinkan memberi perintah (tanpa + dan spasi)
define('DGP_ALLOWED', serialize([
'6289653639446',
'6285226287777',
'628997716677',
'6285191190681',
]));
// =============================================================
// ------------------------------------------------------------------
// AKTIVASI PLUGIN — Buat tabel MySQL
// ------------------------------------------------------------------
register_activation_hook(__FILE__, 'dgp_buat_tabel');
function dgp_buat_tabel() {
global $wpdb;
$table = $wpdb->prefix . DGP_TABLE;
$charset = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS $table (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
perintah VARCHAR(50) NOT NULL,
nomor_wa VARCHAR(20) NOT NULL,
status ENUM('pending','diproses','selesai','gagal') NOT NULL DEFAULT 'pending',
hasil TEXT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX idx_status (status),
INDEX idx_created (created_at)
) $charset;";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta($sql);
}
// ------------------------------------------------------------------
// DAFTARKAN ENDPOINT REST API
// ------------------------------------------------------------------
add_action('rest_api_init', function () {
// [A] MikroTik → server: ambil perintah pending
register_rest_route('dhcp-guardian/v1', '/perintah', [
'methods' => 'GET',
'callback' => 'dgp_ambil_perintah',
'permission_callback' => '__return_true',
]);
// [B] MikroTik → server: kirim hasil eksekusi perintah
register_rest_route('dhcp-guardian/v1', '/hasil', [
'methods' => 'POST',
'callback' => 'dgp_terima_hasil',
'permission_callback' => '__return_true',
]);
});
// ------------------------------------------------------------------
// [A] TANGKAP PESAN WA DARI PLUGIN ORG-ANGGOTA VIA WORDPRESS ACTION
// Plugin lama memanggil: do_action('dgp_wa_pesan_masuk', $phone, $message)
// DHCP Guardian mendengarkan di sini — 1 webhook Fonnte untuk semua plugin
// ------------------------------------------------------------------
add_action('dgp_wa_pesan_masuk', 'dgp_proses_pesan_masuk', 10, 2);
function dgp_proses_pesan_masuk(string $pengirim, string $pesan) {
global $wpdb;
$pengirim_bersih = preg_replace('/\D/', '', $pengirim);
$pesan = strtolower(trim($pesan));
// Validasi nomor diizinkan
$allowed = unserialize(DGP_ALLOWED);
if (!in_array($pengirim_bersih, $allowed, true)) {
return; // Bukan teknisi, abaikan
}
$tabel = $wpdb->prefix . DGP_TABLE;
// Perintah: "cek N"
if (preg_match('/^cek\s+(\d+)$/', $pesan, $m)) {
$wpdb->insert($tabel, [
'perintah' => 'cek ' . intval($m[1]),
'nomor_wa' => $pengirim_bersih,
'status' => 'pending',
]);
error_log("DGP: Perintah '{$pesan}' dari {$pengirim_bersih} disimpan, id=" . $wpdb->insert_id);
return;
}
// Perintah: "list" / "gangguan" / "daftar"
if (in_array($pesan, ['list', 'gangguan', 'daftar', 'cek all', 'cek semua'], true)) {
$wpdb->insert($tabel, [
'perintah' => 'list',
'nomor_wa' => $pengirim_bersih,
'status' => 'pending',
]);
error_log("DGP: Perintah 'list' dari {$pengirim_bersih} disimpan, id=" . $wpdb->insert_id);
return;
}
// Perintah: "status"
if ($pesan === 'status') {
$wpdb->insert($tabel, [
'perintah' => 'status',
'nomor_wa' => $pengirim_bersih,
'status' => 'pending',
]);
return;
}
// Perintah: "gateway"
if ($pesan === 'gateway') {
$wpdb->insert($tabel, [
'perintah' => 'gateway',
'nomor_wa' => $pengirim_bersih,
'status' => 'pending',
]);
return;
}
// Perintah: "listrik"
if ($pesan === 'listrik') {
$wpdb->insert($tabel, [
'perintah' => 'listrik',
'nomor_wa' => $pengirim_bersih,
'status' => 'pending',
]);
return;
}
// Perintah: "teknisi"
if ($pesan === 'teknisi') {
$wpdb->insert($tabel, [
'perintah' => 'teknisi',
'nomor_wa' => $pengirim_bersih,
'status' => 'pending',
]);
return;
}
// Perintah: "selesai N"
if (preg_match('/^selesai\s+(\d+)$/', $pesan, $m)) {
$wpdb->insert($tabel, [
'perintah' => 'selesai ' . intval($m[1]),
'nomor_wa' => $pengirim_bersih,
'status' => 'pending',
]);
return;
}
// Perintah: "eskalasi N"
if (preg_match('/^eskalasi\s+(\d+)$/', $pesan, $m)) {
$wpdb->insert($tabel, [
'perintah' => 'eskalasi ' . intval($m[1]),
'nomor_wa' => $pengirim_bersih,
'status' => 'pending',
]);
return;
}
// Perintah: "cari NAMA"
if (preg_match('/^cari\s+(.+)$/', $pesan, $m)) {
$kata_kunci = sanitize_text_field(trim($m[1]));
if (strlen($kata_kunci) >= 2) {
$wpdb->insert($tabel, [
'perintah' => 'cari ' . $kata_kunci,
'nomor_wa' => $pengirim_bersih,
'status' => 'pending',
]);
error_log("DGP: Perintah 'cari {$kata_kunci}' dari {$pengirim_bersih} disimpan, id=" . $wpdb->insert_id);
}
return;
}
// Perintah: "psb IP KOMENTAR SPEED" - hanya eskalasi
if (preg_match('/^psb\s+(\S+)\s+(\S+)\s+(\d+)$/', $pesan, $m)) {
$wpdb->insert($tabel, [
'perintah' => 'psb ' . sanitize_text_field($m[1]) . ' ' . sanitize_text_field($m[2]) . ' ' . intval($m[3]),
'nomor_wa' => $pengirim_bersih,
'status' => 'pending',
]);
error_log("DGP: Perintah PSB dari {$pengirim_bersih} disimpan, id=" . $wpdb->insert_id);
return;
}
// Perintah: "ok IP" - konfirmasi PSB, hanya eskalasi
if (preg_match('/^ok\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/', $pesan, $m)) {
$wpdb->insert($tabel, [
'perintah' => 'ok ' . sanitize_text_field($m[1]),
'nomor_wa' => $pengirim_bersih,
'status' => 'pending',
]);
error_log("DGP: Perintah OK PSB dari {$pengirim_bersih} untuk IP {$m[1]} disimpan, id=" . $wpdb->insert_id);
return;
}
// Perintah: "help"
if (in_array($pesan, ['help', 'bantuan', '?'], true)) {
$pesan_help =
"*DHCP Guardian Pro - Perintah*\n" .
"-------------------------------\n" .
"*list* - Daftar gangguan aktif\n" .
"*cek N* - Cek status pelanggan no.N\n" .
" Contoh: cek 1\n" .
"*status* - Ringkasan kondisi jaringan\n" .
"*gateway* - Cek status semua gateway\n" .
"*listrik* - Status listrik terakhir\n" .
"*selesai N* - Tandai pelanggan N selesai\n" .
" Contoh: selesai 2\n" .
"*teknisi* - Daftar teknisi terdaftar\n" .
"*eskalasi N* - Eskalasi manual pelanggan N\n" .
" Contoh: eskalasi 1\n" .
"-------------------------------\n" .
"Perintah hanya aktif untuk nomor teknisi terdaftar.";
dgp_kirim_wa($pengirim_bersih, $pesan_help);
return;
}
// Bukan perintah DHCP Guardian — abaikan diam-diam
}
// ------------------------------------------------------------------
// [B] KELUARKAN PERINTAH PENDING UNTUK MIKROTIK
// GET /wp-json/dhcp-guardian/v1/perintah?secret=XXX
// ------------------------------------------------------------------
function dgp_ambil_perintah(WP_REST_Request $req) {
global $wpdb;
// Validasi secret key dari MikroTik
$secret = sanitize_text_field($req->get_param('secret') ?? '');
if ($secret !== DGP_API_SECRET) {
return new WP_REST_Response(['status' => 'unauthorized'], 403);
}
$tabel = $wpdb->prefix . DGP_TABLE;
// Ambil 1 perintah pending paling lama
$row = $wpdb->get_row(
"SELECT id, perintah, nomor_wa FROM $tabel
WHERE status = 'pending'
ORDER BY created_at ASC
LIMIT 1"
);
if (!$row) {
return new WP_REST_Response(['status' => 'kosong', 'perintah' => ''], 200);
}
// Tandai sebagai sedang diproses agar tidak diambil dua kali
$wpdb->update($tabel,
['status' => 'diproses'],
['id' => $row->id]
);
return new WP_REST_Response([
'status' => 'ada',
'id' => (int) $row->id,
'perintah' => $row->perintah,
'nomor_wa' => $row->nomor_wa,
], 200);
}
// ------------------------------------------------------------------
// [C] TERIMA HASIL DARI MIKROTIK DAN BALAS WA
// POST /wp-json/dhcp-guardian/v1/hasil
// ------------------------------------------------------------------
function dgp_terima_hasil(WP_REST_Request $req) {
global $wpdb;
$body = $req->get_body_params();
$secret = sanitize_text_field($body['secret'] ?? '');
$id = intval($body['id'] ?? 0);
$pesan = sanitize_textarea_field($body['pesan'] ?? '');
$nomor = preg_replace('/\D/', '', $body['nomor_wa'] ?? '');
// Validasi secret
if ($secret !== DGP_API_SECRET) {
return new WP_REST_Response(['status' => 'unauthorized'], 403);
}
if ($id < 1 || empty($pesan) || empty($nomor)) {
return new WP_REST_Response(['status' => 'error', 'reason' => 'data tidak lengkap'], 400);
}
$tabel = $wpdb->prefix . DGP_TABLE;
// Update status perintah menjadi selesai
$wpdb->update($tabel,
['status' => 'selesai', 'hasil' => $pesan],
['id' => $id]
);
// Kirim balasan WA ke teknisi
dgp_kirim_wa($nomor, $pesan);
error_log("DGP: Hasil perintah id={$id} diterima, WA dikirim ke {$nomor}");
return new WP_REST_Response(['status' => 'ok'], 200);
}
// ------------------------------------------------------------------
// HELPER: Kirim WA via Fonnte
// ------------------------------------------------------------------
function dgp_kirim_wa(string $nomor, string $pesan) {
$response = wp_remote_post(DGP_FONNTE_SEND, [
'headers' => ['Authorization' => DGP_FONNTE_TOKEN],
'body' => ['target' => $nomor, 'message' => $pesan],
'timeout' => 15,
]);
if (is_wp_error($response)) {
error_log('DGP: Gagal kirim WA ke ' . $nomor . ' - ' . $response->get_error_message());
}
}
// ------------------------------------------------------------------
// PEMBERSIHAN OTOMATIS: hapus perintah > 1 jam (cron harian)
// ------------------------------------------------------------------
register_activation_hook(__FILE__, function () {
if (!wp_next_scheduled('dgp_cleanup_cron')) {
wp_schedule_event(time(), 'hourly', 'dgp_cleanup_cron');
}
});
register_deactivation_hook(__FILE__, function () {
wp_clear_scheduled_hook('dgp_cleanup_cron');
});
add_action('dgp_cleanup_cron', function () {
global $wpdb;
$tabel = $wpdb->prefix . DGP_TABLE;
$wpdb->query(
"DELETE FROM $tabel
WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 HOUR)
AND status IN ('selesai', 'gagal', 'diproses')"
);
error_log('DGP: Cleanup perintah lama selesai.');
});