FE+BE: init check work, removed legacy setDeviceData

Signed-off-by: jokob-sk <jokob.sk@gmail.com>
This commit is contained in:
jokob-sk
2025-12-18 09:02:57 +11:00
parent bc76c04f9e
commit daa720ab94
4 changed files with 325 additions and 271 deletions

View File

@@ -14,21 +14,21 @@
<!-- Buttons -->
<div class="col-xs-12">
<div class="pull-right">
<button type="button"
class="btn btn-default pa-btn pa-btn-delete"
style="margin-left:0px;"
id="btnDelete"
onclick="askDeleteDevice()">
<i class="fas fa-trash-alt"></i>
<?= lang('DevDetail_button_Delete');?>
<button type="button"
class="btn btn-default pa-btn pa-btn-delete"
style="margin-left:0px;"
id="btnDelete"
onclick="askDeleteDevice()">
<i class="fas fa-trash-alt"></i>
<?= lang('DevDetail_button_Delete');?>
</button>
<button type="button"
class="btn btn-primary pa-btn"
style="margin-left:6px; "
id="btnSave"
onclick="setDeviceData()" >
<button type="button"
class="btn btn-primary pa-btn"
style="margin-left:6px; "
id="btnSave"
onclick="setDeviceData()" >
<i class="fas fa-save"></i>
<?= lang('DevDetail_button_Save');?>
<?= lang('DevDetail_button_Save');?>
</button>
</div>
</div>
@@ -36,8 +36,8 @@
<script defer>
// -------------------------------------------------------------------
// -------------------------------------------------------------------
// Get plugin and settings data from API endpoints
function getDeviceData(){
@@ -45,8 +45,8 @@
console.log(mac);
// get data from server
$.get('php/server/devices.php?action=getServerDeviceData&mac='+ mac + '&period='+ period, function(data) {
// get data from server
$.get('php/server/devices.php?action=getServerDeviceData&mac='+ mac + '&period='+ period, function(data) {
// show loading dialog
showSpinner()
@@ -55,30 +55,30 @@
// some race condition, need to implement delay
setTimeout(() => {
$.get('php/server/query_json.php', {
file: 'table_settings.json',
// nocache: Date.now()
},
function(res) {
$.get('php/server/query_json.php', {
file: 'table_settings.json',
// nocache: Date.now()
},
function(res) {
settingsData = res["data"];
// columns to hide
hiddenFields = ["NEWDEV_devScan", "NEWDEV_devPresentLastScan" ]
// columns to disable/readonly - conditional depending if a new dummy device is created
disabledFields = mac == "new" ? ["NEWDEV_devLastNotification", "NEWDEV_devFirstConnection", "NEWDEV_devLastConnection"] : ["NEWDEV_devLastNotification", "NEWDEV_devFirstConnection", "NEWDEV_devLastConnection", "NEWDEV_devMac", "NEWDEV_devLastIP", "NEWDEV_devSyncHubNode", "NEWDEV_devFQDN" ];
// Grouping of fields into categories with associated documentation links
const fieldGroups = {
// Group for device main information
DevDetail_MainInfo_Title: {
data: ["devMac", "devLastIP", "devName", "devOwner", "devType", "devVendor", "devGroup", "devIcon", "devLocation", "devComments"],
data: ["devMac", "devLastIP", "devName", "devOwner", "devType", "devVendor", "devGroup", "devIcon", "devLocation", "devComments"],
docs: "https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICE_MANAGEMENT.md",
iconClass: "fa fa-pencil",
inputGroupClasses: "field-group main-group col-lg-4 col-sm-6 col-xs-12",
labelClasses: "col-sm-4 col-xs-12 control-label",
inputClasses: "col-sm-8 col-xs-12 input-group"
},
},
// Group for event and alert settings
DevDetail_EveandAl_Title: {
data: ["devAlertEvents", "devAlertDown", "devSkipRepeated", "devReqNicsOnline", "devChildrenNicsDynamic"],
@@ -150,14 +150,14 @@
// Loop over each field group to generate sections for each category
Object.entries(fieldGroups).forEach(([groupName, obj]) => {
const groupDiv = $('<div>').addClass(obj.inputGroupClasses); // Create a div for each group with responsive Bootstrap classes
// Add group title and documentation link
groupDiv.append(`<h5><i class="${obj.iconClass}"></i> ${getString(groupName)}
groupDiv.append(`<h5><i class="${obj.iconClass}"></i> ${getString(groupName)}
<span class="helpIconSmallTopRight">
<a target="_blank" href="${obj.docs}">
<i class="fa fa-circle-question"></i>
</a>
</span>
</span>
</h5>
<hr>
`);
@@ -174,8 +174,8 @@
fieldData = fieldData == null ? "" : fieldData;
fieldOptionsOverride = null;
// console.log(setting.setKey);
// console.log(fieldData);
// console.log(setting.setKey);
// console.log(fieldData);
// Additional form elements like the random MAC address button for devMac
let inlineControl = "";
@@ -183,7 +183,7 @@
if (setting.setKey == "NEWDEV_devMac" && deviceData["devIsRandomMAC"] == true) {
inlineControl += `<span class="input-group-addon pointer"
title="${getString("RandomMAC_hover")}">
<a href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/RANDOM_MAC.md" target="_blank">
<a href="https://github.com/jokob-sk/NetAlertX/blob/main/docs/RANDOM_MAC.md" target="_blank">
<i class="fa-solid fa-shuffle"></i>
</a>
</span>`;
@@ -204,15 +204,15 @@
<i class="fa-solid fa-dice" ></i>
</span>`;
}
// handle devChildrenDynamic or NEWDEV_devChildrenNicsDynamic - selected values and options are the same
if (
Array.isArray(fieldData) &&
(setting.setKey == "NEWDEV_devChildrenDynamic" ||
setting.setKey == "NEWDEV_devChildrenNicsDynamic" )
)
{
fieldDataNew = []
if (
Array.isArray(fieldData) &&
(setting.setKey == "NEWDEV_devChildrenDynamic" ||
setting.setKey == "NEWDEV_devChildrenNicsDynamic" )
)
{
fieldDataNew = []
fieldData.forEach(child => {
fieldDataNew.push(child.devMac)
})
@@ -222,10 +222,10 @@
// Generate the input field HTML
const inputFormHtml = `<div class="form-group col-xs-12">
<label id="${setting.setKey}_label" class="${obj.labelClasses}" > ${setting.setName}
<label id="${setting.setKey}_label" class="${obj.labelClasses}" > ${setting.setName}
<i my-set-key="${setting.setKey}"
title="${getString("Settings_Show_Description")}"
class="fa fa-circle-info pointer helpIconSmallTopRight"
title="${getString("Settings_Show_Description")}"
class="fa fa-circle-info pointer helpIconSmallTopRight"
onclick="showDescriptionPopup(this)">
</i>
</label>
@@ -247,29 +247,29 @@
updateAllIconPreviews();
// update readonly fields
handleReadOnly(settingsData, disabledFields);
handleReadOnly(settingsData, disabledFields);
};
// console.log(relevantSettings)
generateSimpleForm(relevantSettings);
toggleNetworkConfiguration(mac == 'Internet')
toggleNetworkConfiguration(mac == 'Internet')
initSelect2();
initHoverNodeInfo();
hideSpinner();
})
}, 100);
});
}
// ----------------------------------------
// Handle the read-only fields
@@ -306,62 +306,102 @@
showSpinner();
// Update data to server using POST
$.post('php/server/devices.php?action=setDeviceData', {
mac: $('#NEWDEV_devMac').val(),
name: encodeURIComponent($('#NEWDEV_devName').val().replace(/'/g, "")),
owner: encodeURIComponent($('#NEWDEV_devOwner').val().replace(/'/g, "")),
type: $('#NEWDEV_devType').val().replace(/'/g, ""),
vendor: encodeURIComponent($('#NEWDEV_devVendor').val().replace(/'/g, "")),
icon: encodeURIComponent($('#NEWDEV_devIcon').val()),
favorite: ($('#NEWDEV_devFavorite')[0].checked * 1),
group: encodeURIComponent($('#NEWDEV_devGroup').val().replace(/'/g, "")),
location: encodeURIComponent($('#NEWDEV_devLocation').val().replace(/'/g, "")),
comments: encodeURIComponent(encodeSpecialChars($('#NEWDEV_devComments').val())),
networknode: $('#NEWDEV_devParentMAC').val(),
networknodeport: $('#NEWDEV_devParentPort').val(),
ssid: $('#NEWDEV_devSSID').val(),
networksite: $('#NEWDEV_devSite').val(),
staticIP: ($('#NEWDEV_devStaticIP')[0].checked * 1),
scancycle: "1",
alertevents: ($('#NEWDEV_devAlertEvents')[0].checked * 1),
alertdown: ($('#NEWDEV_devAlertDown')[0].checked * 1),
skiprepeated: $('#NEWDEV_devSkipRepeated').val().split(' ')[0],
relType: $('#NEWDEV_devParentRelType').val().replace(/'/g, ""),
reqNics: ($('#NEWDEV_devReqNicsOnline')[0].checked * 1),
newdevice: ($('#NEWDEV_devIsNew')[0].checked * 1),
archived: ($('#NEWDEV_devIsArchived')[0].checked * 1),
devFirstConnection: ($('#NEWDEV_devFirstConnection').val()),
devLastConnection: ($('#NEWDEV_devLastConnection').val()),
devCustomProps: btoa(JSON.stringify(collectTableData("#NEWDEV_devCustomProps_table"))),
ip: ($('#NEWDEV_devLastIP').val()),
const apiToken = getSetting("API_TOKEN"); // dynamic token
const host = window.location.hostname;
const port = getSetting("GRAPHQL_PORT");
mac = $('#NEWDEV_devMac').val();
// Build payload for new endpoint
const payload = {
devName: $('#NEWDEV_devName').val().replace(/'/g, ""),
devOwner: $('#NEWDEV_devOwner').val().replace(/'/g, ""),
devType: $('#NEWDEV_devType').val().replace(/'/g, ""),
devVendor: $('#NEWDEV_devVendor').val().replace(/'/g, ""),
devIcon: $('#NEWDEV_devIcon').val(),
devFavorite: ($('#NEWDEV_devFavorite')[0].checked * 1),
devGroup: $('#NEWDEV_devGroup').val().replace(/'/g, ""),
devLocation: $('#NEWDEV_devLocation').val().replace(/'/g, ""),
devComments: encodeSpecialChars($('#NEWDEV_devComments').val()),
devParentMAC: $('#NEWDEV_devParentMAC').val(),
devParentPort: $('#NEWDEV_devParentPort').val(),
devParentRelType: $('#NEWDEV_devParentRelType').val().replace(/'/g, ""),
devSSID: $('#NEWDEV_devSSID').val(),
devSite: $('#NEWDEV_devSite').val(),
devStaticIP: ($('#NEWDEV_devStaticIP')[0].checked * 1),
devScan: 1,
devAlertEvents: ($('#NEWDEV_devAlertEvents')[0].checked * 1),
devAlertDown: ($('#NEWDEV_devAlertDown')[0].checked * 1),
devSkipRepeated: $('#NEWDEV_devSkipRepeated').val().split(' ')[0],
devReqNicsOnline: ($('#NEWDEV_devReqNicsOnline')[0].checked * 1),
devIsNew: ($('#NEWDEV_devIsNew')[0].checked * 1),
devIsArchived: ($('#NEWDEV_devIsArchived')[0].checked * 1),
devFirstConnection: $('#NEWDEV_devFirstConnection').val(),
devLastConnection: $('#NEWDEV_devLastConnection').val(),
devLastIP: $('#NEWDEV_devLastIP').val(),
devCustomProps: btoa(
JSON.stringify(collectTableData("#NEWDEV_devCustomProps_table"))
),
createNew: createNew
}, function(msg) {
showMessage(msg);
};
// Remove navigation prompt "Are you sure you want to leave..."
window.onbeforeunload = null;
somethingChanged = false;
// refresh API
updateApi("devices,appevents");
$.ajax({
url: "http://" + host + ":" + port + "/device/" + encodeURIComponent(mac),
type: "POST",
headers: {
"Authorization": "Bearer " + apiToken,
"Content-Type": "application/json"
},
data: JSON.stringify(payload),
success: function (resp) {
// Callback function
if (typeof refreshCallback == 'function') {
refreshCallback(direction);
if (resp && resp.success) {
showMessage("Device saved successfully");
} else {
showMessage("Device update returned an unexpected response");
}
// Remove navigation prompt
window.onbeforeunload = null;
somethingChanged = false;
// Refresh API
updateApi("devices,appevents");
// Callback
if (typeof refreshCallback === "function") {
refreshCallback(direction);
}
hideSpinner();
},
error: function (xhr) {
if (xhr.status === 403) {
showMessage("Unauthorized invalid API token");
} else {
showMessage("Failed to save device (" + xhr.status + ")");
}
hideSpinner();
}
// Everything loaded
hideSpinner();
});
}
//-----------------------------------------------------------------------------------
// Disables or enables network configuration for the root node
function toggleNetworkConfiguration(disable) {
if (disable) {
if (disable) {
// Completely disable the NEWDEV_devParentMAC <select> and NEWDEV_devParentPort
$('#NEWDEV_devParentMAC').prop('disabled', true).val("").prop('selectedIndex', 0);
$('#NEWDEV_devParentMAC').prop('disabled', true).val("").prop('selectedIndex', 0);
$('#NEWDEV_devParentMAC').empty() // Remove all options
.append('<option value="">Root Node</option>')
$('#NEWDEV_devParentPort').prop('disabled', true);
@@ -380,7 +420,7 @@
// INIT with polling for panel element visibility
// -----------------------------------------------
var deviceDetailsPageInitialized = false;
var deviceDetailsPageInitialized = false;
function initdeviceDetailsPage()
{

View File

@@ -1,7 +1,7 @@
<?php
//------------------------------------------------------------------------------
// NetAlertX
// Open Source Network Guard / WIFI & LAN intrusion detector
// Open Source Network Guard / WIFI & LAN intrusion detector
//
// devices.php - Front module. Server side. Manage Devices
//------------------------------------------------------------------------------
@@ -32,17 +32,16 @@
switch ($action) {
// check server/api_server/api_server_start.py for equivalents
case 'getServerDeviceData': getServerDeviceData(); break; // equivalent: get_device_data
case 'setDeviceData': setDeviceData(); break; // equivalent: set_device_data
case 'deleteDevice': deleteDevice(); break; // equivalent: delete_device(mac)
case 'deleteAllWithEmptyMACs': deleteAllWithEmptyMACs(); break; // equivalent: delete_all_with_empty_macs
case 'deleteAllWithEmptyMACs': deleteAllWithEmptyMACs(); break; // equivalent: delete_all_with_empty_macs
case 'deleteAllDevices': deleteAllDevices(); break; // equivalent: delete_devices(macs)
case 'deleteUnknownDevices': deleteUnknownDevices(); break; // equivalent: delete_unknown_devices
case 'deleteEvents': deleteEvents(); break; // equivalent: delete_events
case 'deleteEvents30': deleteEvents30(); break; // equivalent: delete_events_30
case 'deleteActHistory': deleteActHistory(); break; // equivalent: delete_online_history
case 'deleteDeviceEvents': deleteDeviceEvents(); break; // equivalent: delete_device_events(mac)
case 'resetDeviceProps': resetDeviceProps(); break; // equivalent: reset_device_props
case 'resetDeviceProps': resetDeviceProps(); break; // equivalent: reset_device_props
case 'ExportCSV': ExportCSV(); break; // equivalent: export_devices
case 'ImportCSV': ImportCSV(); break; // equivalent: import_csv
@@ -54,11 +53,11 @@
case 'copyFromDevice': copyFromDevice(); break; // equivalent: copy_device(mac_from, mac_to)
case 'wakeonlan': wakeonlan(); break; // equivalent: wakeonlan
default: logServerConsole ('Action: '. $action); break; // equivalent:
default: logServerConsole ('Action: '. $action); break; // equivalent:
}
}
//------------------------------------------------------------------------------
// Query Device Data
@@ -125,47 +124,47 @@ function getServerDeviceData() {
// Fetch Device Info + Children + Events Stats
$sql =<<<SQL
SELECT
SELECT
d.rowid,
d.*,
CASE
CASE
WHEN d.devAlertDown != 0 AND d.devPresentLastScan = 0 THEN "Down"
WHEN d.devPresentLastScan = 1 THEN "On-line"
ELSE "Off-line"
END AS devStatus,
-- Event counters
(SELECT COUNT(*) FROM Sessions
(SELECT COUNT(*) FROM Sessions
WHERE ses_MAC = d.devMac AND (
ses_DateTimeConnection >= $periodDate OR
ses_DateTimeDisconnection >= $periodDate OR
ses_DateTimeConnection >= $periodDate OR
ses_DateTimeDisconnection >= $periodDate OR
ses_StillConnected = 1
)
) AS devSessions,
(SELECT COUNT(*) FROM Events
WHERE eve_MAC = d.devMac AND
eve_DateTime >= $periodDate AND
(SELECT COUNT(*) FROM Events
WHERE eve_MAC = d.devMac AND
eve_DateTime >= $periodDate AND
eve_EventType NOT IN ("Connected", "Disconnected")
) AS devEvents,
(SELECT COUNT(*) FROM Events
WHERE eve_MAC = d.devMac AND
eve_DateTime >= $periodDate AND
(SELECT COUNT(*) FROM Events
WHERE eve_MAC = d.devMac AND
eve_DateTime >= $periodDate AND
eve_EventType = "Device Down"
) AS devDownAlerts,
(SELECT CAST(( MAX (0, SUM (julianday (IFNULL (ses_DateTimeDisconnection,'$currentdate'))
- julianday (CASE WHEN ses_DateTimeConnection < $periodDate
THEN $periodDate
- julianday (CASE WHEN ses_DateTimeConnection < $periodDate
THEN $periodDate
ELSE ses_DateTimeConnection END)) *24 )) AS INT)
FROM Sessions
WHERE ses_MAC = d.devMac AND
ses_DateTimeConnection IS NOT NULL AND
(ses_DateTimeDisconnection IS NOT NULL OR ses_StillConnected = 1) AND
WHERE ses_MAC = d.devMac AND
ses_DateTimeConnection IS NOT NULL AND
(ses_DateTimeDisconnection IS NOT NULL OR ses_StillConnected = 1) AND
(
ses_DateTimeConnection >= $periodDate OR
ses_DateTimeDisconnection >= $periodDate OR
ses_DateTimeConnection >= $periodDate OR
ses_DateTimeDisconnection >= $periodDate OR
ses_StillConnected = 1
)
) AS devPresenceHours
@@ -271,31 +270,31 @@ function setDeviceData() {
WHERE devMac = '$mac'";
} else { // An INSERT
$sql = "INSERT INTO Devices (
devMac,
devName,
devOwner,
devType,
devVendor,
devIcon,
devFavorite,
devGroup,
devLocation,
devComments,
devParentMAC,
devParentPort,
devSSID,
devSite,
devStaticIP,
devScan,
devAlertEvents,
devAlertDown,
devMac,
devName,
devOwner,
devType,
devVendor,
devIcon,
devFavorite,
devGroup,
devLocation,
devComments,
devParentMAC,
devParentPort,
devSSID,
devSite,
devStaticIP,
devScan,
devAlertEvents,
devAlertDown,
devParentRelType,
devReqNicsOnline,
devSkipRepeated,
devIsNew,
devIsArchived,
devLastConnection,
devFirstConnection,
devSkipRepeated,
devIsNew,
devIsArchived,
devLastConnection,
devFirstConnection,
devLastIP,
devGUID,
devCustomProps,
@@ -369,7 +368,7 @@ function deleteDevice() {
// Delete all devices with empty MAC addresses
//------------------------------------------------------------------------------
function deleteAllWithEmptyMACs() {
global $db;
global $db;
// sql
$sql = 'DELETE FROM Devices WHERE devMac=""';
@@ -388,7 +387,7 @@ function deleteAllWithEmptyMACs() {
// Delete all devices with empty MAC addresses
//------------------------------------------------------------------------------
function deleteUnknownDevices() {
global $db;
global $db;
// sql
$sql = 'DELETE FROM Devices WHERE devName="(unknown)" OR devName="(name not found)"';
@@ -430,7 +429,7 @@ function resetDeviceProps() {
// sql
$sql = 'UPDATE Devices set devCustomProps = "'.getSettingValue("NEWDEV_devCustomProps").'" WHERE devMac="' . $_REQUEST['mac'] .'"';
// execute sql
$result = $db->query($sql);
@@ -443,7 +442,7 @@ function resetDeviceProps() {
}
//------------------------------------------------------------------------------
// Delete all devices
// Delete all devices
//------------------------------------------------------------------------------
function deleteAllDevices() {
global $db;
@@ -462,7 +461,7 @@ function deleteAllDevices() {
}
//------------------------------------------------------------------------------
// Delete all Events
// Delete all Events
//------------------------------------------------------------------------------
function deleteEvents() {
global $db;
@@ -527,18 +526,18 @@ function ExportCSV() {
header("Content-disposition: attachment; filename=\"devices.csv\"");
global $db;
$func_result = $db->query("SELECT * FROM Devices");
$func_result = $db->query("SELECT * FROM Devices");
// prepare CSV header row
$columns = getDevicesColumns();
// wrap the headers with " (quotes)
// wrap the headers with " (quotes)
$resultCSV = '"'.implode('","', $columns).'"'."\n";
// retrieve the devices from the DB
while ($row = $func_result->fetchArray(SQLITE3_ASSOC)) {
while ($row = $func_result->fetchArray(SQLITE3_ASSOC)) {
// loop through columns and add values to the string
// loop through columns and add values to the string
$index = 0;
foreach ($columns as $columnName) {
// Escape special chars (e.g.quotes) inside fields by replacing them with html definitions
@@ -552,14 +551,14 @@ function ExportCSV() {
$resultCSV .= ',';
}
$index++;
}
}
// add a new line for the next row
$resultCSV .= "\n";
}
//write the built CSV string
echo $resultCSV;
echo $resultCSV;
}
@@ -568,7 +567,7 @@ function ExportCSV() {
//------------------------------------------------------------------------------
function ImportCSV() {
global $db;
global $db;
$file = '../../../config/devices.csv';
$data = "";
$skipped = "";
@@ -587,9 +586,9 @@ function ImportCSV() {
} else if (file_exists($file)) { // try to get the data form the file
// Read the CSV file
$data = file_get_contents($file);
$data = file_get_contents($file);
} else {
echo lang('BackDevices_DBTools_ImportCSVMissing');
echo lang('BackDevices_DBTools_ImportCSVMissing');
}
if($data != "")
@@ -600,20 +599,20 @@ function ImportCSV() {
return str_replace("\n", " ", $matches[0]); // Replace with a space
}, $data);
$lines = explode("\n", $data);
$lines = explode("\n", $data);
// Get the column headers from the first line of the CSV
$header = str_getcsv(array_shift($lines));
$header = array_map('trim', $header);
// Delete everything form the DB table
$sql = 'DELETE FROM Devices';
$result = $db->query($sql);
$sql = 'DELETE FROM Devices';
$result = $db->query($sql);
// Build the SQL statement
$sql = "INSERT INTO Devices (" . implode(', ', $header) . ") VALUES ";
// Parse data from CSV file line by line (max 10000 lines)
// Parse data from CSV file line by line (max 10000 lines)
$index = 0;
foreach($lines as $row) {
$rowArray = str_getcsv($row);
@@ -642,7 +641,7 @@ function ImportCSV() {
// Import successful
echo lang('BackDevices_DBTools_ImportCSV') . " (Skipped lines: " . $skipped . ") ";
} else {
// An error occurred while writing to the DB, display the last error message
// An error occurred while writing to the DB, display the last error message
echo lang('BackDevices_DBTools_ImportCSVError') . "\n" . $error . "\n" . $sql . "\n\n" . $result;
}
}
@@ -665,21 +664,21 @@ function getDevicesTotals() {
// combined query
$result = $db->query(
'SELECT
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('my').') as devices,
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('connected').') as connected,
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('favorites').') as favorites,
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('new').') as new,
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('down').') as down,
'SELECT
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('my').') as devices,
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('connected').') as connected,
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('favorites').') as favorites,
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('new').') as new,
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('down').') as down,
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('archived').') as archived
');
$row = $result -> fetchArray (SQLITE3_NUM);
$row = $result -> fetchArray (SQLITE3_NUM);
$resultJSON = json_encode (array ($row[0], $row[1], $row[2], $row[3], $row[4], $row[5]));
// save to cache
setCache("getDevicesTotals", $resultJSON );
}
}
echo ($resultJSON);
}
@@ -769,19 +768,19 @@ function updateNetworkLeaf()
}
//------------------------------------------------------------------------------
// Wake-on-LAN
// Wake-on-LAN
// Inspired by @leiweibau: https://github.com/leiweibau/Pi.Alert/commit/30427c7fea180670c71a2b790699e5d9e9e88ffd
//------------------------------------------------------------------------------
function wakeonlan() {
function wakeonlan() {
$WOL_HOST_IP = $_REQUEST['ip'];
$WOL_HOST_MAC = $_REQUEST['mac'];
if (!filter_var($WOL_HOST_IP, FILTER_VALIDATE_IP)) {
if (!filter_var($WOL_HOST_IP, FILTER_VALIDATE_IP)) {
echo "Invalid IP! ". lang('BackDevDetail_Tools_WOL_error'); exit;
}
elseif (!filter_var($WOL_HOST_MAC, FILTER_VALIDATE_MAC)) {
echo "Invalid MAC! ". lang('BackDevDetail_Tools_WOL_error'); exit;
}
elseif (!filter_var($WOL_HOST_MAC, FILTER_VALIDATE_MAC)) {
echo "Invalid MAC! ". lang('BackDevDetail_Tools_WOL_error'); exit;
}
exec('wakeonlan '.$WOL_HOST_MAC , $output);
@@ -792,14 +791,14 @@ function wakeonlan() {
//------------------------------------------------------------------------------
// Copy from device
//------------------------------------------------------------------------------
function copyFromDevice() {
function copyFromDevice() {
$MAC_FROM = $_REQUEST['macFrom'];
$MAC_TO = $_REQUEST['macTo'];
global $db;
// clean-up temporary table
// clean-up temporary table
$sql = "DROP TABLE IF EXISTS temp_devices ";
$result = $db->query($sql);
@@ -810,7 +809,7 @@ function copyFromDevice() {
// update temporary table with the correct target MAC
$sql = "UPDATE temp_devices SET devMac = '". $MAC_TO . "';";
$result = $db->query($sql);
// delete previous entry
$sql = "DELETE FROM Devices WHERE devMac = '". $MAC_TO . "';";
$result = $db->query($sql);
@@ -828,8 +827,8 @@ function copyFromDevice() {
echo 'OK';
} else {
echo lang('BackDevices_Device_UpdDevError');
}
}
}
//------------------------------------------------------------------------------
@@ -845,7 +844,7 @@ function getDeviceCondition ($deviceStatus) {
case 'down': return 'WHERE devIsArchived=0 AND devAlertDown !=0 AND devPresentLastScan=0'; break;
case 'archived': return 'WHERE devIsArchived=1'; break;
default: return 'WHERE 1=0'; break;
}
}
}

View File

@@ -345,8 +345,7 @@ function formatDataSize(bytes) {
function loadInterfaces() {
const apiToken = getSetting("API_TOKEN"); // replace with dynamic token if available
const apiToken = getSetting("API_TOKEN");
const host = window.location.hostname;
const port = getSetting("GRAPHQL_PORT");

View File

@@ -500,96 +500,112 @@ class DeviceInstance:
def setDeviceData(self, mac, data):
"""Update or create a device."""
if data.get("createNew", False):
sql = """
INSERT INTO Devices (
devMac, devName, devOwner, devType, devVendor, devIcon,
devFavorite, devGroup, devLocation, devComments,
devParentMAC, devParentPort, devSSID, devSite,
devStaticIP, devScan, devAlertEvents, devAlertDown,
devParentRelType, devReqNicsOnline, devSkipRepeated,
devIsNew, devIsArchived, devLastConnection,
devFirstConnection, devLastIP, devGUID, devCustomProps,
devSourcePlugin
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
"""
try:
if data.get("createNew", False):
sql = """
INSERT INTO Devices (
devMac, devName, devOwner, devType, devVendor, devIcon,
devFavorite, devGroup, devLocation, devComments,
devParentMAC, devParentPort, devSSID, devSite,
devStaticIP, devScan, devAlertEvents, devAlertDown,
devParentRelType, devReqNicsOnline, devSkipRepeated,
devIsNew, devIsArchived, devLastConnection,
devFirstConnection, devLastIP, devGUID, devCustomProps,
devSourcePlugin
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
"""
values = (
mac,
data.get("devName", ""),
data.get("devOwner", ""),
data.get("devType", ""),
data.get("devVendor", ""),
data.get("devIcon", ""),
data.get("devFavorite", 0),
data.get("devGroup", ""),
data.get("devLocation", ""),
data.get("devComments", ""),
data.get("devParentMAC", ""),
data.get("devParentPort", ""),
data.get("devSSID", ""),
data.get("devSite", ""),
data.get("devStaticIP", 0),
data.get("devScan", 0),
data.get("devAlertEvents", 0),
data.get("devAlertDown", 0),
data.get("devParentRelType", "default"),
data.get("devReqNicsOnline", 0),
data.get("devSkipRepeated", 0),
data.get("devIsNew", 0),
data.get("devIsArchived", 0),
data.get("devLastConnection", timeNowDB()),
data.get("devFirstConnection", timeNowDB()),
data.get("devLastIP", ""),
data.get("devGUID", ""),
data.get("devCustomProps", ""),
data.get("devSourcePlugin", "DUMMY"),
)
values = (
mac,
data.get("devName", ""),
data.get("devOwner", ""),
data.get("devType", ""),
data.get("devVendor", ""),
data.get("devIcon", ""),
data.get("devFavorite", 0),
data.get("devGroup", ""),
data.get("devLocation", ""),
data.get("devComments", ""),
data.get("devParentMAC", ""),
data.get("devParentPort", ""),
data.get("devSSID", ""),
data.get("devSite", ""),
data.get("devStaticIP", 0),
data.get("devScan", 0),
data.get("devAlertEvents", 0),
data.get("devAlertDown", 0),
data.get("devParentRelType", "default"),
data.get("devReqNicsOnline", 0),
data.get("devSkipRepeated", 0),
data.get("devIsNew", 0),
data.get("devIsArchived", 0),
data.get("devLastConnection", timeNowDB()),
data.get("devFirstConnection", timeNowDB()),
data.get("devLastIP", ""),
data.get("devGUID", ""),
data.get("devCustomProps", ""),
data.get("devSourcePlugin", "DUMMY"),
)
else:
sql = """
UPDATE Devices SET
devName=?, devOwner=?, devType=?, devVendor=?, devIcon=?,
devFavorite=?, devGroup=?, devLocation=?, devComments=?,
devParentMAC=?, devParentPort=?, devSSID=?, devSite=?,
devStaticIP=?, devScan=?, devAlertEvents=?, devAlertDown=?,
devParentRelType=?, devReqNicsOnline=?, devSkipRepeated=?,
devIsNew=?, devIsArchived=?, devCustomProps=?
WHERE devMac=?
"""
values = (
data.get("devName", ""),
data.get("devOwner", ""),
data.get("devType", ""),
data.get("devVendor", ""),
data.get("devIcon", ""),
data.get("devFavorite", 0),
data.get("devGroup", ""),
data.get("devLocation", ""),
data.get("devComments", ""),
data.get("devParentMAC", ""),
data.get("devParentPort", ""),
data.get("devSSID", ""),
data.get("devSite", ""),
data.get("devStaticIP", 0),
data.get("devScan", 0),
data.get("devAlertEvents", 0),
data.get("devAlertDown", 0),
data.get("devParentRelType", "default"),
data.get("devReqNicsOnline", 0),
data.get("devSkipRepeated", 0),
data.get("devIsNew", 0),
data.get("devIsArchived", 0),
data.get("devCustomProps", ""),
mac,
)
else:
sql = """
UPDATE Devices SET
devName=?, devOwner=?, devType=?, devVendor=?, devIcon=?,
devFavorite=?, devGroup=?, devLocation=?, devComments=?,
devParentMAC=?, devParentPort=?, devSSID=?, devSite=?,
devStaticIP=?, devScan=?, devAlertEvents=?, devAlertDown=?,
devParentRelType=?, devReqNicsOnline=?, devSkipRepeated=?,
devIsNew=?, devIsArchived=?, devCustomProps=?
WHERE devMac=?
"""
values = (
data.get("devName", ""),
data.get("devOwner", ""),
data.get("devType", ""),
data.get("devVendor", ""),
data.get("devIcon", ""),
data.get("devFavorite", 0),
data.get("devGroup", ""),
data.get("devLocation", ""),
data.get("devComments", ""),
data.get("devParentMAC", ""),
data.get("devParentPort", ""),
data.get("devSSID", ""),
data.get("devSite", ""),
data.get("devStaticIP", 0),
data.get("devScan", 0),
data.get("devAlertEvents", 0),
data.get("devAlertDown", 0),
data.get("devParentRelType", "default"),
data.get("devReqNicsOnline", 0),
data.get("devSkipRepeated", 0),
data.get("devIsNew", 0),
data.get("devIsArchived", 0),
data.get("devCustomProps", ""),
mac,
)
conn = get_temp_db_connection()
cur = conn.cursor()
cur.execute(sql, values)
conn.commit()
conn.close()
return {"success": True}
conn = get_temp_db_connection()
cur = conn.cursor()
cur.execute(sql, values)
conn.commit()
conn.close()
return {"success": True}
except Exception as e:
if conn:
conn.rollback()
# Optional: your existing logger
mylog("none", f"[DeviceInstance] setDeviceData({mac}) failed: {e}")
return {
"success": False,
"error": str(e)
}
finally:
if conn:
conn.close()
def deleteDeviceByMAC(self, mac):
"""Delete a device by MAC."""