Merge branch 'Investigator/initial' into 'master'
initial commit api Investigator See merge request fronk/thetool!2063
This commit is contained in:
176
application/Api/v1/InvestigatorApicontroller.php
Normal file
176
application/Api/v1/InvestigatorApicontroller.php
Normal file
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
class InvestigatorApicontroller extends mfBaseApicontroller
|
||||
{
|
||||
protected function init() {}
|
||||
|
||||
protected function registerRoutes()
|
||||
{
|
||||
$this->addRoute("/investigator/customer/:id", "getCustomer", "GET");
|
||||
$this->addRoute("/investigator/customer/:id/contract", "getCustomerContract", "GET");
|
||||
$this->addRoute("/investigator/customer/:id/cpe", "getCustomerCpe", "GET");
|
||||
$this->addRoute("/investigator/customer/:id/address", "getCustomerAddress", "GET");
|
||||
$this->addRoute("/investigator/search/customer", "searchCustomer", "GET");
|
||||
}
|
||||
|
||||
protected function authenticated()
|
||||
{
|
||||
$this->registerRoutes();
|
||||
}
|
||||
|
||||
public function getCustomer($customerId)
|
||||
{
|
||||
if (!$customerId) return mfResponse::BadRequest(['message' => 'Customer ID is required']);
|
||||
|
||||
$addresses = AddressModel::search(['customer_number' => $customerId]);
|
||||
if (empty($addresses)) return mfResponse::NotFound(['message' => 'Customer not found']);
|
||||
|
||||
$address = $addresses[0];
|
||||
return mfResponse::Ok([
|
||||
'customer' => [
|
||||
'id' => $address->id,
|
||||
'customerNumber' => $address->customer_number,
|
||||
'company' => $address->company,
|
||||
'firstName' => $address->firstname,
|
||||
'lastName' => $address->lastname,
|
||||
'email' => $address->email,
|
||||
'phone' => $address->phone,
|
||||
'street' => $address->street,
|
||||
'zip' => $address->zip,
|
||||
'city' => $address->city,
|
||||
'country' => $address->country,
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function getCustomerContract($customerId)
|
||||
{
|
||||
if (!$customerId) return mfResponse::BadRequest(['message' => 'Customer ID is required']);
|
||||
|
||||
$addresses = AddressModel::search(['customer_number' => $customerId]);
|
||||
if (empty($addresses)) return mfResponse::NotFound(['message' => 'Customer not found']);
|
||||
|
||||
$contracts = ContractModel::search(['owner_id' => $addresses[0]->id]);
|
||||
$contractData = [];
|
||||
|
||||
foreach ($contracts as $contract) {
|
||||
$contractData[] = [
|
||||
'contractId' => $contract->contract_id,
|
||||
'productName' => $contract->product_name,
|
||||
'productExternal' => $contract->product_external,
|
||||
'price' => $contract->price,
|
||||
'billingPeriod' => $contract->billing_period,
|
||||
'orderDate' => $contract->order_date,
|
||||
'finishDate' => $contract->finish_date,
|
||||
'cancelDate' => $contract->cancel_date,
|
||||
'slaId' => $contract->sla_id,
|
||||
'status' => $contract->cancel_date ? 'Cancelled' : ($contract->finish_date ? 'Active' : 'Pending'),
|
||||
];
|
||||
}
|
||||
|
||||
return mfResponse::Ok([
|
||||
'customerId' => $customerId,
|
||||
'contractCount' => count($contractData),
|
||||
'contracts' => $contractData,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getCustomerCpe($customerId)
|
||||
{
|
||||
if (!$customerId) return mfResponse::BadRequest(['message' => 'Customer ID is required']);
|
||||
|
||||
$addresses = AddressModel::search(['customer_number' => $customerId]);
|
||||
if (empty($addresses)) return mfResponse::NotFound(['message' => 'Customer not found']);
|
||||
|
||||
$db = $this->db();
|
||||
$sql = "SELECT cp.* FROM Cpeprovisioning cp
|
||||
INNER JOIN `Order` o ON cp.order_id = o.id
|
||||
WHERE o.owner_id = " . intval($addresses[0]->id) . "
|
||||
ORDER BY cp.id DESC LIMIT 10";
|
||||
|
||||
$res = $db->query($sql);
|
||||
$cpeData = [];
|
||||
|
||||
while ($row = $db->fetch_object($res)) {
|
||||
$cpeData[] = [
|
||||
'orderId' => $row->order_id ?? null,
|
||||
'routerType' => $row->routertype ?? null,
|
||||
'routerConfigFinished' => (bool)($row->routerconfig_finished ?? false),
|
||||
'mac' => $row->mac ?? null,
|
||||
'ontSerial' => $row->ont_sn ?? null,
|
||||
'wifiSsid' => $row->wifi_ssid ?? null,
|
||||
'wifiPasswordSet' => !empty($row->wifi_pass),
|
||||
'vlanPublic' => $row->vlan_public ?? null,
|
||||
'vlanNat' => $row->vlan_nat ?? null,
|
||||
'vlanIpv6' => $row->vlan_ipv6 ?? null,
|
||||
'shipping' => (bool)($row->shipping ?? false),
|
||||
];
|
||||
}
|
||||
|
||||
return mfResponse::Ok([
|
||||
'customerId' => $customerId,
|
||||
'cpeCount' => count($cpeData),
|
||||
'cpeProvisioning' => $cpeData,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getCustomerAddress($customerId)
|
||||
{
|
||||
if (!$customerId) return mfResponse::BadRequest(['message' => 'Customer ID is required']);
|
||||
|
||||
$addresses = AddressModel::search(['customer_number' => $customerId]);
|
||||
if (empty($addresses)) return mfResponse::NotFound(['message' => 'Customer not found']);
|
||||
|
||||
$address = $addresses[0];
|
||||
return mfResponse::Ok([
|
||||
'customerId' => $customerId,
|
||||
'address' => [
|
||||
'company' => $address->company,
|
||||
'name' => trim(($address->firstname ?? '') . ' ' . ($address->lastname ?? '')),
|
||||
'street' => $address->street,
|
||||
'zip' => $address->zip,
|
||||
'city' => $address->city,
|
||||
'country' => $address->country,
|
||||
'email' => $address->email,
|
||||
'phone' => $address->phone,
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function searchCustomer()
|
||||
{
|
||||
$searchTerm = $this->get['q'] ?? '';
|
||||
$limit = intval($this->get['limit'] ?? 10);
|
||||
|
||||
if (empty($searchTerm)) return mfResponse::BadRequest(['message' => 'Search term required']);
|
||||
|
||||
$db = $this->db();
|
||||
$searchTerm = $db->escape($searchTerm);
|
||||
|
||||
$sql = "SELECT * FROM Address
|
||||
WHERE customer_number LIKE '%$searchTerm%'
|
||||
OR CONCAT(firstname, ' ', lastname) LIKE '%$searchTerm%'
|
||||
OR company LIKE '%$searchTerm%'
|
||||
OR email LIKE '%$searchTerm%'
|
||||
OR street LIKE '%$searchTerm%'
|
||||
LIMIT $limit";
|
||||
|
||||
$results = $db->queryRows($sql);
|
||||
$customers = [];
|
||||
|
||||
foreach ($results as $row) {
|
||||
$customers[] = [
|
||||
'customerId' => $row['customer_number'],
|
||||
'name' => trim(($row['firstname'] ?? '') . ' ' . ($row['lastname'] ?? '')) ?: $row['company'],
|
||||
'email' => $row['email'],
|
||||
'city' => $row['city'],
|
||||
];
|
||||
}
|
||||
|
||||
return mfResponse::Ok([
|
||||
'searchTerm' => $searchTerm,
|
||||
'count' => count($customers),
|
||||
'customers' => $customers,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,45 @@ use PHPMailer\PHPMailer\Exception;
|
||||
|
||||
class RadiusController extends mfBaseController {
|
||||
private User $me;
|
||||
private bool $isApiCall = false;
|
||||
|
||||
private array $apiAllowedActions = [
|
||||
'ProxyUnsecureHTTPRequestToRadius',
|
||||
'GenieacsRunSpeedtest',
|
||||
'GenieacsGetSpeedtestResult',
|
||||
'GenieacsGetDeviceByIp',
|
||||
'GenieacsGetDeviceByMac',
|
||||
'GenieacsRefreshDevice',
|
||||
'GenieacsRebootDevice',
|
||||
'GenieacsGetDeviceInfo',
|
||||
'GenieacsPing',
|
||||
'GenieacsRemoteAccess',
|
||||
'GenieacsEventLog',
|
||||
'GenieacsNetworkStructure',
|
||||
];
|
||||
|
||||
protected function init(): void {
|
||||
$this->needlogin=true;
|
||||
$apiKey = $_SERVER['HTTP_X_API_KEY'] ?? null;
|
||||
|
||||
if ($apiKey && in_array($this->action, $this->apiAllowedActions)) {
|
||||
$me = new User();
|
||||
$me->loadByApikey($apiKey);
|
||||
|
||||
if ($me->id) {
|
||||
$this->me = $me;
|
||||
$this->isApiCall = true;
|
||||
$this->needlogin = false;
|
||||
if (!defined('INTERNAL_USER_ID')) {
|
||||
define('INTERNAL_USER_ID', $me->id);
|
||||
}
|
||||
header("Access-Control-Allow-Origin: *");
|
||||
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
|
||||
header("Access-Control-Allow-Headers: Content-Type, X-API-Key");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->needlogin = true;
|
||||
$me = new User();
|
||||
$me->loadMe();
|
||||
$this->layout()->set("me", $me);
|
||||
@@ -51,20 +87,32 @@ class RadiusController extends mfBaseController {
|
||||
|
||||
$acs = $this->getGenieACS();
|
||||
|
||||
// Set speedtest parameters on the device
|
||||
$acs->setParameterValues($deviceId, [
|
||||
$resolvedId = $this->resolveDeviceId($deviceId, $acs);
|
||||
if (!$resolvedId) self::sendError("Device not found in GenieACS");
|
||||
|
||||
$acs->getParameterValues($resolvedId, [
|
||||
'InternetGatewayDevice.X_AVM-DE_SpeedtestServer.UDP.Start',
|
||||
'InternetGatewayDevice.X_AVM-DE_SpeedtestServer.UDP.StartBidirect',
|
||||
'InternetGatewayDevice.X_AVM-DE_SpeedtestServer.UDP.WANAccess',
|
||||
'InternetGatewayDevice.X_AVM-DE_SpeedtestServer.UDP.Result'
|
||||
]);
|
||||
|
||||
sleep(2);
|
||||
|
||||
$acs->setParameterValues($resolvedId, [
|
||||
'InternetGatewayDevice.X_AVM-DE_SpeedtestServer.UDP.Start' => 1,
|
||||
'InternetGatewayDevice.X_AVM-DE_SpeedtestServer.UDP.StartBidirect' => 1,
|
||||
'InternetGatewayDevice.X_AVM-DE_SpeedtestServer.UDP.WANAccess' => true
|
||||
]);
|
||||
|
||||
// Get device and extract IP
|
||||
$device = $acs->getDevice($deviceId);
|
||||
$ip = GenieACS::getExternalIP($device);
|
||||
sleep(3);
|
||||
|
||||
$device = $acs->getDevice($resolvedId);
|
||||
$managementIp = GenieACS::getManagementIP($device);
|
||||
$externalIp = GenieACS::getExternalIP($device);
|
||||
$ip = $externalIp ?: $managementIp;
|
||||
|
||||
if (!$ip) self::sendError("Could not determine device IP");
|
||||
|
||||
// Trigger speedtest via external API
|
||||
$url = "http://acs.xinon.at:5000/run-speedtest";
|
||||
$apiKey = "2H9zWrgxPEJL9MZ1yTGtWh16cPCu0AsQ";
|
||||
$data = json_encode(['ip' => $ip]);
|
||||
@@ -84,9 +132,8 @@ class RadiusController extends mfBaseController {
|
||||
|
||||
if ($response === false) self::sendError("Failed to connect to speedtest server");
|
||||
|
||||
self::returnJson(['success' => true, 'message' => 'Speedtest started']);
|
||||
self::returnJson(['success' => true, 'message' => 'Speedtest started', 'ip' => $ip, 'serverResponse' => json_decode($response, true)]);
|
||||
} catch (Exception $e) {
|
||||
$this->log->debug("Speedtest Error", ['error' => $e->getMessage()]);
|
||||
self::sendError("Error running speedtest: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
@@ -101,11 +148,12 @@ class RadiusController extends mfBaseController {
|
||||
|
||||
$acs = $this->getGenieACS();
|
||||
|
||||
// Request parameter refresh
|
||||
$acs->getParameterValues($deviceId, ['InternetGatewayDevice.X_AVM-DE_SpeedtestServer.UDP.Result']);
|
||||
$resolvedId = $this->resolveDeviceId($deviceId, $acs);
|
||||
if (!$resolvedId) self::sendError("Device not found in GenieACS");
|
||||
|
||||
// Get device info with full data
|
||||
$device = $acs->getDevice($deviceId);
|
||||
$acs->getParameterValues($resolvedId, ['InternetGatewayDevice.X_AVM-DE_SpeedtestServer.UDP.Result']);
|
||||
|
||||
$device = $acs->getDevice($resolvedId);
|
||||
|
||||
if (!$device) self::sendError("Device not found");
|
||||
|
||||
@@ -178,6 +226,19 @@ class RadiusController extends mfBaseController {
|
||||
return new GenieACS($host, $username, $password);
|
||||
}
|
||||
|
||||
private function resolveDeviceId(string $deviceId, GenieACS $acs): ?string {
|
||||
if (strpos($deviceId, ':') !== false) {
|
||||
$device = $acs->getDeviceByMac($deviceId);
|
||||
if ($device) {
|
||||
$resolvedId = GenieACS::getDeviceId($device);
|
||||
if ($resolvedId) return $resolvedId;
|
||||
if (isset($device['_id'])) return $device['_id'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return $deviceId;
|
||||
}
|
||||
|
||||
protected function genieacsGetDeviceByIpAction() {
|
||||
try {
|
||||
$ip = $_GET['ip'] ?? null;
|
||||
@@ -255,7 +316,11 @@ class RadiusController extends mfBaseController {
|
||||
if (!$deviceId) self::sendError("Device ID is required");
|
||||
|
||||
$acs = $this->getGenieACS();
|
||||
$acs->getParameterValues($deviceId, [
|
||||
|
||||
$resolvedId = $this->resolveDeviceId($deviceId, $acs);
|
||||
if (!$resolvedId) self::sendError("Device not found in GenieACS");
|
||||
|
||||
$acs->getParameterValues($resolvedId, [
|
||||
'InternetGatewayDevice.DeviceInfo.HardwareVersion',
|
||||
'InternetGatewayDevice.DeviceInfo.SoftwareVersion',
|
||||
'InternetGatewayDevice.WANDevice.*.WANConnectionDevice.*.WANIPConnection.*.MACAddress',
|
||||
@@ -267,7 +332,7 @@ class RadiusController extends mfBaseController {
|
||||
'InternetGatewayDevice.LANDevice.*.Hosts.Host.*.MACAddress'
|
||||
]);
|
||||
|
||||
$device = $acs->getDevice($deviceId);
|
||||
$device = $acs->getDevice($resolvedId);
|
||||
|
||||
self::returnJson([
|
||||
'success' => true,
|
||||
@@ -373,8 +438,11 @@ class RadiusController extends mfBaseController {
|
||||
if (!$deviceId) self::sendError("Device ID is required");
|
||||
|
||||
$acs = $this->getGenieACS();
|
||||
$creds = $acs->createRemoteUser($deviceId);
|
||||
|
||||
$resolvedId = $this->resolveDeviceId($deviceId, $acs);
|
||||
if (!$resolvedId) self::sendError("Device not found in GenieACS");
|
||||
|
||||
$creds = $acs->createRemoteUser($resolvedId);
|
||||
if (!$creds) self::sendError("Could not obtain credentials for FritzBox");
|
||||
|
||||
$url = "http://acs.xinon.at:5000/read-fritz-eventlog";
|
||||
@@ -425,8 +493,11 @@ class RadiusController extends mfBaseController {
|
||||
if (!$deviceId) self::sendError("Device ID is required");
|
||||
|
||||
$acs = $this->getGenieACS();
|
||||
$creds = $acs->createRemoteUser($deviceId);
|
||||
|
||||
$resolvedId = $this->resolveDeviceId($deviceId, $acs);
|
||||
if (!$resolvedId) self::sendError("Device not found in GenieACS");
|
||||
|
||||
$creds = $acs->createRemoteUser($resolvedId);
|
||||
if (!$creds) self::sendError("Could not obtain credentials for FritzBox");
|
||||
|
||||
$url = "http://acs.xinon.at:5000/read-fritz";
|
||||
|
||||
Reference in New Issue
Block a user