diff --git a/docs/PLUGINS_DEV.md b/docs/PLUGINS_DEV.md index 5176131f..1bfaf854 100755 --- a/docs/PLUGINS_DEV.md +++ b/docs/PLUGINS_DEV.md @@ -34,7 +34,7 @@ NetAlertX comes with a plugin system to feed events from third-party scripts int ### 🐛 Troubleshooting - **[Debugging Plugins](DEBUG_PLUGINS.md)** - Troubleshoot plugin issues -- **[Plugin Examples](../front/plugins)** - Study existing plugins as reference implementations +- **[Plugin Examples](https://github.com/netalertx/NetAlertX/tree/main/front/plugins)** - Study existing plugins as reference implementations ### 🎥 Video Tutorial diff --git a/front/js/network-api.js b/front/js/network-api.js index 712f1024..ba8f9abe 100644 --- a/front/js/network-api.js +++ b/front/js/network-api.js @@ -17,10 +17,10 @@ function loadNetworkNodes() { const rawSql = ` SELECT parent.devName AS node_name, - parent.devMac AS node_mac, + LOWER(parent.devMac) AS node_mac, parent.devPresentLastScan AS online, parent.devType AS node_type, - parent.devParentMAC AS parent_mac, + LOWER(parent.devParentMAC) AS parent_mac, parent.devIcon AS node_icon, parent.devAlertDown AS node_alert, COUNT(child.devMac) AS node_ports_count @@ -116,6 +116,7 @@ function loadDeviceTable({ sql, containerSelector, tableId, wrapperHtml = null, orderable: false, width: '5%', render: function (mac) { + // mac = mac.toLowerCase() const label = assignMode ? 'assign' : 'unassign'; const btnClass = assignMode ? 'btn-primary' : 'btn-primary bg-red'; const btnText = assignMode ? getString('Network_ManageAssign') : getString('Network_ManageUnassign'); @@ -204,7 +205,7 @@ function loadUnassignedDevices() { SELECT devMac, devPresentLastScan, devName, devLastIP, devVendor, devAlertDown, devParentPort FROM Devices WHERE (devParentMAC IS NULL OR devParentMAC IN ("", " ", "undefined", "null")) - AND devMac NOT LIKE "%internet%" + AND LOWER(devMac) NOT LIKE "%internet%" AND devIsArchived = 0 ORDER BY devName ASC`; diff --git a/front/js/network-init.js b/front/js/network-init.js index b23364e4..474aba27 100644 --- a/front/js/network-init.js +++ b/front/js/network-init.js @@ -21,10 +21,12 @@ function initNetworkTopology() { // Always get all devices const rawSql = ` SELECT *, + LOWER(devMac) AS devMac, + LOWER(devParentMAC) AS devParentMAC, CASE - WHEN devAlertDown != 0 AND devPresentLastScan = 0 THEN "Down" - WHEN devPresentLastScan = 1 THEN "On-line" - ELSE "Off-line" + WHEN devAlertDown != 0 AND devPresentLastScan = 0 THEN 'Down' + WHEN devPresentLastScan = 1 THEN 'On-line' + ELSE 'Off-line' END AS devStatus, CASE WHEN devType IN (${networkDeviceTypes}) THEN 1 @@ -33,6 +35,7 @@ function initNetworkTopology() { FROM Devices a `; + const { token: apiToken, apiBase, authHeader } = getAuthContext(); // Verify token is available before making API call diff --git a/front/js/network-tabs.js b/front/js/network-tabs.js index 06096532..b8907b77 100644 --- a/front/js/network-tabs.js +++ b/front/js/network-tabs.js @@ -49,7 +49,7 @@ function renderNetworkTabContent(nodes) { $('.tab-content').empty(); nodes.forEach((node, i) => { - const id = node.node_mac.replace(/:/g, '_'); + const id = node.node_mac.replace(/:/g, '_').toLowerCase(); const badge = getStatusBadgeParts( node.online, diff --git a/front/plugins/website_monitor/config.json b/front/plugins/website_monitor/config.json index 49e19405..9aeb11f0 100755 --- a/front/plugins/website_monitor/config.json +++ b/front/plugins/website_monitor/config.json @@ -9,7 +9,7 @@ "display_name": [ { "language_code": "en_us", - "string": "Website monitor" + "string": "Services & Web monitor" }, { "language_code": "es_es", diff --git a/server/models/device_instance.py b/server/models/device_instance.py index d51fdf0a..94726753 100755 --- a/server/models/device_instance.py +++ b/server/models/device_instance.py @@ -463,46 +463,49 @@ class DeviceInstance: # Fetch device info + computed fields sql = f""" - SELECT - d.*, - CASE - WHEN d.devAlertDown != 0 AND d.devPresentLastScan = 0 THEN 'Down' - WHEN d.devPresentLastScan = 1 THEN 'On-line' - ELSE 'Off-line' - END AS devStatus, + SELECT + d.*, + LOWER(d.devMac) AS devMac, + LOWER(d.devParentMAC) AS devParentMAC, + CASE + WHEN d.devAlertDown != 0 AND d.devPresentLastScan = 0 THEN 'Down' + WHEN d.devPresentLastScan = 1 THEN 'On-line' + ELSE 'Off-line' + END AS devStatus, - (SELECT COUNT(*) FROM Sessions - WHERE ses_MAC = d.devMac AND ( - ses_DateTimeConnection >= {period_date_sql} OR - ses_DateTimeDisconnection >= {period_date_sql} OR - ses_StillConnected = 1 - )) AS devSessions, + (SELECT COUNT(*) FROM Sessions + WHERE LOWER(ses_MAC) = LOWER(d.devMac) AND ( + ses_DateTimeConnection >= {period_date_sql} OR + ses_DateTimeDisconnection >= {period_date_sql} OR + ses_StillConnected = 1 + )) AS devSessions, - (SELECT COUNT(*) FROM Events - WHERE eve_MAC = d.devMac AND eve_DateTime >= {period_date_sql} - AND eve_EventType NOT IN ('Connected','Disconnected')) AS devEvents, + (SELECT COUNT(*) FROM Events + WHERE LOWER(eve_MAC) = LOWER(d.devMac) AND eve_DateTime >= {period_date_sql} + AND eve_EventType NOT IN ('Connected','Disconnected')) AS devEvents, - (SELECT COUNT(*) FROM Events - WHERE eve_MAC = d.devMac AND eve_DateTime >= {period_date_sql} - AND eve_EventType = 'Device Down') AS devDownAlerts, + (SELECT COUNT(*) FROM Events + WHERE LOWER(eve_MAC) = LOWER(d.devMac) AND eve_DateTime >= {period_date_sql} + AND eve_EventType = 'Device Down') AS devDownAlerts, - (SELECT CAST(MAX(0, SUM( - julianday(IFNULL(ses_DateTimeDisconnection,'{now}')) - - julianday(CASE WHEN ses_DateTimeConnection < {period_date_sql} - THEN {period_date_sql} 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 (ses_DateTimeConnection >= {period_date_sql} - OR ses_DateTimeDisconnection >= {period_date_sql} OR ses_StillConnected = 1) - ) AS devPresenceHours + (SELECT CAST(MAX(0, SUM( + julianday(IFNULL(ses_DateTimeDisconnection,'{now}')) - + julianday(CASE WHEN ses_DateTimeConnection < {period_date_sql} + THEN {period_date_sql} ELSE ses_DateTimeConnection END) + ) * 24) AS INT) + FROM Sessions + WHERE LOWER(ses_MAC) = LOWER(d.devMac) + AND ses_DateTimeConnection IS NOT NULL + AND (ses_DateTimeDisconnection IS NOT NULL OR ses_StillConnected = 1) + AND (ses_DateTimeConnection >= {period_date_sql} + OR ses_DateTimeDisconnection >= {period_date_sql} OR ses_StillConnected = 1) + ) AS devPresenceHours - FROM Devices d - WHERE d.devMac = ? OR CAST(d.rowid AS TEXT) = ? + FROM Devices d + WHERE LOWER(d.devMac) = LOWER(?) OR CAST(d.rowid AS TEXT) = ? """ + conn = get_temp_db_connection() cur = conn.cursor() cur.execute(sql, (mac, mac)) @@ -818,9 +821,9 @@ class DeviceInstance: conn = get_temp_db_connection() cur = conn.cursor() - # Build safe SQL with column name - sql = f"UPDATE Devices SET {column_name}=? WHERE devMac=?" - cur.execute(sql, (column_value, mac)) + # Convert the MAC to lowercase for comparison + sql = f"UPDATE Devices SET {column_name}=? WHERE LOWER(devMac)=?" + cur.execute(sql, (column_value, mac.lower())) conn.commit() if cur.rowcount > 0: @@ -831,6 +834,7 @@ class DeviceInstance: conn.close() return result + def lockDeviceField(self, mac, field_name): """Lock a device field so it won't be overwritten by plugins.""" if field_name not in FIELD_SOURCE_MAP: