87 lines
2.9 KiB
PHP
87 lines
2.9 KiB
PHP
<?php
|
|
/*
|
|
* Reflector Dashboard — web front-end for SvxReflector
|
|
* Copyright (C) 2026 SA7AUX (Björn)
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify it under
|
|
* the terms of the GNU Affero General Public License as published by the Free
|
|
* Software Foundation, either version 3 of the License, or (at your option) any
|
|
* later version. See the LICENSE file for details.
|
|
*/
|
|
declare(strict_types=1);
|
|
require __DIR__ . '/lib.php';
|
|
|
|
$uuid = require_login();
|
|
$me = acct_get($uuid);
|
|
$my_calls = acct_all_calls($uuid); // primary + admin-added extra/club calls
|
|
$my_email = strtolower(trim($me['email'] ?? ''));
|
|
|
|
if (!$my_calls && $my_email === '') {
|
|
json_out(['ok' => true, 'nodes' => []]);
|
|
}
|
|
|
|
// Fetch reflector status via cURL
|
|
$ch = curl_init('http://127.0.0.1:8098/api/status');
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_TIMEOUT => 5,
|
|
CURLOPT_CONNECTTIMEOUT => 2,
|
|
]);
|
|
$json = curl_exec($ch);
|
|
$err = curl_error($ch);
|
|
curl_close($ch);
|
|
|
|
if ($json === false || $json === '') {
|
|
json_out(['ok' => false, 'error' => 'Cannot reach reflector API' . ($err ? ": $err" : '')], 502);
|
|
}
|
|
|
|
$data = json_decode($json, true);
|
|
if (!is_array($data) || !isset($data['nodes'])) {
|
|
json_out(['ok' => false, 'error' => 'Invalid reflector response'], 502);
|
|
}
|
|
|
|
$r = redis();
|
|
|
|
// Match nodes belonging to this user
|
|
$my_nodes = [];
|
|
foreach ($data['nodes'] as $node_call => $node_info) {
|
|
// Only LOCAL client nodes: skip remote trunk nodes (other reflectors'
|
|
// clients relayed over trunks) and bridge/gateway infrastructure.
|
|
if (!empty($node_info['remoteTrunk'])) continue;
|
|
if (stripos((string)($node_info['sw'] ?? ''), 'bridge') !== false) continue;
|
|
|
|
$sysop = strtoupper(trim($node_info['sysop'] ?? ''));
|
|
$match = false;
|
|
|
|
if ($my_calls && $sysop !== '' && in_array($sysop, $my_calls, true)) $match = true;
|
|
|
|
if (!$match && $my_calls && calls_match_node($my_calls, (string)$node_call)) $match = true;
|
|
|
|
// Also match if user is a node admin
|
|
if (!$match && $my_calls) {
|
|
$admins = $r->sMembers(rkey("node_admins:" . strtoupper($node_call)));
|
|
if (is_array($admins)) {
|
|
foreach ($my_calls as $c) {
|
|
if (in_array($c, $admins, true)) { $match = true; break; }
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($match) {
|
|
// Add node admins info — sysop is always default admin
|
|
$stored_admins = $r->sMembers(rkey("node_admins:" . strtoupper($node_call)));
|
|
if (!is_array($stored_admins)) $stored_admins = [];
|
|
$all_admins = $stored_admins;
|
|
if ($sysop !== '' && !in_array($sysop, $all_admins, true)) {
|
|
array_unshift($all_admins, $sysop);
|
|
}
|
|
sort($all_admins);
|
|
$node_info['node_admins'] = $all_admins;
|
|
|
|
$my_nodes[$node_call] = $node_info;
|
|
}
|
|
}
|
|
|
|
json_out(['ok' => true, 'nodes' => $my_nodes]);
|