Refactor event and session column names to camelCase

- Updated test cases to reflect new column names (eve_MAC -> eveMac, eve_DateTime -> eveDateTime, etc.) across various test files.
- Modified SQL table definitions in the database cleanup and migration tests to use camelCase naming conventions.
- Implemented migration tests to ensure legacy column names are correctly renamed to camelCase equivalents.
- Ensured that existing data is preserved during the migration process and that views referencing old column names are dropped before renaming.
- Verified that the migration function is idempotent, allowing for safe re-execution without data loss.
This commit is contained in:
Jokob @NetAlertX
2026-03-16 10:11:22 +00:00
parent 0bb6db155b
commit c7399215ec
109 changed files with 2403 additions and 1967 deletions

View File

@@ -154,30 +154,30 @@ class LangStringResult(ObjectType):
# --- APP EVENTS ---
class AppEvent(ObjectType):
Index = Int(description="Internal index")
GUID = String(description="Unique event GUID")
AppEventProcessed = Int(description="Processing status (0 or 1)")
DateTimeCreated = String(description="Event creation timestamp")
index = Int(description="Internal index")
guid = String(description="Unique event GUID")
appEventProcessed = Int(description="Processing status (0 or 1)")
dateTimeCreated = String(description="Event creation timestamp")
ObjectType = String(description="Type of the related object (Device, Setting, etc.)")
ObjectGUID = String(description="GUID of the related object")
ObjectPlugin = String(description="Plugin associated with the object")
ObjectPrimaryID = String(description="Primary identifier of the object")
ObjectSecondaryID = String(description="Secondary identifier of the object")
ObjectForeignKey = String(description="Foreign key reference")
ObjectIndex = Int(description="Object index")
objectType = String(description="Type of the related object (Device, Setting, etc.)")
objectGuid = String(description="GUID of the related object")
objectPlugin = String(description="Plugin associated with the object")
objectPrimaryId = String(description="Primary identifier of the object")
objectSecondaryId = String(description="Secondary identifier of the object")
objectForeignKey = String(description="Foreign key reference")
objectIndex = Int(description="Object index")
ObjectIsNew = Int(description="Is the object new? (0 or 1)")
ObjectIsArchived = Int(description="Is the object archived? (0 or 1)")
ObjectStatusColumn = String(description="Column used for status")
ObjectStatus = String(description="Object status value")
objectIsNew = Int(description="Is the object new? (0 or 1)")
objectIsArchived = Int(description="Is the object archived? (0 or 1)")
objectStatusColumn = String(description="Column used for status")
objectStatus = String(description="Object status value")
AppEventType = String(description="Type of application event")
appEventType = String(description="Type of application event")
Helper1 = String(description="Generic helper field 1")
Helper2 = String(description="Generic helper field 2")
Helper3 = String(description="Generic helper field 3")
Extra = String(description="Additional JSON data")
helper1 = String(description="Generic helper field 1")
helper2 = String(description="Generic helper field 2")
helper3 = String(description="Generic helper field 3")
extra = String(description="Additional JSON data")
class AppEventResult(ObjectType):
@@ -499,18 +499,18 @@ class Query(ObjectType):
search_term = options.search.lower()
searchable_fields = [
"GUID",
"ObjectType",
"ObjectGUID",
"ObjectPlugin",
"ObjectPrimaryID",
"ObjectSecondaryID",
"ObjectStatus",
"AppEventType",
"Helper1",
"Helper2",
"Helper3",
"Extra",
"guid",
"objectType",
"objectGuid",
"objectPlugin",
"objectPrimaryId",
"objectSecondaryId",
"objectStatus",
"appEventType",
"helper1",
"helper2",
"helper3",
"extra",
]
events_data = [
@@ -616,9 +616,9 @@ class Query(ObjectType):
plugin_data = json.load(f).get("data", [])
plugin_list = [
LangString(
langCode=entry.get("Language_Code"),
langStringKey=entry.get("String_Key"),
langStringText=entry.get("String_Value")
langCode=entry.get("languageCode"),
langStringKey=entry.get("stringKey"),
langStringText=entry.get("stringValue")
) for entry in plugin_data
]
_langstrings_cache[cache_key] = plugin_list

View File

@@ -33,8 +33,8 @@ def create_session(
cur.execute(
"""
INSERT INTO Sessions (ses_MAC, ses_IP, ses_DateTimeConnection, ses_DateTimeDisconnection,
ses_EventTypeConnection, ses_EventTypeDisconnection)
INSERT INTO Sessions (sesMac, sesIp, sesDateTimeConnection, sesDateTimeDisconnection,
sesEventTypeConnection, sesEventTypeDisconnection)
VALUES (?, ?, ?, ?, ?, ?)
""",
(mac, ip, start_time, end_time, event_type_conn, event_type_disc),
@@ -52,7 +52,7 @@ def delete_session(mac):
conn = get_temp_db_connection()
cur = conn.cursor()
cur.execute("DELETE FROM Sessions WHERE ses_MAC = ?", (mac,))
cur.execute("DELETE FROM Sessions WHERE sesMac = ?", (mac,))
conn.commit()
conn.close()
@@ -69,13 +69,13 @@ def get_sessions(mac=None, start_date=None, end_date=None):
params = []
if mac:
sql += " AND ses_MAC = ?"
sql += " AND sesMac = ?"
params.append(mac)
if start_date:
sql += " AND ses_DateTimeConnection >= ?"
sql += " AND sesDateTimeConnection >= ?"
params.append(start_date)
if end_date:
sql += " AND ses_DateTimeDisconnection <= ?"
sql += " AND sesDateTimeDisconnection <= ?"
params.append(end_date)
cur.execute(sql, tuple(params))
@@ -106,49 +106,49 @@ def get_sessions_calendar(start_date, end_date, mac):
sql = """
SELECT
SES1.ses_MAC,
SES1.ses_EventTypeConnection,
SES1.ses_DateTimeConnection,
SES1.ses_EventTypeDisconnection,
SES1.ses_DateTimeDisconnection,
SES1.ses_IP,
SES1.ses_AdditionalInfo,
SES1.ses_StillConnected,
SES1.sesMac,
SES1.sesEventTypeConnection,
SES1.sesDateTimeConnection,
SES1.sesEventTypeDisconnection,
SES1.sesDateTimeDisconnection,
SES1.sesIp,
SES1.sesAdditionalInfo,
SES1.sesStillConnected,
CASE
WHEN SES1.ses_EventTypeConnection = '<missing event>' THEN
WHEN SES1.sesEventTypeConnection = '<missing event>' THEN
IFNULL(
(
SELECT MAX(SES2.ses_DateTimeDisconnection)
SELECT MAX(SES2.sesDateTimeDisconnection)
FROM Sessions AS SES2
WHERE SES2.ses_MAC = SES1.ses_MAC
AND SES2.ses_DateTimeDisconnection < SES1.ses_DateTimeDisconnection
AND SES2.ses_DateTimeDisconnection BETWEEN Date(?) AND Date(?)
WHERE SES2.sesMac = SES1.sesMac
AND SES2.sesDateTimeDisconnection < SES1.sesDateTimeDisconnection
AND SES2.sesDateTimeDisconnection BETWEEN Date(?) AND Date(?)
),
DATETIME(SES1.ses_DateTimeDisconnection, '-1 hour')
DATETIME(SES1.sesDateTimeDisconnection, '-1 hour')
)
ELSE SES1.ses_DateTimeConnection
END AS ses_DateTimeConnectionCorrected,
ELSE SES1.sesDateTimeConnection
END AS sesDateTimeConnectionCorrected,
CASE
WHEN SES1.ses_EventTypeDisconnection = '<missing event>' THEN
WHEN SES1.sesEventTypeDisconnection = '<missing event>' THEN
(
SELECT MIN(SES2.ses_DateTimeConnection)
SELECT MIN(SES2.sesDateTimeConnection)
FROM Sessions AS SES2
WHERE SES2.ses_MAC = SES1.ses_MAC
AND SES2.ses_DateTimeConnection > SES1.ses_DateTimeConnection
AND SES2.ses_DateTimeConnection BETWEEN Date(?) AND Date(?)
WHERE SES2.sesMac = SES1.sesMac
AND SES2.sesDateTimeConnection > SES1.sesDateTimeConnection
AND SES2.sesDateTimeConnection BETWEEN Date(?) AND Date(?)
)
ELSE SES1.ses_DateTimeDisconnection
END AS ses_DateTimeDisconnectionCorrected
ELSE SES1.sesDateTimeDisconnection
END AS sesDateTimeDisconnectionCorrected
FROM Sessions AS SES1
WHERE (
(SES1.ses_DateTimeConnection BETWEEN Date(?) AND Date(?))
OR (SES1.ses_DateTimeDisconnection BETWEEN Date(?) AND Date(?))
OR SES1.ses_StillConnected = 1
(SES1.sesDateTimeConnection BETWEEN Date(?) AND Date(?))
OR (SES1.sesDateTimeDisconnection BETWEEN Date(?) AND Date(?))
OR SES1.sesStillConnected = 1
)
AND (? IS NULL OR SES1.ses_MAC = ?)
AND (? IS NULL OR SES1.sesMac = ?)
"""
cur.execute(
@@ -173,31 +173,31 @@ def get_sessions_calendar(start_date, end_date, mac):
# Color logic (unchanged from PHP)
if (
row["ses_EventTypeConnection"] == "<missing event>" or row["ses_EventTypeDisconnection"] == "<missing event>"
row["sesEventTypeConnection"] == "<missing event>" or row["sesEventTypeDisconnection"] == "<missing event>"
):
color = "#f39c12"
elif row["ses_StillConnected"] == 1:
elif row["sesStillConnected"] == 1:
color = "#00a659"
else:
color = "#0073b7"
# --- IMPORTANT FIX ---
# FullCalendar v3 CANNOT handle end = null
end_dt = row["ses_DateTimeDisconnectionCorrected"]
if not end_dt and row["ses_StillConnected"] == 1:
end_dt = row["sesDateTimeDisconnectionCorrected"]
if not end_dt and row["sesStillConnected"] == 1:
end_dt = now_iso
tooltip = (
f"Connection: {format_event_date(row['ses_DateTimeConnection'], row['ses_EventTypeConnection'])}\n"
f"Disconnection: {format_event_date(row['ses_DateTimeDisconnection'], row['ses_EventTypeDisconnection'])}\n"
f"IP: {row['ses_IP']}"
f"Connection: {format_event_date(row['sesDateTimeConnection'], row['sesEventTypeConnection'])}\n"
f"Disconnection: {format_event_date(row['sesDateTimeDisconnection'], row['sesEventTypeDisconnection'])}\n"
f"IP: {row['sesIp']}"
)
events.append(
{
"resourceId": row["ses_MAC"],
"resourceId": row["sesMac"],
"title": "",
"start": format_date_iso(row["ses_DateTimeConnectionCorrected"]),
"start": format_date_iso(row["sesDateTimeConnectionCorrected"]),
"end": format_date_iso(end_dt),
"color": color,
"tooltip": tooltip,
@@ -219,20 +219,20 @@ def get_device_sessions(mac, period):
sql = f"""
SELECT
IFNULL(ses_DateTimeConnection, ses_DateTimeDisconnection) AS ses_DateTimeOrder,
ses_EventTypeConnection,
ses_DateTimeConnection,
ses_EventTypeDisconnection,
ses_DateTimeDisconnection,
ses_StillConnected,
ses_IP,
ses_AdditionalInfo
IFNULL(sesDateTimeConnection, sesDateTimeDisconnection) AS sesDateTimeOrder,
sesEventTypeConnection,
sesDateTimeConnection,
sesEventTypeDisconnection,
sesDateTimeDisconnection,
sesStillConnected,
sesIp,
sesAdditionalInfo
FROM Sessions
WHERE ses_MAC = ?
WHERE sesMac = ?
AND (
ses_DateTimeConnection >= {period_date}
OR ses_DateTimeDisconnection >= {period_date}
OR ses_StillConnected = 1
sesDateTimeConnection >= {period_date}
OR sesDateTimeDisconnection >= {period_date}
OR sesStillConnected = 1
)
"""
@@ -245,44 +245,44 @@ def get_device_sessions(mac, period):
for row in rows:
# Connection DateTime
if row["ses_EventTypeConnection"] == "<missing event>":
ini = row["ses_EventTypeConnection"]
if row["sesEventTypeConnection"] == "<missing event>":
ini = row["sesEventTypeConnection"]
else:
ini = format_date(row["ses_DateTimeConnection"])
ini = format_date(row["sesDateTimeConnection"])
# Disconnection DateTime
if row["ses_StillConnected"]:
if row["sesStillConnected"]:
end = "..."
elif row["ses_EventTypeDisconnection"] == "<missing event>":
end = row["ses_EventTypeDisconnection"]
elif row["sesEventTypeDisconnection"] == "<missing event>":
end = row["sesEventTypeDisconnection"]
else:
end = format_date(row["ses_DateTimeDisconnection"])
end = format_date(row["sesDateTimeDisconnection"])
# Duration
if row["ses_EventTypeConnection"] in ("<missing event>", None) or row[
"ses_EventTypeDisconnection"
if row["sesEventTypeConnection"] in ("<missing event>", None) or row[
"sesEventTypeDisconnection"
] in ("<missing event>", None):
dur = "..."
elif row["ses_StillConnected"]:
dur = format_date_diff(row["ses_DateTimeConnection"], None, tz_name)["text"]
elif row["sesStillConnected"]:
dur = format_date_diff(row["sesDateTimeConnection"], None, tz_name)["text"]
else:
dur = format_date_diff(row["ses_DateTimeConnection"], row["ses_DateTimeDisconnection"], tz_name)["text"]
dur = format_date_diff(row["sesDateTimeConnection"], row["sesDateTimeDisconnection"], tz_name)["text"]
# Additional Info
info = row["ses_AdditionalInfo"]
if row["ses_EventTypeConnection"] == "New Device":
info = f"{row['ses_EventTypeConnection']}: {info}"
info = row["sesAdditionalInfo"]
if row["sesEventTypeConnection"] == "New Device":
info = f"{row['sesEventTypeConnection']}: {info}"
# Push row data
table_data["data"].append(
{
"ses_MAC": mac,
"ses_DateTimeOrder": row["ses_DateTimeOrder"],
"ses_Connection": ini,
"ses_Disconnection": end,
"ses_Duration": dur,
"ses_IP": row["ses_IP"],
"ses_Info": info,
"sesMac": mac,
"sesDateTimeOrder": row["sesDateTimeOrder"],
"sesConnection": ini,
"sesDisconnection": end,
"sesDuration": dur,
"sesIp": row["sesIp"],
"sesInfo": info,
}
)
@@ -307,42 +307,42 @@ def get_session_events(event_type, period_date):
# Base SQLs
sql_events = f"""
SELECT
eve_DateTime AS eve_DateTimeOrder,
eveDateTime AS eveDateTimeOrder,
devName,
devOwner,
eve_DateTime,
eve_EventType,
eveDateTime,
eveEventType,
NULL,
NULL,
NULL,
NULL,
eve_IP,
eveIp,
NULL,
eve_AdditionalInfo,
eveAdditionalInfo,
NULL,
devMac,
eve_PendingAlertEmail
evePendingAlertEmail
FROM Events_Devices
WHERE eve_DateTime >= {period_date}
WHERE eveDateTime >= {period_date}
"""
sql_sessions = """
SELECT
IFNULL(ses_DateTimeConnection, ses_DateTimeDisconnection) AS ses_DateTimeOrder,
IFNULL(sesDateTimeConnection, sesDateTimeDisconnection) AS sesDateTimeOrder,
devName,
devOwner,
NULL,
NULL,
ses_DateTimeConnection,
ses_DateTimeDisconnection,
sesDateTimeConnection,
sesDateTimeDisconnection,
NULL,
NULL,
ses_IP,
sesIp,
NULL,
ses_AdditionalInfo,
ses_StillConnected,
sesAdditionalInfo,
sesStillConnected,
devMac,
0 AS ses_PendingAlertEmail
0 AS sesPendingAlertEmail
FROM Sessions_Devices
"""
@@ -353,9 +353,9 @@ def get_session_events(event_type, period_date):
sql = (
sql_sessions + f"""
WHERE (
ses_DateTimeConnection >= {period_date}
OR ses_DateTimeDisconnection >= {period_date}
OR ses_StillConnected = 1
sesDateTimeConnection >= {period_date}
OR sesDateTimeDisconnection >= {period_date}
OR sesStillConnected = 1
)
"""
)
@@ -363,17 +363,17 @@ def get_session_events(event_type, period_date):
sql = (
sql_sessions + f"""
WHERE (
(ses_DateTimeConnection IS NULL AND ses_DateTimeDisconnection >= {period_date})
OR (ses_DateTimeDisconnection IS NULL AND ses_StillConnected = 0 AND ses_DateTimeConnection >= {period_date})
(sesDateTimeConnection IS NULL AND sesDateTimeDisconnection >= {period_date})
OR (sesDateTimeDisconnection IS NULL AND sesStillConnected = 0 AND sesDateTimeConnection >= {period_date})
)
"""
)
elif event_type == "voided":
sql = sql_events + ' AND eve_EventType LIKE "VOIDED%"'
sql = sql_events + ' AND eveEventType LIKE "VOIDED%"'
elif event_type == "new":
sql = sql_events + ' AND eve_EventType = "New Device"'
sql = sql_events + ' AND eveEventType = "New Device"'
elif event_type == "down":
sql = sql_events + ' AND eve_EventType = "Device Down"'
sql = sql_events + ' AND eveEventType = "Device Down"'
else:
sql = sql_events + " AND 1=0"

View File

@@ -67,7 +67,7 @@ sql_devices_all = """
FROM DevicesView
"""
sql_appevents = """select * from AppEvents order by DateTimeCreated desc"""
sql_appevents = """select * from AppEvents order by dateTimeCreated desc"""
# The below query calculates counts of devices in various categories:
# (connected/online, offline, down, new, archived),
# as well as a combined count for devices that match any status listed in the UI_MY_DEVICES setting
@@ -141,32 +141,32 @@ sql_devices_filters = """
sql_devices_stats = f"""
SELECT
Online_Devices as online,
Down_Devices as down,
All_Devices as 'all',
Archived_Devices as archived,
onlineDevices as online,
downDevices as down,
allDevices as 'all',
archivedDevices as archived,
(SELECT COUNT(*) FROM Devices a WHERE devIsNew = 1) as new,
(SELECT COUNT(*) FROM Devices a WHERE devName IN ({NULL_EQUIVALENTS_SQL}) OR devName IS NULL) as unknown
FROM Online_History
ORDER BY Scan_Date DESC
ORDER BY scanDate DESC
LIMIT 1
"""
sql_events_pending_alert = "SELECT * FROM Events where eve_PendingAlertEmail is not 0"
sql_events_pending_alert = "SELECT * FROM Events where evePendingAlertEmail is not 0"
sql_settings = "SELECT * FROM Settings"
sql_plugins_objects = "SELECT * FROM Plugins_Objects"
sql_language_strings = "SELECT * FROM Plugins_Language_Strings"
sql_notifications_all = "SELECT * FROM Notifications"
sql_online_history = "SELECT * FROM Online_History"
sql_plugins_events = "SELECT * FROM Plugins_Events"
sql_plugins_history = "SELECT * FROM Plugins_History ORDER BY DateTimeChanged DESC"
sql_plugins_history = "SELECT * FROM Plugins_History ORDER BY dateTimeChanged DESC"
sql_new_devices = """SELECT * FROM (
SELECT eve_IP as devLastIP,
eve_MAC as devMac,
MAX(eve_DateTime) as lastEvent
SELECT eveIp as devLastIP,
eveMac as devMac,
MAX(eveDateTime) as lastEvent
FROM Events_Devices
WHERE eve_PendingAlertEmail = 1
AND eve_EventType = 'New Device'
GROUP BY eve_MAC
WHERE evePendingAlertEmail = 1
AND eveEventType = 'New Device'
GROUP BY eveMac
ORDER BY lastEvent
) t1
LEFT JOIN

View File

@@ -16,6 +16,7 @@ from db.db_upgrade import (
ensure_Settings,
ensure_Indexes,
ensure_mac_lowercase_triggers,
migrate_to_camelcase,
migrate_timestamps_to_utc,
)
@@ -194,6 +195,10 @@ class DB:
if not ensure_column(self.sql, "Devices", "devCanSleep", "INTEGER"):
raise RuntimeError("ensure_column(devCanSleep) failed")
# CamelCase column migration (must run before UTC migration and
# before ensure_plugins_tables which uses IF NOT EXISTS with new names)
migrate_to_camelcase(self.sql)
# Settings table setup
ensure_Settings(self.sql)

View File

@@ -157,7 +157,7 @@ def ensure_views(sql) -> bool:
sql.execute(""" CREATE VIEW Events_Devices AS
SELECT *
FROM Events
LEFT JOIN Devices ON eve_MAC = devMac;
LEFT JOIN Devices ON eveMac = devMac;
""")
sql.execute(""" DROP VIEW IF EXISTS LatestEventsPerMAC;""")
@@ -165,7 +165,7 @@ def ensure_views(sql) -> bool:
WITH RankedEvents AS (
SELECT
e.*,
ROW_NUMBER() OVER (PARTITION BY e.eve_MAC ORDER BY e.eve_DateTime DESC) AS row_num
ROW_NUMBER() OVER (PARTITION BY e.eveMac ORDER BY e.eveDateTime DESC) AS row_num
FROM Events AS e
)
SELECT
@@ -173,43 +173,43 @@ def ensure_views(sql) -> bool:
d.*,
c.*
FROM RankedEvents AS e
LEFT JOIN Devices AS d ON e.eve_MAC = d.devMac
INNER JOIN CurrentScan AS c ON e.eve_MAC = c.scanMac
LEFT JOIN Devices AS d ON e.eveMac = d.devMac
INNER JOIN CurrentScan AS c ON e.eveMac = c.scanMac
WHERE e.row_num = 1;""")
sql.execute(""" DROP VIEW IF EXISTS Sessions_Devices;""")
sql.execute(
"""CREATE VIEW Sessions_Devices AS SELECT * FROM Sessions LEFT JOIN "Devices" ON ses_MAC = devMac;"""
"""CREATE VIEW Sessions_Devices AS SELECT * FROM Sessions LEFT JOIN "Devices" ON sesMac = devMac;"""
)
# handling the Convert_Events_to_Sessions / Sessions screens
sql.execute("""DROP VIEW IF EXISTS Convert_Events_to_Sessions;""")
sql.execute("""CREATE VIEW Convert_Events_to_Sessions AS SELECT EVE1.eve_MAC,
EVE1.eve_IP,
EVE1.eve_EventType AS eve_EventTypeConnection,
EVE1.eve_DateTime AS eve_DateTimeConnection,
CASE WHEN EVE2.eve_EventType IN ('Disconnected', 'Device Down') OR
EVE2.eve_EventType IS NULL THEN EVE2.eve_EventType ELSE '<missing event>' END AS eve_EventTypeDisconnection,
CASE WHEN EVE2.eve_EventType IN ('Disconnected', 'Device Down') THEN EVE2.eve_DateTime ELSE NULL END AS eve_DateTimeDisconnection,
CASE WHEN EVE2.eve_EventType IS NULL THEN 1 ELSE 0 END AS eve_StillConnected,
EVE1.eve_AdditionalInfo
sql.execute("""CREATE VIEW Convert_Events_to_Sessions AS SELECT EVE1.eveMac,
EVE1.eveIp,
EVE1.eveEventType AS eveEventTypeConnection,
EVE1.eveDateTime AS eveDateTimeConnection,
CASE WHEN EVE2.eveEventType IN ('Disconnected', 'Device Down') OR
EVE2.eveEventType IS NULL THEN EVE2.eveEventType ELSE '<missing event>' END AS eveEventTypeDisconnection,
CASE WHEN EVE2.eveEventType IN ('Disconnected', 'Device Down') THEN EVE2.eveDateTime ELSE NULL END AS eveDateTimeDisconnection,
CASE WHEN EVE2.eveEventType IS NULL THEN 1 ELSE 0 END AS eveStillConnected,
EVE1.eveAdditionalInfo
FROM Events AS EVE1
LEFT JOIN
Events AS EVE2 ON EVE1.eve_PairEventRowID = EVE2.RowID
WHERE EVE1.eve_EventType IN ('New Device', 'Connected','Down Reconnected')
Events AS EVE2 ON EVE1.evePairEventRowid = EVE2.RowID
WHERE EVE1.eveEventType IN ('New Device', 'Connected','Down Reconnected')
UNION
SELECT eve_MAC,
eve_IP,
'<missing event>' AS eve_EventTypeConnection,
NULL AS eve_DateTimeConnection,
eve_EventType AS eve_EventTypeDisconnection,
eve_DateTime AS eve_DateTimeDisconnection,
0 AS eve_StillConnected,
eve_AdditionalInfo
SELECT eveMac,
eveIp,
'<missing event>' AS eveEventTypeConnection,
NULL AS eveDateTimeConnection,
eveEventType AS eveEventTypeDisconnection,
eveDateTime AS eveDateTimeDisconnection,
0 AS eveStillConnected,
eveAdditionalInfo
FROM Events AS EVE1
WHERE (eve_EventType = 'Device Down' OR
eve_EventType = 'Disconnected') AND
EVE1.eve_PairEventRowID IS NULL;
WHERE (eveEventType = 'Device Down' OR
eveEventType = 'Disconnected') AND
EVE1.evePairEventRowid IS NULL;
""")
sql.execute(""" DROP VIEW IF EXISTS LatestDeviceScan;""")
@@ -316,10 +316,10 @@ def ensure_views(sql) -> bool:
WHEN EXISTS (
SELECT 1
FROM Events e
WHERE LOWER(e.eve_MAC) = LOWER(Devices.devMac)
AND e.eve_EventType IN ('Connected','Disconnected','Device Down','Down Reconnected')
AND e.eve_DateTime >= datetime('now', '-{FLAP_WINDOW_HOURS} hours')
GROUP BY e.eve_MAC
WHERE LOWER(e.eveMac) = LOWER(Devices.devMac)
AND e.eveEventType IN ('Connected','Disconnected','Device Down','Down Reconnected')
AND e.eveDateTime >= datetime('now', '-{FLAP_WINDOW_HOURS} hours')
GROUP BY e.eveMac
HAVING COUNT(*) >= {FLAP_THRESHOLD}
)
THEN 1
@@ -360,10 +360,10 @@ def ensure_Indexes(sql) -> bool:
SELECT MIN(rowid)
FROM Events
GROUP BY
eve_MAC,
eve_IP,
eve_EventType,
eve_DateTime
eveMac,
eveIp,
eveEventType,
eveDateTime
);
"""
@@ -373,32 +373,32 @@ def ensure_Indexes(sql) -> bool:
# Sessions
(
"idx_ses_mac_date",
"CREATE INDEX idx_ses_mac_date ON Sessions(ses_MAC, ses_DateTimeConnection, ses_DateTimeDisconnection, ses_StillConnected)",
"CREATE INDEX idx_ses_mac_date ON Sessions(sesMac, sesDateTimeConnection, sesDateTimeDisconnection, sesStillConnected)",
),
# Events
(
"idx_eve_mac_date_type",
"CREATE INDEX idx_eve_mac_date_type ON Events(eve_MAC, eve_DateTime, eve_EventType)",
"CREATE INDEX idx_eve_mac_date_type ON Events(eveMac, eveDateTime, eveEventType)",
),
(
"idx_eve_alert_pending",
"CREATE INDEX idx_eve_alert_pending ON Events(eve_PendingAlertEmail)",
"CREATE INDEX idx_eve_alert_pending ON Events(evePendingAlertEmail)",
),
(
"idx_eve_mac_datetime_desc",
"CREATE INDEX idx_eve_mac_datetime_desc ON Events(eve_MAC, eve_DateTime DESC)",
"CREATE INDEX idx_eve_mac_datetime_desc ON Events(eveMac, eveDateTime DESC)",
),
(
"idx_eve_pairevent",
"CREATE INDEX idx_eve_pairevent ON Events(eve_PairEventRowID)",
"CREATE INDEX idx_eve_pairevent ON Events(evePairEventRowid)",
),
(
"idx_eve_type_date",
"CREATE INDEX idx_eve_type_date ON Events(eve_EventType, eve_DateTime)",
"CREATE INDEX idx_eve_type_date ON Events(eveEventType, eveDateTime)",
),
(
"idx_events_unique",
"CREATE UNIQUE INDEX idx_events_unique ON Events (eve_MAC, eve_IP, eve_EventType, eve_DateTime)",
"CREATE UNIQUE INDEX idx_events_unique ON Events (eveMac, eveIp, eveEventType, eveDateTime)",
),
# Devices
("idx_dev_mac", "CREATE INDEX idx_dev_mac ON Devices(devMac)"),
@@ -436,15 +436,15 @@ def ensure_Indexes(sql) -> bool:
# Plugins_Objects
(
"idx_plugins_plugin_mac_ip",
"CREATE INDEX idx_plugins_plugin_mac_ip ON Plugins_Objects(Plugin, Object_PrimaryID, Object_SecondaryID)",
"CREATE INDEX idx_plugins_plugin_mac_ip ON Plugins_Objects(plugin, objectPrimaryId, objectSecondaryId)",
), # Issue #1251: Optimize name resolution lookup
# Plugins_History: covers both the db_cleanup window function
# (PARTITION BY Plugin ORDER BY DateTimeChanged DESC) and the
# API query (SELECT * … ORDER BY DateTimeChanged DESC).
# (PARTITION BY plugin ORDER BY dateTimeChanged DESC) and the
# API query (SELECT * … ORDER BY dateTimeChanged DESC).
# Without this, both ops do a full 48k-row table sort on every cycle.
(
"idx_plugins_history_plugin_dt",
"CREATE INDEX idx_plugins_history_plugin_dt ON Plugins_History(Plugin, DateTimeChanged DESC)",
"CREATE INDEX idx_plugins_history_plugin_dt ON Plugins_History(plugin, dateTimeChanged DESC)",
),
]
@@ -547,94 +547,295 @@ def ensure_plugins_tables(sql) -> bool:
# Plugin state
sql_Plugins_Objects = """ CREATE TABLE IF NOT EXISTS Plugins_Objects(
"Index" INTEGER,
Plugin TEXT NOT NULL,
Object_PrimaryID TEXT NOT NULL,
Object_SecondaryID TEXT NOT NULL,
DateTimeCreated TEXT NOT NULL,
DateTimeChanged TEXT NOT NULL,
Watched_Value1 TEXT NOT NULL,
Watched_Value2 TEXT NOT NULL,
Watched_Value3 TEXT NOT NULL,
Watched_Value4 TEXT NOT NULL,
Status TEXT NOT NULL,
Extra TEXT NOT NULL,
UserData TEXT NOT NULL,
ForeignKey TEXT NOT NULL,
SyncHubNodeName TEXT,
"HelpVal1" TEXT,
"HelpVal2" TEXT,
"HelpVal3" TEXT,
"HelpVal4" TEXT,
ObjectGUID TEXT,
PRIMARY KEY("Index" AUTOINCREMENT)
"index" INTEGER,
plugin TEXT NOT NULL,
objectPrimaryId TEXT NOT NULL,
objectSecondaryId TEXT NOT NULL,
dateTimeCreated TEXT NOT NULL,
dateTimeChanged TEXT NOT NULL,
watchedValue1 TEXT NOT NULL,
watchedValue2 TEXT NOT NULL,
watchedValue3 TEXT NOT NULL,
watchedValue4 TEXT NOT NULL,
"status" TEXT NOT NULL,
extra TEXT NOT NULL,
userData TEXT NOT NULL,
foreignKey TEXT NOT NULL,
syncHubNodeName TEXT,
helpVal1 TEXT,
helpVal2 TEXT,
helpVal3 TEXT,
helpVal4 TEXT,
objectGuid TEXT,
PRIMARY KEY("index" AUTOINCREMENT)
); """
sql.execute(sql_Plugins_Objects)
# Plugin execution results
sql_Plugins_Events = """ CREATE TABLE IF NOT EXISTS Plugins_Events(
"Index" INTEGER,
Plugin TEXT NOT NULL,
Object_PrimaryID TEXT NOT NULL,
Object_SecondaryID TEXT NOT NULL,
DateTimeCreated TEXT NOT NULL,
DateTimeChanged TEXT NOT NULL,
Watched_Value1 TEXT NOT NULL,
Watched_Value2 TEXT NOT NULL,
Watched_Value3 TEXT NOT NULL,
Watched_Value4 TEXT NOT NULL,
Status TEXT NOT NULL,
Extra TEXT NOT NULL,
UserData TEXT NOT NULL,
ForeignKey TEXT NOT NULL,
SyncHubNodeName TEXT,
"HelpVal1" TEXT,
"HelpVal2" TEXT,
"HelpVal3" TEXT,
"HelpVal4" TEXT,
PRIMARY KEY("Index" AUTOINCREMENT)
"index" INTEGER,
plugin TEXT NOT NULL,
objectPrimaryId TEXT NOT NULL,
objectSecondaryId TEXT NOT NULL,
dateTimeCreated TEXT NOT NULL,
dateTimeChanged TEXT NOT NULL,
watchedValue1 TEXT NOT NULL,
watchedValue2 TEXT NOT NULL,
watchedValue3 TEXT NOT NULL,
watchedValue4 TEXT NOT NULL,
"status" TEXT NOT NULL,
extra TEXT NOT NULL,
userData TEXT NOT NULL,
foreignKey TEXT NOT NULL,
syncHubNodeName TEXT,
helpVal1 TEXT,
helpVal2 TEXT,
helpVal3 TEXT,
helpVal4 TEXT,
objectGuid TEXT,
PRIMARY KEY("index" AUTOINCREMENT)
); """
sql.execute(sql_Plugins_Events)
# Plugin execution history
sql_Plugins_History = """ CREATE TABLE IF NOT EXISTS Plugins_History(
"Index" INTEGER,
Plugin TEXT NOT NULL,
Object_PrimaryID TEXT NOT NULL,
Object_SecondaryID TEXT NOT NULL,
DateTimeCreated TEXT NOT NULL,
DateTimeChanged TEXT NOT NULL,
Watched_Value1 TEXT NOT NULL,
Watched_Value2 TEXT NOT NULL,
Watched_Value3 TEXT NOT NULL,
Watched_Value4 TEXT NOT NULL,
Status TEXT NOT NULL,
Extra TEXT NOT NULL,
UserData TEXT NOT NULL,
ForeignKey TEXT NOT NULL,
SyncHubNodeName TEXT,
"HelpVal1" TEXT,
"HelpVal2" TEXT,
"HelpVal3" TEXT,
"HelpVal4" TEXT,
PRIMARY KEY("Index" AUTOINCREMENT)
"index" INTEGER,
plugin TEXT NOT NULL,
objectPrimaryId TEXT NOT NULL,
objectSecondaryId TEXT NOT NULL,
dateTimeCreated TEXT NOT NULL,
dateTimeChanged TEXT NOT NULL,
watchedValue1 TEXT NOT NULL,
watchedValue2 TEXT NOT NULL,
watchedValue3 TEXT NOT NULL,
watchedValue4 TEXT NOT NULL,
"status" TEXT NOT NULL,
extra TEXT NOT NULL,
userData TEXT NOT NULL,
foreignKey TEXT NOT NULL,
syncHubNodeName TEXT,
helpVal1 TEXT,
helpVal2 TEXT,
helpVal3 TEXT,
helpVal4 TEXT,
objectGuid TEXT,
PRIMARY KEY("index" AUTOINCREMENT)
); """
sql.execute(sql_Plugins_History)
# Dynamically generated language strings
sql.execute("DROP TABLE IF EXISTS Plugins_Language_Strings;")
sql.execute(""" CREATE TABLE IF NOT EXISTS Plugins_Language_Strings(
"Index" INTEGER,
Language_Code TEXT NOT NULL,
String_Key TEXT NOT NULL,
String_Value TEXT NOT NULL,
Extra TEXT NOT NULL,
PRIMARY KEY("Index" AUTOINCREMENT)
"index" INTEGER,
languageCode TEXT NOT NULL,
stringKey TEXT NOT NULL,
stringValue TEXT NOT NULL,
extra TEXT NOT NULL,
PRIMARY KEY("index" AUTOINCREMENT)
); """)
return True
# ===============================================================================
# CamelCase Column Migration
# ===============================================================================
# Mapping of (table_name, old_column_name) → new_column_name.
# Only entries where the name actually changes are listed.
# Columns like "Index" → "index" are cosmetic case changes handled
# implicitly by SQLite's case-insensitive matching.
_CAMELCASE_COLUMN_MAP = {
"Events": {
"eve_MAC": "eveMac",
"eve_IP": "eveIp",
"eve_DateTime": "eveDateTime",
"eve_EventType": "eveEventType",
"eve_AdditionalInfo": "eveAdditionalInfo",
"eve_PendingAlertEmail": "evePendingAlertEmail",
"eve_PairEventRowid": "evePairEventRowid",
"eve_PairEventRowID": "evePairEventRowid",
},
"Sessions": {
"ses_MAC": "sesMac",
"ses_IP": "sesIp",
"ses_EventTypeConnection": "sesEventTypeConnection",
"ses_DateTimeConnection": "sesDateTimeConnection",
"ses_EventTypeDisconnection": "sesEventTypeDisconnection",
"ses_DateTimeDisconnection": "sesDateTimeDisconnection",
"ses_StillConnected": "sesStillConnected",
"ses_AdditionalInfo": "sesAdditionalInfo",
},
"Online_History": {
"Index": "index",
"Scan_Date": "scanDate",
"Online_Devices": "onlineDevices",
"Down_Devices": "downDevices",
"All_Devices": "allDevices",
"Archived_Devices": "archivedDevices",
"Offline_Devices": "offlineDevices",
},
"Plugins_Objects": {
"Index": "index",
"Plugin": "plugin",
"Object_PrimaryID": "objectPrimaryId",
"Object_SecondaryID": "objectSecondaryId",
"DateTimeCreated": "dateTimeCreated",
"DateTimeChanged": "dateTimeChanged",
"Watched_Value1": "watchedValue1",
"Watched_Value2": "watchedValue2",
"Watched_Value3": "watchedValue3",
"Watched_Value4": "watchedValue4",
"Status": "status",
"Extra": "extra",
"UserData": "userData",
"ForeignKey": "foreignKey",
"SyncHubNodeName": "syncHubNodeName",
"HelpVal1": "helpVal1",
"HelpVal2": "helpVal2",
"HelpVal3": "helpVal3",
"HelpVal4": "helpVal4",
"ObjectGUID": "objectGuid",
},
"Plugins_Events": {
"Index": "index",
"Plugin": "plugin",
"Object_PrimaryID": "objectPrimaryId",
"Object_SecondaryID": "objectSecondaryId",
"DateTimeCreated": "dateTimeCreated",
"DateTimeChanged": "dateTimeChanged",
"Watched_Value1": "watchedValue1",
"Watched_Value2": "watchedValue2",
"Watched_Value3": "watchedValue3",
"Watched_Value4": "watchedValue4",
"Status": "status",
"Extra": "extra",
"UserData": "userData",
"ForeignKey": "foreignKey",
"SyncHubNodeName": "syncHubNodeName",
"HelpVal1": "helpVal1",
"HelpVal2": "helpVal2",
"HelpVal3": "helpVal3",
"HelpVal4": "helpVal4",
"ObjectGUID": "objectGuid",
},
"Plugins_History": {
"Index": "index",
"Plugin": "plugin",
"Object_PrimaryID": "objectPrimaryId",
"Object_SecondaryID": "objectSecondaryId",
"DateTimeCreated": "dateTimeCreated",
"DateTimeChanged": "dateTimeChanged",
"Watched_Value1": "watchedValue1",
"Watched_Value2": "watchedValue2",
"Watched_Value3": "watchedValue3",
"Watched_Value4": "watchedValue4",
"Status": "status",
"Extra": "extra",
"UserData": "userData",
"ForeignKey": "foreignKey",
"SyncHubNodeName": "syncHubNodeName",
"HelpVal1": "helpVal1",
"HelpVal2": "helpVal2",
"HelpVal3": "helpVal3",
"HelpVal4": "helpVal4",
"ObjectGUID": "objectGuid",
},
"Plugins_Language_Strings": {
"Index": "index",
"Language_Code": "languageCode",
"String_Key": "stringKey",
"String_Value": "stringValue",
"Extra": "extra",
},
"AppEvents": {
"Index": "index",
"GUID": "guid",
"AppEventProcessed": "appEventProcessed",
"DateTimeCreated": "dateTimeCreated",
"ObjectType": "objectType",
"ObjectGUID": "objectGuid",
"ObjectPlugin": "objectPlugin",
"ObjectPrimaryID": "objectPrimaryId",
"ObjectSecondaryID": "objectSecondaryId",
"ObjectForeignKey": "objectForeignKey",
"ObjectIndex": "objectIndex",
"ObjectIsNew": "objectIsNew",
"ObjectIsArchived": "objectIsArchived",
"ObjectStatusColumn": "objectStatusColumn",
"ObjectStatus": "objectStatus",
"AppEventType": "appEventType",
"Helper1": "helper1",
"Helper2": "helper2",
"Helper3": "helper3",
"Extra": "extra",
},
"Notifications": {
"Index": "index",
"GUID": "guid",
"DateTimeCreated": "dateTimeCreated",
"DateTimePushed": "dateTimePushed",
"Status": "status",
"JSON": "json",
"Text": "text",
"HTML": "html",
"PublishedVia": "publishedVia",
"Extra": "extra",
},
}
def migrate_to_camelcase(sql) -> bool:
"""
Detects legacy (underscore/PascalCase) column names and renames them
to camelCase using ALTER TABLE … RENAME COLUMN (SQLite ≥ 3.25.0).
Idempotent: columns already matching the new name are silently skipped.
"""
# Quick probe: if Events table has 'eveMac' we're already on the new schema
sql.execute('PRAGMA table_info("Events")')
events_cols = {row[1] for row in sql.fetchall()}
if "eveMac" in events_cols:
mylog("verbose", ["[db_upgrade] Schema already uses camelCase — skipping migration"])
return True
if "eve_MAC" not in events_cols:
# Events table doesn't exist or has unexpected schema — skip silently
mylog("verbose", ["[db_upgrade] Events table missing/unrecognised — skipping camelCase migration"])
return True
mylog("none", ["[db_upgrade] Starting camelCase column migration …"])
# Drop views first — ALTER TABLE RENAME COLUMN will fail if a view
# references the old column name and the view SQL cannot be rewritten.
for view_name in ("Events_Devices", "LatestEventsPerMAC", "Sessions_Devices",
"Convert_Events_to_Sessions", "LatestDeviceScan", "DevicesView"):
sql.execute(f"DROP VIEW IF EXISTS {view_name};")
renamed_count = 0
for table, column_map in _CAMELCASE_COLUMN_MAP.items():
# Check table exists
sql.execute(f"SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table,))
if not sql.fetchone():
mylog("verbose", [f"[db_upgrade] Table '{table}' does not exist — skipping"])
continue
# Get current column names (case-preserved)
sql.execute(f'PRAGMA table_info("{table}")')
current_cols = {row[1] for row in sql.fetchall()}
for old_name, new_name in column_map.items():
if old_name in current_cols and new_name not in current_cols:
sql.execute(f'ALTER TABLE "{table}" RENAME COLUMN "{old_name}" TO "{new_name}"')
renamed_count += 1
mylog("verbose", [f"[db_upgrade] {table}.{old_name}{new_name}"])
mylog("none", [f"[db_upgrade] ✓ camelCase migration complete — {renamed_count} columns renamed"])
return True
# ===============================================================================
# UTC Timestamp Migration (added 2026-02-10)
# ===============================================================================
@@ -817,17 +1018,18 @@ def migrate_timestamps_to_utc(sql) -> bool:
mylog("verbose", f"[db_upgrade] Starting UTC timestamp migration (offset: {offset_hours} hours)")
# List of tables and their datetime columns
# List of tables and their datetime columns (camelCase names —
# migrate_to_camelcase() runs before this function).
timestamp_columns = {
'Devices': ['devFirstConnection', 'devLastConnection', 'devLastNotification'],
'Events': ['eve_DateTime'],
'Sessions': ['ses_DateTimeConnection', 'ses_DateTimeDisconnection'],
'Notifications': ['DateTimeCreated', 'DateTimePushed'],
'Online_History': ['Scan_Date'],
'Plugins_Objects': ['DateTimeCreated', 'DateTimeChanged'],
'Plugins_Events': ['DateTimeCreated', 'DateTimeChanged'],
'Plugins_History': ['DateTimeCreated', 'DateTimeChanged'],
'AppEvents': ['DateTimeCreated'],
'Events': ['eveDateTime'],
'Sessions': ['sesDateTimeConnection', 'sesDateTimeDisconnection'],
'Notifications': ['dateTimeCreated', 'dateTimePushed'],
'Online_History': ['scanDate'],
'Plugins_Objects': ['dateTimeCreated', 'dateTimeChanged'],
'Plugins_Events': ['dateTimeCreated', 'dateTimeChanged'],
'Plugins_History': ['dateTimeCreated', 'dateTimeChanged'],
'AppEvents': ['dateTimeCreated'],
}
for table, columns in timestamp_columns.items():

View File

@@ -1,14 +1,14 @@
CREATE TABLE Events (eve_MAC STRING (50) NOT NULL COLLATE NOCASE, eve_IP STRING (50) NOT NULL COLLATE NOCASE, eve_DateTime DATETIME NOT NULL, eve_EventType STRING (30) NOT NULL COLLATE NOCASE, eve_AdditionalInfo STRING (250) DEFAULT (''), eve_PendingAlertEmail BOOLEAN NOT NULL CHECK (eve_PendingAlertEmail IN (0, 1)) DEFAULT (1), eve_PairEventRowid INTEGER);
CREATE TABLE Sessions (ses_MAC STRING (50) COLLATE NOCASE, ses_IP STRING (50) COLLATE NOCASE, ses_EventTypeConnection STRING (30) COLLATE NOCASE, ses_DateTimeConnection DATETIME, ses_EventTypeDisconnection STRING (30) COLLATE NOCASE, ses_DateTimeDisconnection DATETIME, ses_StillConnected BOOLEAN, ses_AdditionalInfo STRING (250));
CREATE TABLE IF NOT EXISTS "Online_History" (
"Index" INTEGER,
"Scan_Date" TEXT,
"Online_Devices" INTEGER,
"Down_Devices" INTEGER,
"All_Devices" INTEGER,
"Archived_Devices" INTEGER,
"Offline_Devices" INTEGER,
PRIMARY KEY("Index" AUTOINCREMENT)
CREATE TABLE Events (eveMac STRING (50) NOT NULL COLLATE NOCASE, eveIp STRING (50) NOT NULL COLLATE NOCASE, eveDateTime DATETIME NOT NULL, eveEventType STRING (30) NOT NULL COLLATE NOCASE, eveAdditionalInfo STRING (250) DEFAULT (''), evePendingAlertEmail BOOLEAN NOT NULL CHECK (evePendingAlertEmail IN (0, 1)) DEFAULT (1), evePairEventRowid INTEGER);
CREATE TABLE Sessions (sesMac STRING (50) COLLATE NOCASE, sesIp STRING (50) COLLATE NOCASE, sesEventTypeConnection STRING (30) COLLATE NOCASE, sesDateTimeConnection DATETIME, sesEventTypeDisconnection STRING (30) COLLATE NOCASE, sesDateTimeDisconnection DATETIME, sesStillConnected BOOLEAN, sesAdditionalInfo STRING (250));
CREATE TABLE IF NOT EXISTS Online_History (
"index" INTEGER,
scanDate TEXT,
onlineDevices INTEGER,
downDevices INTEGER,
allDevices INTEGER,
archivedDevices INTEGER,
offlineDevices INTEGER,
PRIMARY KEY("index" AUTOINCREMENT)
);
CREATE TABLE Devices (
devMac STRING (50) PRIMARY KEY NOT NULL COLLATE NOCASE,
@@ -57,96 +57,98 @@ CREATE TABLE Devices (
devParentPortSource TEXT,
devParentRelTypeSource TEXT,
devVlanSource TEXT,
"devCustomProps" TEXT);
CREATE TABLE IF NOT EXISTS "Settings" (
"setKey" TEXT,
"setName" TEXT,
"setDescription" TEXT,
"setType" TEXT,
"setOptions" TEXT,
"setGroup" TEXT,
"setValue" TEXT,
"setEvents" TEXT,
"setOverriddenByEnv" INTEGER
devCustomProps TEXT);
CREATE TABLE IF NOT EXISTS Settings (
setKey TEXT,
setName TEXT,
setDescription TEXT,
setType TEXT,
setOptions TEXT,
setGroup TEXT,
setValue TEXT,
setEvents TEXT,
setOverriddenByEnv INTEGER
);
CREATE TABLE IF NOT EXISTS "Parameters" (
"parID" TEXT PRIMARY KEY,
"parValue" TEXT
CREATE TABLE IF NOT EXISTS Parameters (
parID TEXT PRIMARY KEY,
parValue TEXT
);
CREATE TABLE Plugins_Objects(
"Index" INTEGER,
Plugin TEXT NOT NULL,
Object_PrimaryID TEXT NOT NULL,
Object_SecondaryID TEXT NOT NULL,
DateTimeCreated TEXT NOT NULL,
DateTimeChanged TEXT NOT NULL,
Watched_Value1 TEXT NOT NULL,
Watched_Value2 TEXT NOT NULL,
Watched_Value3 TEXT NOT NULL,
Watched_Value4 TEXT NOT NULL,
Status TEXT NOT NULL,
Extra TEXT NOT NULL,
UserData TEXT NOT NULL,
ForeignKey TEXT NOT NULL,
SyncHubNodeName TEXT,
"HelpVal1" TEXT,
"HelpVal2" TEXT,
"HelpVal3" TEXT,
"HelpVal4" TEXT,
ObjectGUID TEXT,
PRIMARY KEY("Index" AUTOINCREMENT)
"index" INTEGER,
plugin TEXT NOT NULL,
objectPrimaryId TEXT NOT NULL,
objectSecondaryId TEXT NOT NULL,
dateTimeCreated TEXT NOT NULL,
dateTimeChanged TEXT NOT NULL,
watchedValue1 TEXT NOT NULL,
watchedValue2 TEXT NOT NULL,
watchedValue3 TEXT NOT NULL,
watchedValue4 TEXT NOT NULL,
"status" TEXT NOT NULL,
extra TEXT NOT NULL,
userData TEXT NOT NULL,
foreignKey TEXT NOT NULL,
syncHubNodeName TEXT,
helpVal1 TEXT,
helpVal2 TEXT,
helpVal3 TEXT,
helpVal4 TEXT,
objectGuid TEXT,
PRIMARY KEY("index" AUTOINCREMENT)
);
CREATE TABLE Plugins_Events(
"Index" INTEGER,
Plugin TEXT NOT NULL,
Object_PrimaryID TEXT NOT NULL,
Object_SecondaryID TEXT NOT NULL,
DateTimeCreated TEXT NOT NULL,
DateTimeChanged TEXT NOT NULL,
Watched_Value1 TEXT NOT NULL,
Watched_Value2 TEXT NOT NULL,
Watched_Value3 TEXT NOT NULL,
Watched_Value4 TEXT NOT NULL,
Status TEXT NOT NULL,
Extra TEXT NOT NULL,
UserData TEXT NOT NULL,
ForeignKey TEXT NOT NULL,
SyncHubNodeName TEXT,
"HelpVal1" TEXT,
"HelpVal2" TEXT,
"HelpVal3" TEXT,
"HelpVal4" TEXT, "ObjectGUID" TEXT,
PRIMARY KEY("Index" AUTOINCREMENT)
"index" INTEGER,
plugin TEXT NOT NULL,
objectPrimaryId TEXT NOT NULL,
objectSecondaryId TEXT NOT NULL,
dateTimeCreated TEXT NOT NULL,
dateTimeChanged TEXT NOT NULL,
watchedValue1 TEXT NOT NULL,
watchedValue2 TEXT NOT NULL,
watchedValue3 TEXT NOT NULL,
watchedValue4 TEXT NOT NULL,
"status" TEXT NOT NULL,
extra TEXT NOT NULL,
userData TEXT NOT NULL,
foreignKey TEXT NOT NULL,
syncHubNodeName TEXT,
helpVal1 TEXT,
helpVal2 TEXT,
helpVal3 TEXT,
helpVal4 TEXT,
objectGuid TEXT,
PRIMARY KEY("index" AUTOINCREMENT)
);
CREATE TABLE Plugins_History(
"Index" INTEGER,
Plugin TEXT NOT NULL,
Object_PrimaryID TEXT NOT NULL,
Object_SecondaryID TEXT NOT NULL,
DateTimeCreated TEXT NOT NULL,
DateTimeChanged TEXT NOT NULL,
Watched_Value1 TEXT NOT NULL,
Watched_Value2 TEXT NOT NULL,
Watched_Value3 TEXT NOT NULL,
Watched_Value4 TEXT NOT NULL,
Status TEXT NOT NULL,
Extra TEXT NOT NULL,
UserData TEXT NOT NULL,
ForeignKey TEXT NOT NULL,
SyncHubNodeName TEXT,
"HelpVal1" TEXT,
"HelpVal2" TEXT,
"HelpVal3" TEXT,
"HelpVal4" TEXT, "ObjectGUID" TEXT,
PRIMARY KEY("Index" AUTOINCREMENT)
"index" INTEGER,
plugin TEXT NOT NULL,
objectPrimaryId TEXT NOT NULL,
objectSecondaryId TEXT NOT NULL,
dateTimeCreated TEXT NOT NULL,
dateTimeChanged TEXT NOT NULL,
watchedValue1 TEXT NOT NULL,
watchedValue2 TEXT NOT NULL,
watchedValue3 TEXT NOT NULL,
watchedValue4 TEXT NOT NULL,
"status" TEXT NOT NULL,
extra TEXT NOT NULL,
userData TEXT NOT NULL,
foreignKey TEXT NOT NULL,
syncHubNodeName TEXT,
helpVal1 TEXT,
helpVal2 TEXT,
helpVal3 TEXT,
helpVal4 TEXT,
objectGuid TEXT,
PRIMARY KEY("index" AUTOINCREMENT)
);
CREATE TABLE Plugins_Language_Strings(
"Index" INTEGER,
Language_Code TEXT NOT NULL,
String_Key TEXT NOT NULL,
String_Value TEXT NOT NULL,
Extra TEXT NOT NULL,
PRIMARY KEY("Index" AUTOINCREMENT)
"index" INTEGER,
languageCode TEXT NOT NULL,
stringKey TEXT NOT NULL,
stringValue TEXT NOT NULL,
extra TEXT NOT NULL,
PRIMARY KEY("index" AUTOINCREMENT)
);
CREATE TABLE CurrentScan (
scanMac STRING(50) NOT NULL COLLATE NOCASE,
@@ -165,50 +167,50 @@ CREATE TABLE CurrentScan (
scanType STRING(250),
UNIQUE(scanMac)
);
CREATE TABLE IF NOT EXISTS "AppEvents" (
"Index" INTEGER PRIMARY KEY AUTOINCREMENT,
"GUID" TEXT UNIQUE,
"AppEventProcessed" BOOLEAN,
"DateTimeCreated" TEXT,
"ObjectType" TEXT,
"ObjectGUID" TEXT,
"ObjectPlugin" TEXT,
"ObjectPrimaryID" TEXT,
"ObjectSecondaryID" TEXT,
"ObjectForeignKey" TEXT,
"ObjectIndex" TEXT,
"ObjectIsNew" BOOLEAN,
"ObjectIsArchived" BOOLEAN,
"ObjectStatusColumn" TEXT,
"ObjectStatus" TEXT,
"AppEventType" TEXT,
"Helper1" TEXT,
"Helper2" TEXT,
"Helper3" TEXT,
"Extra" TEXT
CREATE TABLE IF NOT EXISTS AppEvents (
"index" INTEGER PRIMARY KEY AUTOINCREMENT,
guid TEXT UNIQUE,
appEventProcessed BOOLEAN,
dateTimeCreated TEXT,
objectType TEXT,
objectGuid TEXT,
objectPlugin TEXT,
objectPrimaryId TEXT,
objectSecondaryId TEXT,
objectForeignKey TEXT,
objectIndex TEXT,
objectIsNew BOOLEAN,
objectIsArchived BOOLEAN,
objectStatusColumn TEXT,
objectStatus TEXT,
appEventType TEXT,
helper1 TEXT,
helper2 TEXT,
helper3 TEXT,
extra TEXT
);
CREATE TABLE IF NOT EXISTS "Notifications" (
"Index" INTEGER,
"GUID" TEXT UNIQUE,
"DateTimeCreated" TEXT,
"DateTimePushed" TEXT,
"Status" TEXT,
"JSON" TEXT,
"Text" TEXT,
"HTML" TEXT,
"PublishedVia" TEXT,
"Extra" TEXT,
PRIMARY KEY("Index" AUTOINCREMENT)
CREATE TABLE IF NOT EXISTS Notifications (
"index" INTEGER,
guid TEXT UNIQUE,
dateTimeCreated TEXT,
dateTimePushed TEXT,
"status" TEXT,
"json" TEXT,
"text" TEXT,
html TEXT,
publishedVia TEXT,
extra TEXT,
PRIMARY KEY("index" AUTOINCREMENT)
);
CREATE INDEX IDX_eve_DateTime ON Events (eve_DateTime);
CREATE INDEX IDX_eve_EventType ON Events (eve_EventType COLLATE NOCASE);
CREATE INDEX IDX_eve_MAC ON Events (eve_MAC COLLATE NOCASE);
CREATE INDEX IDX_eve_PairEventRowid ON Events (eve_PairEventRowid);
CREATE INDEX IDX_ses_EventTypeDisconnection ON Sessions (ses_EventTypeDisconnection COLLATE NOCASE);
CREATE INDEX IDX_ses_EventTypeConnection ON Sessions (ses_EventTypeConnection COLLATE NOCASE);
CREATE INDEX IDX_ses_DateTimeDisconnection ON Sessions (ses_DateTimeDisconnection);
CREATE INDEX IDX_ses_MAC ON Sessions (ses_MAC COLLATE NOCASE);
CREATE INDEX IDX_ses_DateTimeConnection ON Sessions (ses_DateTimeConnection);
CREATE INDEX IDX_eve_DateTime ON Events (eveDateTime);
CREATE INDEX IDX_eve_EventType ON Events (eveEventType COLLATE NOCASE);
CREATE INDEX IDX_eve_MAC ON Events (eveMac COLLATE NOCASE);
CREATE INDEX IDX_eve_PairEventRowid ON Events (evePairEventRowid);
CREATE INDEX IDX_ses_EventTypeDisconnection ON Sessions (sesEventTypeDisconnection COLLATE NOCASE);
CREATE INDEX IDX_ses_EventTypeConnection ON Sessions (sesEventTypeConnection COLLATE NOCASE);
CREATE INDEX IDX_ses_DateTimeDisconnection ON Sessions (sesDateTimeDisconnection);
CREATE INDEX IDX_ses_MAC ON Sessions (sesMac COLLATE NOCASE);
CREATE INDEX IDX_ses_DateTimeConnection ON Sessions (sesDateTimeConnection);
CREATE INDEX IDX_dev_PresentLastScan ON Devices (devPresentLastScan);
CREATE INDEX IDX_dev_FirstConnection ON Devices (devFirstConnection);
CREATE INDEX IDX_dev_AlertDeviceDown ON Devices (devAlertDown);
@@ -220,21 +222,20 @@ CREATE INDEX IDX_dev_NewDevice ON Devices (devIsNew);
CREATE INDEX IDX_dev_Archived ON Devices (devIsArchived);
CREATE UNIQUE INDEX IF NOT EXISTS idx_events_unique
ON Events (
eve_MAC,
eve_IP,
eve_EventType,
eve_DateTime
eveMac,
eveIp,
eveEventType,
eveDateTime
);
CREATE VIEW Events_Devices AS
SELECT *
FROM Events
LEFT JOIN Devices ON eve_MAC = devMac
/* Events_Devices(eve_MAC,eve_IP,eve_DateTime,eve_EventType,eve_AdditionalInfo,eve_PendingAlertEmail,eve_PairEventRowid,devMac,devName,devOwner,devType,devVendor,devFavorite,devGroup,devComments,devFirstConnection,devLastConnection,devLastIP,devStaticIP,devScan,devLogEvents,devAlertEvents,devAlertDown,devSkipRepeated,devLastNotification,devPresentLastScan,devIsNew,devLocation,devIsArchived,devParentMAC,devParentPort,devIcon,devGUID,devSite,devSSID,devSyncHubNode,devSourcePlugin,devCustomProps) */;
LEFT JOIN Devices ON eveMac = devMac;
CREATE VIEW LatestEventsPerMAC AS
WITH RankedEvents AS (
SELECT
e.*,
ROW_NUMBER() OVER (PARTITION BY e.eve_MAC ORDER BY e.eve_DateTime DESC) AS row_num
ROW_NUMBER() OVER (PARTITION BY e.eveMac ORDER BY e.eveDateTime DESC) AS row_num
FROM Events AS e
)
SELECT
@@ -242,192 +243,33 @@ CREATE VIEW LatestEventsPerMAC AS
d.*,
c.*
FROM RankedEvents AS e
LEFT JOIN Devices AS d ON e.eve_MAC = d.devMac
INNER JOIN CurrentScan AS c ON e.eve_MAC = c.scanMac
WHERE e.row_num = 1
/* LatestEventsPerMAC(eve_MAC,eve_IP,eve_DateTime,eve_EventType,eve_AdditionalInfo,eve_PendingAlertEmail,eve_PairEventRowid,row_num,devMac,devName,devOwner,devType,devVendor,devFavorite,devGroup,devComments,devFirstConnection,devLastConnection,devLastIP,devStaticIP,devScan,devLogEvents,devAlertEvents,devAlertDown,devSkipRepeated,devLastNotification,devPresentLastScan,devIsNew,devLocation,devIsArchived,devParentMAC,devParentPort,devIcon,devGUID,devSite,devSSID,devSyncHubNode,devSourcePlugin,devCustomProps,scanMac,scanLastIP,scanVendor,scanSourcePlugin,scanName,scanLastQuery,scanLastConnection,scanSyncHubNode,scanSite,scanSSID,scanParentMAC,scanParentPort,scanType) */;
CREATE VIEW Sessions_Devices AS SELECT * FROM Sessions LEFT JOIN "Devices" ON ses_MAC = devMac
/* Sessions_Devices(ses_MAC,ses_IP,ses_EventTypeConnection,ses_DateTimeConnection,ses_EventTypeDisconnection,ses_DateTimeDisconnection,ses_StillConnected,ses_AdditionalInfo,devMac,devName,devOwner,devType,devVendor,devFavorite,devGroup,devComments,devFirstConnection,devLastConnection,devLastIP,devStaticIP,devScan,devLogEvents,devAlertEvents,devAlertDown,devSkipRepeated,devLastNotification,devPresentLastScan,devIsNew,devLocation,devIsArchived,devParentMAC,devParentPort,devIcon,devGUID,devSite,devSSID,devSyncHubNode,devSourcePlugin,devCustomProps) */;
CREATE VIEW Convert_Events_to_Sessions AS SELECT EVE1.eve_MAC,
EVE1.eve_IP,
EVE1.eve_EventType AS eve_EventTypeConnection,
EVE1.eve_DateTime AS eve_DateTimeConnection,
CASE WHEN EVE2.eve_EventType IN ('Disconnected', 'Device Down') OR
EVE2.eve_EventType IS NULL THEN EVE2.eve_EventType ELSE '<missing event>' END AS eve_EventTypeDisconnection,
CASE WHEN EVE2.eve_EventType IN ('Disconnected', 'Device Down') THEN EVE2.eve_DateTime ELSE NULL END AS eve_DateTimeDisconnection,
CASE WHEN EVE2.eve_EventType IS NULL THEN 1 ELSE 0 END AS eve_StillConnected,
EVE1.eve_AdditionalInfo
LEFT JOIN Devices AS d ON e.eveMac = d.devMac
INNER JOIN CurrentScan AS c ON e.eveMac = c.scanMac
WHERE e.row_num = 1;
CREATE VIEW Sessions_Devices AS SELECT * FROM Sessions LEFT JOIN Devices ON sesMac = devMac;
CREATE VIEW Convert_Events_to_Sessions AS SELECT EVE1.eveMac,
EVE1.eveIp,
EVE1.eveEventType AS eveEventTypeConnection,
EVE1.eveDateTime AS eveDateTimeConnection,
CASE WHEN EVE2.eveEventType IN ('Disconnected', 'Device Down') OR
EVE2.eveEventType IS NULL THEN EVE2.eveEventType ELSE '<missing event>' END AS eveEventTypeDisconnection,
CASE WHEN EVE2.eveEventType IN ('Disconnected', 'Device Down') THEN EVE2.eveDateTime ELSE NULL END AS eveDateTimeDisconnection,
CASE WHEN EVE2.eveEventType IS NULL THEN 1 ELSE 0 END AS eveStillConnected,
EVE1.eveAdditionalInfo
FROM Events AS EVE1
LEFT JOIN
Events AS EVE2 ON EVE1.eve_PairEventRowID = EVE2.RowID
WHERE EVE1.eve_EventType IN ('New Device', 'Connected','Down Reconnected')
Events AS EVE2 ON EVE1.evePairEventRowid = EVE2.RowID
WHERE EVE1.eveEventType IN ('New Device', 'Connected','Down Reconnected')
UNION
SELECT eve_MAC,
eve_IP,
'<missing event>' AS eve_EventTypeConnection,
NULL AS eve_DateTimeConnection,
eve_EventType AS eve_EventTypeDisconnection,
eve_DateTime AS eve_DateTimeDisconnection,
0 AS eve_StillConnected,
eve_AdditionalInfo
SELECT eveMac,
eveIp,
'<missing event>' AS eveEventTypeConnection,
NULL AS eveDateTimeConnection,
eveEventType AS eveEventTypeDisconnection,
eveDateTime AS eveDateTimeDisconnection,
0 AS eveStillConnected,
eveAdditionalInfo
FROM Events AS EVE1
WHERE (eve_EventType = 'Device Down' OR
eve_EventType = 'Disconnected') AND
EVE1.eve_PairEventRowID IS NULL
/* Convert_Events_to_Sessions(eve_MAC,eve_IP,eve_EventTypeConnection,eve_DateTimeConnection,eve_EventTypeDisconnection,eve_DateTimeDisconnection,eve_StillConnected,eve_AdditionalInfo) */;
CREATE TRIGGER "trg_insert_devices"
AFTER INSERT ON "Devices"
WHEN NOT EXISTS (
SELECT 1 FROM AppEvents
WHERE AppEventProcessed = 0
AND ObjectType = 'Devices'
AND ObjectGUID = NEW.devGUID
AND ObjectStatus = CASE WHEN NEW.devPresentLastScan = 1 THEN 'online' ELSE 'offline' END
AND AppEventType = 'insert'
)
BEGIN
INSERT INTO "AppEvents" (
"GUID",
"DateTimeCreated",
"AppEventProcessed",
"ObjectType",
"ObjectGUID",
"ObjectPrimaryID",
"ObjectSecondaryID",
"ObjectStatus",
"ObjectStatusColumn",
"ObjectIsNew",
"ObjectIsArchived",
"ObjectForeignKey",
"ObjectPlugin",
"AppEventType"
)
VALUES (
lower(
hex(randomblob(4)) || '-' || hex(randomblob(2)) || '-' || '4' ||
substr(hex( randomblob(2)), 2) || '-' ||
substr('AB89', 1 + (abs(random()) % 4) , 1) ||
substr(hex(randomblob(2)), 2) || '-' ||
hex(randomblob(6))
)
,
DATETIME('now'),
FALSE,
'Devices',
NEW.devGUID, -- ObjectGUID
NEW.devMac, -- ObjectPrimaryID
NEW.devLastIP, -- ObjectSecondaryID
CASE WHEN NEW.devPresentLastScan = 1 THEN 'online' ELSE 'offline' END, -- ObjectStatus
'devPresentLastScan', -- ObjectStatusColumn
NEW.devIsNew, -- ObjectIsNew
NEW.devIsArchived, -- ObjectIsArchived
NEW.devGUID, -- ObjectForeignKey
'DEVICES', -- ObjectForeignKey
'insert'
);
END;
CREATE TRIGGER "trg_update_devices"
AFTER UPDATE ON "Devices"
WHEN NOT EXISTS (
SELECT 1 FROM AppEvents
WHERE AppEventProcessed = 0
AND ObjectType = 'Devices'
AND ObjectGUID = NEW.devGUID
AND ObjectStatus = CASE WHEN NEW.devPresentLastScan = 1 THEN 'online' ELSE 'offline' END
AND AppEventType = 'update'
)
BEGIN
INSERT INTO "AppEvents" (
"GUID",
"DateTimeCreated",
"AppEventProcessed",
"ObjectType",
"ObjectGUID",
"ObjectPrimaryID",
"ObjectSecondaryID",
"ObjectStatus",
"ObjectStatusColumn",
"ObjectIsNew",
"ObjectIsArchived",
"ObjectForeignKey",
"ObjectPlugin",
"AppEventType"
)
VALUES (
lower(
hex(randomblob(4)) || '-' || hex(randomblob(2)) || '-' || '4' ||
substr(hex( randomblob(2)), 2) || '-' ||
substr('AB89', 1 + (abs(random()) % 4) , 1) ||
substr(hex(randomblob(2)), 2) || '-' ||
hex(randomblob(6))
)
,
DATETIME('now'),
FALSE,
'Devices',
NEW.devGUID, -- ObjectGUID
NEW.devMac, -- ObjectPrimaryID
NEW.devLastIP, -- ObjectSecondaryID
CASE WHEN NEW.devPresentLastScan = 1 THEN 'online' ELSE 'offline' END, -- ObjectStatus
'devPresentLastScan', -- ObjectStatusColumn
NEW.devIsNew, -- ObjectIsNew
NEW.devIsArchived, -- ObjectIsArchived
NEW.devGUID, -- ObjectForeignKey
'DEVICES', -- ObjectForeignKey
'update'
);
END;
CREATE TRIGGER "trg_delete_devices"
AFTER DELETE ON "Devices"
WHEN NOT EXISTS (
SELECT 1 FROM AppEvents
WHERE AppEventProcessed = 0
AND ObjectType = 'Devices'
AND ObjectGUID = OLD.devGUID
AND ObjectStatus = CASE WHEN OLD.devPresentLastScan = 1 THEN 'online' ELSE 'offline' END
AND AppEventType = 'delete'
)
BEGIN
INSERT INTO "AppEvents" (
"GUID",
"DateTimeCreated",
"AppEventProcessed",
"ObjectType",
"ObjectGUID",
"ObjectPrimaryID",
"ObjectSecondaryID",
"ObjectStatus",
"ObjectStatusColumn",
"ObjectIsNew",
"ObjectIsArchived",
"ObjectForeignKey",
"ObjectPlugin",
"AppEventType"
)
VALUES (
lower(
hex(randomblob(4)) || '-' || hex(randomblob(2)) || '-' || '4' ||
substr(hex( randomblob(2)), 2) || '-' ||
substr('AB89', 1 + (abs(random()) % 4) , 1) ||
substr(hex(randomblob(2)), 2) || '-' ||
hex(randomblob(6))
)
,
DATETIME('now'),
FALSE,
'Devices',
OLD.devGUID, -- ObjectGUID
OLD.devMac, -- ObjectPrimaryID
OLD.devLastIP, -- ObjectSecondaryID
CASE WHEN OLD.devPresentLastScan = 1 THEN 'online' ELSE 'offline' END, -- ObjectStatus
'devPresentLastScan', -- ObjectStatusColumn
OLD.devIsNew, -- ObjectIsNew
OLD.devIsArchived, -- ObjectIsArchived
OLD.devGUID, -- ObjectForeignKey
'DEVICES', -- ObjectForeignKey
'delete'
);
END;
WHERE (eveEventType = 'Device Down' OR
eveEventType = 'Disconnected') AND
EVE1.evePairEventRowid IS NULL;

View File

@@ -29,10 +29,10 @@ class SafeConditionBuilder:
# Whitelist of allowed column names for filtering
ALLOWED_COLUMNS = {
"eve_MAC",
"eve_DateTime",
"eve_IP",
"eve_EventType",
"eveMac",
"eveDateTime",
"eveIp",
"eveEventType",
"devName",
"devComments",
"devLastIP",
@@ -43,15 +43,15 @@ class SafeConditionBuilder:
"devPresentLastScan",
"devFavorite",
"devIsNew",
"Plugin",
"Object_PrimaryId",
"Object_SecondaryId",
"DateTimeChanged",
"Watched_Value1",
"Watched_Value2",
"Watched_Value3",
"Watched_Value4",
"Status",
"plugin",
"objectPrimaryId",
"objectSecondaryId",
"dateTimeChanged",
"watchedValue1",
"watchedValue2",
"watchedValue3",
"watchedValue4",
"status",
}
# Whitelist of allowed comparison operators
@@ -413,7 +413,7 @@ class SafeConditionBuilder:
This method handles basic patterns like:
- devName = 'value' (with optional AND/OR prefix)
- devComments LIKE '%value%'
- eve_EventType IN ('type1', 'type2')
- eveEventType IN ('type1', 'type2')
Args:
condition: Single condition string to parse
@@ -648,7 +648,7 @@ class SafeConditionBuilder:
self.parameters[param_name] = event_type
param_names.append(f":{param_name}")
sql_snippet = f"AND eve_EventType IN ({', '.join(param_names)})"
sql_snippet = f"AND eveEventType IN ({', '.join(param_names)})"
return sql_snippet, self.parameters
def get_safe_condition_legacy(

View File

@@ -27,7 +27,7 @@ from messaging.in_app import write_notification
# ===============================================================================
_LANGUAGES_JSON = os.path.join(
applicationPath, "front", "php", "templates", "language", "language_definitions" ,"languages.json"
applicationPath, "front", "php", "templates", "language", "language_definitions", "languages.json"
)
@@ -204,6 +204,9 @@ def importConfigs(pm, db, all_plugins):
# rename settings that have changed names due to code cleanup and migration to plugins
# renameSettings(config_file)
# rename legacy DB column references in user config values (e.g. templates, WATCH lists)
renameColumnReferences(config_file)
fileModifiedTime = os.path.getmtime(config_file)
mylog("debug", ["[Import Config] checking config file "])
@@ -582,7 +585,7 @@ def importConfigs(pm, db, all_plugins):
# bulk-import language strings
sql.executemany(
"""INSERT INTO Plugins_Language_Strings ("Language_Code", "String_Key", "String_Value", "Extra") VALUES (?, ?, ?, ?)""",
"""INSERT INTO Plugins_Language_Strings (languageCode, stringKey, stringValue, extra) VALUES (?, ?, ?, ?)""",
stringSqlParams,
)
@@ -845,3 +848,78 @@ def renameSettings(config_file):
else:
mylog("debug", "[Config] No old setting names found in the file. No changes made.")
# -------------------------------------------------------------------------------
# Rename legacy DB column names in user-persisted config values (templates, WATCH lists, etc.)
# Follows the same backup-and-replace pattern as renameSettings().
_column_replacements = {
# Event columns
r"\beve_MAC\b": "eveMac",
r"\beve_IP\b": "eveIp",
r"\beve_DateTime\b": "eveDateTime",
r"\beve_EventType\b": "eveEventType",
r"\beve_AdditionalInfo\b": "eveAdditionalInfo",
r"\beve_PendingAlertEmail\b": "evePendingAlertEmail",
r"\beve_PairEventRowid\b": "evePairEventRowid",
# Session columns
r"\bses_MAC\b": "sesMac",
r"\bses_IP\b": "sesIp",
r"\bses_StillConnected\b": "sesStillConnected",
r"\bses_AdditionalInfo\b": "sesAdditionalInfo",
# Plugin columns (templates + WATCH values)
r"\bObject_PrimaryID\b": "objectPrimaryId",
r"\bObject_PrimaryId\b": "objectPrimaryId",
r"\bObject_SecondaryID\b": "objectSecondaryId",
r"\bObject_SecondaryId\b": "objectSecondaryId",
r"\bWatched_Value1\b": "watchedValue1",
r"\bWatched_Value2\b": "watchedValue2",
r"\bWatched_Value3\b": "watchedValue3",
r"\bWatched_Value4\b": "watchedValue4",
r"\bDateTimeChanged\b": "dateTimeChanged",
r"\bDateTimeCreated\b": "dateTimeCreated",
r"\bSyncHubNodeName\b": "syncHubNodeName",
# Online_History (in case of API_CUSTOM_SQL)
r"\bScan_Date\b": "scanDate",
r"\bOnline_Devices\b": "onlineDevices",
r"\bDown_Devices\b": "downDevices",
r"\bAll_Devices\b": "allDevices",
r"\bArchived_Devices\b": "archivedDevices",
r"\bOffline_Devices\b": "offlineDevices",
# Language strings (unlikely in user config but thorough)
r"\bLanguage_Code\b": "languageCode",
r"\bString_Key\b": "stringKey",
r"\bString_Value\b": "stringValue",
}
def renameColumnReferences(config_file):
"""Rename legacy DB column references in the user's app.conf file."""
contains_old_refs = False
with open(str(config_file), "r") as f:
for line in f:
if any(re.search(key, line) for key in _column_replacements):
mylog("debug", f"[Config] Old column reference found: ({line.strip()})")
contains_old_refs = True
break
if not contains_old_refs:
mylog("debug", "[Config] No old column references found in config. No changes made.")
return
timestamp = timeNowUTC(as_string=False).strftime("%Y%m%d%H%M%S")
backup_file = f"{config_file}_old_column_names_{timestamp}.bak"
mylog("none", f"[Config] Renaming legacy column references — backup: {backup_file}")
shutil.copy(str(config_file), backup_file)
with (
open(str(config_file), "r") as original,
open(str(config_file) + "_temp", "w") as temp,
):
for line in original:
for pattern, replacement in _column_replacements.items():
line = re.sub(pattern, replacement, line)
temp.write(line)
shutil.move(str(config_file) + "_temp", str(config_file))

View File

@@ -25,11 +25,11 @@ SECTION_TITLES = {
# Which column(s) contain datetime values per section (for timezone conversion)
DATETIME_FIELDS = {
"new_devices": ["eve_DateTime"],
"down_devices": ["eve_DateTime"],
"down_reconnected": ["eve_DateTime"],
"events": ["eve_DateTime"],
"plugins": ["DateTimeChanged"],
"new_devices": ["eveDateTime"],
"down_devices": ["eveDateTime"],
"down_reconnected": ["eveDateTime"],
"events": ["eveDateTime"],
"plugins": ["dateTimeChanged"],
}
# ---------------------------------------------------------------------------
@@ -47,78 +47,78 @@ SQL_TEMPLATES = {
"new_devices": """
SELECT
devName,
eve_MAC,
eveMac,
devVendor,
devLastIP as eve_IP,
eve_DateTime,
eve_EventType,
devLastIP as eveIp,
eveDateTime,
eveEventType,
devComments
FROM Events_Devices
WHERE eve_PendingAlertEmail = 1
AND eve_EventType = 'New Device' {condition}
ORDER BY eve_DateTime
WHERE evePendingAlertEmail = 1
AND eveEventType = 'New Device' {condition}
ORDER BY eveDateTime
""",
"down_devices": """
SELECT
devName,
eve_MAC,
eveMac,
devVendor,
eve_IP,
eve_DateTime,
eve_EventType,
eveIp,
eveDateTime,
eveEventType,
devComments
FROM Events_Devices AS down_events
WHERE eve_PendingAlertEmail = 1
AND down_events.eve_EventType = 'Device Down'
AND eve_DateTime < datetime('now', '-{alert_down_minutes} minutes')
WHERE evePendingAlertEmail = 1
AND down_events.eveEventType = 'Device Down'
AND eveDateTime < datetime('now', '-{alert_down_minutes} minutes')
AND NOT EXISTS (
SELECT 1
FROM Events AS connected_events
WHERE connected_events.eve_MAC = down_events.eve_MAC
AND connected_events.eve_EventType = 'Connected'
AND connected_events.eve_DateTime > down_events.eve_DateTime
WHERE connected_events.eveMac = down_events.eveMac
AND connected_events.eveEventType = 'Connected'
AND connected_events.eveDateTime > down_events.eveDateTime
)
ORDER BY down_events.eve_DateTime
ORDER BY down_events.eveDateTime
""",
"down_reconnected": """
SELECT
devName,
eve_MAC,
eveMac,
devVendor,
eve_IP,
eve_DateTime,
eve_EventType,
eveIp,
eveDateTime,
eveEventType,
devComments
FROM Events_Devices AS reconnected_devices
WHERE reconnected_devices.eve_EventType = 'Down Reconnected'
AND reconnected_devices.eve_PendingAlertEmail = 1
ORDER BY reconnected_devices.eve_DateTime
WHERE reconnected_devices.eveEventType = 'Down Reconnected'
AND reconnected_devices.evePendingAlertEmail = 1
ORDER BY reconnected_devices.eveDateTime
""",
"events": """
SELECT
devName,
eve_MAC,
eveMac,
devVendor,
devLastIP as eve_IP,
eve_DateTime,
eve_EventType,
devLastIP as eveIp,
eveDateTime,
eveEventType,
devComments
FROM Events_Devices
WHERE eve_PendingAlertEmail = 1
AND eve_EventType IN ('Connected', 'Down Reconnected', 'Disconnected','IP Changed') {condition}
ORDER BY eve_DateTime
WHERE evePendingAlertEmail = 1
AND eveEventType IN ('Connected', 'Down Reconnected', 'Disconnected','IP Changed') {condition}
ORDER BY eveDateTime
""",
"plugins": """
SELECT
Plugin,
Object_PrimaryId,
Object_SecondaryId,
DateTimeChanged,
Watched_Value1,
Watched_Value2,
Watched_Value3,
Watched_Value4,
Status
plugin,
objectPrimaryId,
objectSecondaryId,
dateTimeChanged,
watchedValue1,
watchedValue2,
watchedValue3,
watchedValue4,
status
FROM Plugins_Events
""",
}

View File

@@ -114,16 +114,16 @@ def get_notifications(db):
# Disable events where reporting is disabled
sql.execute("""
UPDATE Events SET eve_PendingAlertEmail = 0
WHERE eve_PendingAlertEmail = 1
AND eve_EventType NOT IN ('Device Down', 'Down Reconnected', 'New Device')
AND eve_MAC IN (SELECT devMac FROM Devices WHERE devAlertEvents = 0)
UPDATE Events SET evePendingAlertEmail = 0
WHERE evePendingAlertEmail = 1
AND eveEventType NOT IN ('Device Down', 'Down Reconnected', 'New Device')
AND eveMac IN (SELECT devMac FROM Devices WHERE devAlertEvents = 0)
""")
sql.execute("""
UPDATE Events SET eve_PendingAlertEmail = 0
WHERE eve_PendingAlertEmail = 1
AND eve_EventType IN ('Device Down', 'Down Reconnected')
AND eve_MAC IN (SELECT devMac FROM Devices WHERE devAlertDown = 0)
UPDATE Events SET evePendingAlertEmail = 0
WHERE evePendingAlertEmail = 1
AND eveEventType IN ('Device Down', 'Down Reconnected')
AND eveMac IN (SELECT devMac FROM Devices WHERE devAlertDown = 0)
""")
alert_down_minutes = int(get_setting_value("NTFPRCS_alert_down_time") or 0)
@@ -233,7 +233,7 @@ def skip_repeated_notifications(db):
"""
Skips sending alerts for devices recently notified.
Clears `eve_PendingAlertEmail` for events linked to devices whose last
Clears `evePendingAlertEmail` for events linked to devices whose last
notification time is within their `devSkipRepeated` interval.
Args:
@@ -244,8 +244,8 @@ def skip_repeated_notifications(db):
# due strfime : Overflow --> use "strftime / 60"
mylog("verbose", "[Skip Repeated Notifications] Skip Repeated")
db.sql.execute("""UPDATE Events SET eve_PendingAlertEmail = 0
WHERE eve_PendingAlertEmail = 1 AND eve_MAC IN
db.sql.execute("""UPDATE Events SET evePendingAlertEmail = 0
WHERE evePendingAlertEmail = 1 AND eveMac IN
(
SELECT devMac FROM Devices
WHERE devLastNotification IS NOT NULL

View File

@@ -142,17 +142,17 @@ class DeviceInstance:
objs = PluginObjectInstance().getByField(
plugPrefix='NMAP',
matchedColumn='Object_PrimaryID',
matchedColumn='objectPrimaryId',
matchedKey=primary,
returnFields=['Object_SecondaryID', 'Watched_Value2']
returnFields=['objectSecondaryId', 'watchedValue2']
)
ports = []
for o in objs:
port = int(o.get('Object_SecondaryID') or 0)
port = int(o.get('objectSecondaryId') or 0)
ports.append({"port": port, "service": o.get('Watched_Value2', '')})
ports.append({"port": port, "service": o.get('watchedValue2', '')})
return ports
@@ -471,31 +471,31 @@ class DeviceInstance:
LOWER(d.devParentMAC) AS devParentMAC,
(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
WHERE LOWER(sesMac) = LOWER(d.devMac) AND (
sesDateTimeConnection >= {period_date_sql} OR
sesDateTimeDisconnection >= {period_date_sql} OR
sesStillConnected = 1
)) AS devSessions,
(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,
WHERE LOWER(eveMac) = LOWER(d.devMac) AND eveDateTime >= {period_date_sql}
AND eveEventType 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 = 'Device Down') AS devDownAlerts,
WHERE LOWER(eveMac) = LOWER(d.devMac) AND eveDateTime >= {period_date_sql}
AND eveEventType = '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)
julianday(IFNULL(sesDateTimeDisconnection,'{now}')) -
julianday(CASE WHEN sesDateTimeConnection < {period_date_sql}
THEN {period_date_sql} ELSE sesDateTimeConnection 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)
WHERE LOWER(sesMac) = LOWER(d.devMac)
AND sesDateTimeConnection IS NOT NULL
AND (sesDateTimeDisconnection IS NOT NULL OR sesStillConnected = 1)
AND (sesDateTimeConnection >= {period_date_sql}
OR sesDateTimeDisconnection >= {period_date_sql} OR sesStillConnected = 1)
) AS devPresenceHours
FROM DevicesView d
@@ -797,7 +797,7 @@ class DeviceInstance:
"""Delete all events for a device."""
conn = get_temp_db_connection()
cur = conn.cursor()
cur.execute("DELETE FROM Events WHERE eve_MAC=?", (mac,))
cur.execute("DELETE FROM Events WHERE eveMac=?", (mac,))
conn.commit()
conn.close()
return {"success": True}

View File

@@ -21,7 +21,7 @@ class EventInstance:
def get_all(self):
conn = self._conn()
rows = conn.execute(
"SELECT * FROM Events ORDER BY eve_DateTime DESC"
"SELECT * FROM Events ORDER BY eveDateTime DESC"
).fetchall()
conn.close()
return self._rows_to_list(rows)
@@ -31,7 +31,7 @@ class EventInstance:
conn = self._conn()
rows = conn.execute("""
SELECT * FROM Events
ORDER BY eve_DateTime DESC
ORDER BY eveDateTime DESC
LIMIT ?
""", (n,)).fetchall()
conn.close()
@@ -47,8 +47,8 @@ class EventInstance:
conn = self._conn()
rows = conn.execute("""
SELECT * FROM Events
WHERE eve_DateTime >= ?
ORDER BY eve_DateTime DESC
WHERE eveDateTime >= ?
ORDER BY eveDateTime DESC
""", (since,)).fetchall()
conn.close()
return self._rows_to_list(rows)
@@ -63,8 +63,8 @@ class EventInstance:
conn = self._conn()
rows = conn.execute("""
SELECT * FROM Events
WHERE eve_DateTime >= ?
ORDER BY eve_DateTime DESC
WHERE eveDateTime >= ?
ORDER BY eveDateTime DESC
""", (since,)).fetchall()
conn.close()
return self._rows_to_list(rows)
@@ -78,8 +78,8 @@ class EventInstance:
conn = self._conn()
rows = conn.execute("""
SELECT * FROM Events
WHERE eve_DateTime BETWEEN ? AND ?
ORDER BY eve_DateTime DESC
WHERE eveDateTime BETWEEN ? AND ?
ORDER BY eveDateTime DESC
""", (start, end)).fetchall()
conn.close()
return self._rows_to_list(rows)
@@ -89,9 +89,9 @@ class EventInstance:
conn = self._conn()
conn.execute("""
INSERT OR IGNORE INTO Events (
eve_MAC, eve_IP, eve_DateTime,
eve_EventType, eve_AdditionalInfo,
eve_PendingAlertEmail, eve_PairEventRowid
eveMac, eveIp, eveDateTime,
eveEventType, eveAdditionalInfo,
evePendingAlertEmail, evePairEventRowid
) VALUES (?,?,?,?,?,?,?)
""", (mac, ip, timeNowUTC(), eventType, info,
1 if pendingAlert else 0, pairRow))
@@ -102,7 +102,7 @@ class EventInstance:
def delete_older_than(self, days: int):
cutoff = timeNowUTC(as_string=False) - timedelta(days=days)
conn = self._conn()
result = conn.execute("DELETE FROM Events WHERE eve_DateTime < ?", (cutoff,))
result = conn.execute("DELETE FROM Events WHERE eveDateTime < ?", (cutoff,))
conn.commit()
deleted_count = result.rowcount
conn.close()
@@ -124,7 +124,7 @@ class EventInstance:
cur = conn.cursor()
cur.execute(
"""
INSERT OR IGNORE INTO Events (eve_MAC, eve_IP, eve_DateTime, eve_EventType, eve_AdditionalInfo, eve_PendingAlertEmail)
INSERT OR IGNORE INTO Events (eveMac, eveIp, eveDateTime, eveEventType, eveAdditionalInfo, evePendingAlertEmail)
VALUES (?, ?, ?, ?, ?, ?)
""",
(mac, ip, start_time, event_type, additional_info, pending_alert),
@@ -145,10 +145,10 @@ class EventInstance:
cur = conn.cursor()
if mac:
sql = "SELECT * FROM Events WHERE eve_MAC=? ORDER BY eve_DateTime DESC"
sql = "SELECT * FROM Events WHERE eveMac=? ORDER BY eveDateTime DESC"
cur.execute(sql, (mac,))
else:
sql = "SELECT * FROM Events ORDER BY eve_DateTime DESC"
sql = "SELECT * FROM Events ORDER BY eveDateTime DESC"
cur.execute(sql)
rows = cur.fetchall()
@@ -163,7 +163,7 @@ class EventInstance:
cur = conn.cursor()
# Use a parameterized query with sqlite date function
sql = "DELETE FROM Events WHERE eve_DateTime <= date('now', ?)"
sql = "DELETE FROM Events WHERE eveDateTime <= date('now', ?)"
cur.execute(sql, [f"-{days} days"])
conn.commit()
@@ -197,19 +197,19 @@ class EventInstance:
sql = f"""
SELECT
(SELECT COUNT(*) FROM Events WHERE eve_DateTime >= {period_date_sql}) AS all_events,
(SELECT COUNT(*) FROM Events WHERE eveDateTime >= {period_date_sql}) AS all_events,
(SELECT COUNT(*) FROM Sessions WHERE
ses_DateTimeConnection >= {period_date_sql}
OR ses_DateTimeDisconnection >= {period_date_sql}
OR ses_StillConnected = 1
sesDateTimeConnection >= {period_date_sql}
OR sesDateTimeDisconnection >= {period_date_sql}
OR sesStillConnected = 1
) AS sessions,
(SELECT COUNT(*) FROM Sessions WHERE
(ses_DateTimeConnection IS NULL AND ses_DateTimeDisconnection >= {period_date_sql})
OR (ses_DateTimeDisconnection IS NULL AND ses_StillConnected = 0 AND ses_DateTimeConnection >= {period_date_sql})
(sesDateTimeConnection IS NULL AND sesDateTimeDisconnection >= {period_date_sql})
OR (sesDateTimeDisconnection IS NULL AND sesStillConnected = 0 AND sesDateTimeConnection >= {period_date_sql})
) AS missing,
(SELECT COUNT(*) FROM Events WHERE eve_DateTime >= {period_date_sql} AND eve_EventType LIKE 'VOIDED%') AS voided,
(SELECT COUNT(*) FROM Events WHERE eve_DateTime >= {period_date_sql} AND eve_EventType LIKE 'New Device') AS new,
(SELECT COUNT(*) FROM Events WHERE eve_DateTime >= {period_date_sql} AND eve_EventType LIKE 'Device Down') AS down
(SELECT COUNT(*) FROM Events WHERE eveDateTime >= {period_date_sql} AND eveEventType LIKE 'VOIDED%') AS voided,
(SELECT COUNT(*) FROM Events WHERE eveDateTime >= {period_date_sql} AND eveEventType LIKE 'New Device') AS new,
(SELECT COUNT(*) FROM Events WHERE eveDateTime >= {period_date_sql} AND eveEventType LIKE 'Device Down') AS down
"""
cur.execute(sql)
@@ -247,11 +247,11 @@ class EventInstance:
conn = self._conn()
sql = """
SELECT eve_MAC, COUNT(*) as event_count
SELECT eveMac, COUNT(*) as event_count
FROM Events
WHERE eve_EventType IN ('Connected','Disconnected','Device Down','Down Reconnected')
AND eve_DateTime >= datetime('now', ?)
GROUP BY eve_MAC
WHERE eveEventType IN ('Connected','Disconnected','Device Down','Down Reconnected')
AND eveDateTime >= datetime('now', ?)
GROUP BY eveMac
HAVING COUNT(*) >= ?
"""
@@ -262,6 +262,6 @@ class EventInstance:
conn.close()
if macs_only:
return {row["eve_MAC"] for row in rows}
return {row["eveMac"] for row in rows}
return [dict(row) for row in rows]

View File

@@ -31,17 +31,17 @@ class NotificationInstance:
# Create Notifications table if missing
self.db.sql.execute("""CREATE TABLE IF NOT EXISTS "Notifications" (
"Index" INTEGER,
"GUID" TEXT UNIQUE,
"DateTimeCreated" TEXT,
"DateTimePushed" TEXT,
"Status" TEXT,
"JSON" TEXT,
"Text" TEXT,
"HTML" TEXT,
"PublishedVia" TEXT,
"Extra" TEXT,
PRIMARY KEY("Index" AUTOINCREMENT)
"index" INTEGER,
"guid" TEXT UNIQUE,
"dateTimeCreated" TEXT,
"dateTimePushed" TEXT,
"status" TEXT,
"json" TEXT,
"text" TEXT,
"html" TEXT,
"publishedVia" TEXT,
"extra" TEXT,
PRIMARY KEY("index" AUTOINCREMENT)
);
""")
@@ -178,7 +178,7 @@ class NotificationInstance:
def upsert(self):
self.db.sql.execute(
"""
INSERT OR REPLACE INTO Notifications (GUID, DateTimeCreated, DateTimePushed, Status, JSON, Text, HTML, PublishedVia, Extra)
INSERT OR REPLACE INTO Notifications (guid, dateTimeCreated, dateTimePushed, "status", "json", "text", html, publishedVia, extra)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
@@ -202,7 +202,7 @@ class NotificationInstance:
self.db.sql.execute(
"""
DELETE FROM Notifications
WHERE GUID = ?
WHERE guid = ?
""",
(GUID,),
)
@@ -212,7 +212,7 @@ class NotificationInstance:
def getNew(self):
self.db.sql.execute("""
SELECT * FROM Notifications
WHERE Status = "new"
WHERE "status" = 'new'
""")
return self.db.sql.fetchall()
@@ -221,8 +221,8 @@ class NotificationInstance:
# Execute an SQL query to update the status of all notifications
self.db.sql.execute("""
UPDATE Notifications
SET Status = "processed"
WHERE Status = "new"
SET "status" = 'processed'
WHERE "status" = 'new'
""")
self.save()
@@ -234,15 +234,15 @@ class NotificationInstance:
self.db.sql.execute("""
UPDATE Devices SET devLastNotification = ?
WHERE devMac IN (
SELECT eve_MAC FROM Events
WHERE eve_PendingAlertEmail = 1
SELECT eveMac FROM Events
WHERE evePendingAlertEmail = 1
)
""", (timeNowUTC(),))
self.db.sql.execute("""
UPDATE Events SET eve_PendingAlertEmail = 0
WHERE eve_PendingAlertEmail = 1
AND eve_EventType !='Device Down' """)
UPDATE Events SET evePendingAlertEmail = 0
WHERE evePendingAlertEmail = 1
AND eveEventType !='Device Down' """)
# Clear down events flag after the reporting window passed
minutes = int(get_setting_value("NTFPRCS_alert_down_time") or 0)
@@ -250,10 +250,10 @@ class NotificationInstance:
self.db.sql.execute(
"""
UPDATE Events
SET eve_PendingAlertEmail = 0
WHERE eve_PendingAlertEmail = 1
AND eve_EventType = 'Device Down'
AND eve_DateTime < datetime('now', ?, ?)
SET evePendingAlertEmail = 0
WHERE evePendingAlertEmail = 1
AND eveEventType = 'Device Down'
AND eveDateTime < datetime('now', ?, ?)
""",
(f"-{minutes} minutes", tz_offset),
)

View File

@@ -35,18 +35,18 @@ class PluginObjectInstance:
def getByGUID(self, ObjectGUID):
return self._fetchone(
"SELECT * FROM Plugins_Objects WHERE ObjectGUID = ?", (ObjectGUID,)
"SELECT * FROM Plugins_Objects WHERE objectGuid = ?", (ObjectGUID,)
)
def exists(self, ObjectGUID):
row = self._fetchone("""
SELECT COUNT(*) AS count FROM Plugins_Objects WHERE ObjectGUID = ?
SELECT COUNT(*) AS count FROM Plugins_Objects WHERE objectGuid = ?
""", (ObjectGUID,))
return row["count"] > 0 if row else False
def getByPlugin(self, plugin):
return self._fetchall(
"SELECT * FROM Plugins_Objects WHERE Plugin = ?", (plugin,)
"SELECT * FROM Plugins_Objects WHERE plugin = ?", (plugin,)
)
def getLastNCreatedPerPlugin(self, plugin, entries=1):
@@ -54,8 +54,8 @@ class PluginObjectInstance:
"""
SELECT *
FROM Plugins_Objects
WHERE Plugin = ?
ORDER BY DateTimeCreated DESC
WHERE plugin = ?
ORDER BY dateTimeCreated DESC
LIMIT ?
""",
(plugin, entries),
@@ -63,7 +63,7 @@ class PluginObjectInstance:
def getByField(self, plugPrefix, matchedColumn, matchedKey, returnFields=None):
rows = self._fetchall(
f"SELECT * FROM Plugins_Objects WHERE Plugin = ? AND {matchedColumn} = ?",
f"SELECT * FROM Plugins_Objects WHERE plugin = ? AND {matchedColumn} = ?",
(plugPrefix, matchedKey.lower())
)
@@ -75,12 +75,12 @@ class PluginObjectInstance:
def getByPrimary(self, plugin, primary_id):
return self._fetchall("""
SELECT * FROM Plugins_Objects
WHERE Plugin = ? AND Object_PrimaryID = ?
WHERE plugin = ? AND objectPrimaryId = ?
""", (plugin, primary_id))
def getByStatus(self, status):
return self._fetchall("""
SELECT * FROM Plugins_Objects WHERE Status = ?
SELECT * FROM Plugins_Objects WHERE "status" = ?
""", (status,))
def updateField(self, ObjectGUID, field, value):
@@ -90,7 +90,7 @@ class PluginObjectInstance:
raise ValueError(msg)
self._execute(
f"UPDATE Plugins_Objects SET {field}=? WHERE ObjectGUID=?",
f"UPDATE Plugins_Objects SET {field}=? WHERE objectGuid=?",
(value, ObjectGUID)
)
@@ -100,4 +100,4 @@ class PluginObjectInstance:
mylog("none", msg)
raise ValueError(msg)
self._execute("DELETE FROM Plugins_Objects WHERE ObjectGUID=?", (ObjectGUID,))
self._execute("DELETE FROM Plugins_Objects WHERE objectGuid=?", (ObjectGUID,))

View File

@@ -238,11 +238,11 @@ class plugin_manager:
if plugin_name: # Only compute for single plugin
sql.execute(
"""
SELECT MAX(DateTimeChanged) AS last_changed,
SELECT MAX(dateTimeChanged) AS last_changed,
COUNT(*) AS total_objects,
SUM(CASE WHEN DateTimeCreated = DateTimeChanged THEN 1 ELSE 0 END) AS new_objects
SUM(CASE WHEN dateTimeCreated = dateTimeChanged THEN 1 ELSE 0 END) AS new_objects
FROM Plugins_Objects
WHERE Plugin = ?
WHERE plugin = ?
""",
(plugin_name,),
)
@@ -264,12 +264,12 @@ class plugin_manager:
else: # Compute for all plugins (full refresh)
sql.execute("""
SELECT Plugin,
MAX(DateTimeChanged) AS last_changed,
SELECT plugin,
MAX(dateTimeChanged) AS last_changed,
COUNT(*) AS total_objects,
SUM(CASE WHEN DateTimeCreated = DateTimeChanged THEN 1 ELSE 0 END) AS new_objects
SUM(CASE WHEN dateTimeCreated = dateTimeChanged THEN 1 ELSE 0 END) AS new_objects
FROM Plugins_Objects
GROUP BY Plugin
GROUP BY plugin
""")
for plugin, last_changed, total_objects, new_objects in sql.fetchall():
new_objects = new_objects or 0 # ensure it's int
@@ -496,22 +496,22 @@ def execute_plugin(db, all_plugins, plugin):
# Common part of the SQL parameters
base_params = [
0, # "Index" placeholder
0, # "index" placeholder
plugin[
"unique_prefix"
], # "Plugin" column value from the plugin dictionary
columns[0], # "Object_PrimaryID" value from columns list
columns[1], # "Object_SecondaryID" value from columns list
"null", # Placeholder for "DateTimeCreated" column
columns[2], # "DateTimeChanged" value from columns list
columns[3], # "Watched_Value1" value from columns list
columns[4], # "Watched_Value2" value from columns list
columns[5], # "Watched_Value3" value from columns list
columns[6], # "Watched_Value4" value from columns list
"not-processed", # "Status" column (placeholder)
columns[7], # "Extra" value from columns list
"null", # Placeholder for "UserData" column
columns[8], # "ForeignKey" value from columns list
], # "plugin" column value from the plugin dictionary
columns[0], # "objectPrimaryId" value from columns list
columns[1], # "objectSecondaryId" value from columns list
"null", # Placeholder for "dateTimeCreated" column
columns[2], # "dateTimeChanged" value from columns list
columns[3], # "watchedValue1" value from columns list
columns[4], # "watchedValue2" value from columns list
columns[5], # "watchedValue3" value from columns list
columns[6], # "watchedValue4" value from columns list
"not-processed", # "status" column (placeholder)
columns[7], # "extra" value from columns list
"null", # Placeholder for "userData" column
columns[8], # "foreignKey" value from columns list
tmp_SyncHubNodeName, # Sync Hub Node name
]
@@ -566,26 +566,26 @@ def execute_plugin(db, all_plugins, plugin):
# Each value corresponds to a column in the table in the order of the columns.
# Must match the Plugins_Objects and Plugins_Events database tables and can be used as input for the plugin_object_class.
base_params = [
0, # "Index" placeholder
plugin["unique_prefix"], # "Plugin" plugin dictionary
row[0], # "Object_PrimaryID" row
0, # "index" placeholder
plugin["unique_prefix"], # "plugin" plugin dictionary
row[0], # "objectPrimaryId" row
handle_empty(
row[1]
), # "Object_SecondaryID" column after handling empty values
"null", # Placeholder "DateTimeCreated" column
row[2], # "DateTimeChanged" row
row[3], # "Watched_Value1" row
row[4], # "Watched_Value2" row
), # "objectSecondaryId" column after handling empty values
"null", # Placeholder "dateTimeCreated" column
row[2], # "dateTimeChanged" row
row[3], # "watchedValue1" row
row[4], # "watchedValue2" row
handle_empty(
row[5]
), # "Watched_Value3" column after handling empty values
), # "watchedValue3" column after handling empty values
handle_empty(
row[6]
), # "Watched_Value4" column after handling empty values
"not-processed", # "Status" column (placeholder)
row[7], # "Extra" row
"null", # Placeholder "UserData" column
row[8], # "ForeignKey" row
), # "watchedValue4" column after handling empty values
"not-processed", # "status" column (placeholder)
row[7], # "extra" row
"null", # Placeholder "userData" column
row[8], # "foreignKey" row
"null", # Sync Hub Node name - Only supported with scripts
]
@@ -654,41 +654,41 @@ def execute_plugin(db, all_plugins, plugin):
# Each value corresponds to a column in the table in the order of the columns.
# Must match the Plugins_Objects and Plugins_Events database tables and can be used as input for the plugin_object_class.
base_params = [
0, # "Index" placeholder
plugin["unique_prefix"], # "Plugin"
row[0], # "Object_PrimaryID"
handle_empty(row[1]), # "Object_SecondaryID"
"null", # "DateTimeCreated" column (null placeholder)
row[2], # "DateTimeChanged"
row[3], # "Watched_Value1"
row[4], # "Watched_Value2"
handle_empty(row[5]), # "Watched_Value3"
handle_empty(row[6]), # "Watched_Value4"
"not-processed", # "Status" column (placeholder)
row[7], # "Extra"
"null", # "UserData" column (null placeholder)
row[8], # "ForeignKey"
"null", # Sync Hub Node name - Only supported with scripts
0, # "index" placeholder
plugin["unique_prefix"], # "plugin"
row[0], # "objectPrimaryId"
handle_empty(row[1]), # "objectSecondaryId"
"null", # "dateTimeCreated" column (null placeholder)
row[2], # "dateTimeChanged"
row[3], # "watchedValue1"
row[4], # "watchedValue2"
handle_empty(row[5]), # "watchedValue3"
handle_empty(row[6]), # "watchedValue4"
"not-processed", # "status" column (placeholder)
row[7], # "extra"
"null", # "userData" column (null placeholder)
row[8], # "foreignKey"
"null", # syncHubNodeName - Only supported with scripts
]
# Extend the base tuple with additional values if there are 13 columns
if len(row) == 13:
base_params.extend(
[
row[9], # "HelpVal1"
row[10], # "HelpVal2"
row[11], # "HelpVal3"
row[12], # "HelpVal4"
row[9], # "helpVal1"
row[10], # "helpVal2"
row[11], # "helpVal3"
row[12], # "helpVal4"
]
)
else:
# add padding
base_params.extend(
[
"null", # "HelpVal1"
"null", # "HelpVal2"
"null", # "HelpVal3"
"null", # "HelpVal4"
"null", # "helpVal1"
"null", # "helpVal2"
"null", # "helpVal3"
"null", # "helpVal4"
]
)
@@ -749,7 +749,7 @@ def process_plugin_events(db, plugin, plugEventsArr):
# Create plugin objects from existing database entries
plugObjectsArr = db.get_sql_array(
"SELECT * FROM Plugins_Objects where Plugin = '" + str(pluginPref) + "'"
"SELECT * FROM Plugins_Objects where plugin = '" + str(pluginPref) + "'"
)
for obj in plugObjectsArr:
@@ -894,11 +894,11 @@ def process_plugin_events(db, plugin, plugEventsArr):
sql.executemany(
"""
INSERT INTO Plugins_Objects
("Plugin", "Object_PrimaryID", "Object_SecondaryID", "DateTimeCreated",
"DateTimeChanged", "Watched_Value1", "Watched_Value2", "Watched_Value3",
"Watched_Value4", "Status", "Extra", "UserData", "ForeignKey", "SyncHubNodeName",
"HelpVal1", "HelpVal2", "HelpVal3", "HelpVal4",
"ObjectGUID")
("plugin", "objectPrimaryId", "objectSecondaryId", "dateTimeCreated",
"dateTimeChanged", "watchedValue1", "watchedValue2", "watchedValue3",
"watchedValue4", "status", "extra", "userData", "foreignKey", "syncHubNodeName",
"helpVal1", "helpVal2", "helpVal3", "helpVal4",
"objectGuid")
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
objects_to_insert,
@@ -909,12 +909,12 @@ def process_plugin_events(db, plugin, plugEventsArr):
sql.executemany(
"""
UPDATE Plugins_Objects
SET "Plugin" = ?, "Object_PrimaryID" = ?, "Object_SecondaryID" = ?, "DateTimeCreated" = ?,
"DateTimeChanged" = ?, "Watched_Value1" = ?, "Watched_Value2" = ?, "Watched_Value3" = ?,
"Watched_Value4" = ?, "Status" = ?, "Extra" = ?, "UserData" = ?, "ForeignKey" = ?, "SyncHubNodeName" = ?,
"HelpVal1" = ?, "HelpVal2" = ?, "HelpVal3" = ?, "HelpVal4" = ?,
"ObjectGUID" = ?
WHERE "Index" = ?
SET "plugin" = ?, "objectPrimaryId" = ?, "objectSecondaryId" = ?, "dateTimeCreated" = ?,
"dateTimeChanged" = ?, "watchedValue1" = ?, "watchedValue2" = ?, "watchedValue3" = ?,
"watchedValue4" = ?, "status" = ?, "extra" = ?, "userData" = ?, "foreignKey" = ?, "syncHubNodeName" = ?,
"helpVal1" = ?, "helpVal2" = ?, "helpVal3" = ?, "helpVal4" = ?,
"objectGuid" = ?
WHERE "index" = ?
""",
objects_to_update,
)
@@ -924,11 +924,11 @@ def process_plugin_events(db, plugin, plugEventsArr):
sql.executemany(
"""
INSERT INTO Plugins_Events
("Plugin", "Object_PrimaryID", "Object_SecondaryID", "DateTimeCreated",
"DateTimeChanged", "Watched_Value1", "Watched_Value2", "Watched_Value3",
"Watched_Value4", "Status", "Extra", "UserData", "ForeignKey", "SyncHubNodeName",
"HelpVal1", "HelpVal2", "HelpVal3", "HelpVal4",
"ObjectGUID")
("plugin", "objectPrimaryId", "objectSecondaryId", "dateTimeCreated",
"dateTimeChanged", "watchedValue1", "watchedValue2", "watchedValue3",
"watchedValue4", "status", "extra", "userData", "foreignKey", "syncHubNodeName",
"helpVal1", "helpVal2", "helpVal3", "helpVal4",
"objectGuid")
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
events_to_insert,
@@ -939,11 +939,11 @@ def process_plugin_events(db, plugin, plugEventsArr):
sql.executemany(
"""
INSERT INTO Plugins_History
("Plugin", "Object_PrimaryID", "Object_SecondaryID", "DateTimeCreated",
"DateTimeChanged", "Watched_Value1", "Watched_Value2", "Watched_Value3",
"Watched_Value4", "Status", "Extra", "UserData", "ForeignKey", "SyncHubNodeName",
"HelpVal1", "HelpVal2", "HelpVal3", "HelpVal4",
"ObjectGUID")
("plugin", "objectPrimaryId", "objectSecondaryId", "dateTimeCreated",
"dateTimeChanged", "watchedValue1", "watchedValue2", "watchedValue3",
"watchedValue4", "status", "extra", "userData", "foreignKey", "syncHubNodeName",
"helpVal1", "helpVal2", "helpVal3", "helpVal4",
"objectGuid")
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
history_to_insert,
@@ -993,41 +993,41 @@ def process_plugin_events(db, plugin, plugEventsArr):
tmpList = []
for col in mappedCols:
if col["column"] == "Index":
if col["column"] == "index":
tmpList.append(plgEv.index)
elif col["column"] == "Plugin":
elif col["column"] == "plugin":
tmpList.append(plgEv.pluginPref)
elif col["column"] == "Object_PrimaryID":
elif col["column"] == "objectPrimaryId":
tmpList.append(plgEv.primaryId)
elif col["column"] == "Object_SecondaryID":
elif col["column"] == "objectSecondaryId":
tmpList.append(plgEv.secondaryId)
elif col["column"] == "DateTimeCreated":
elif col["column"] == "dateTimeCreated":
tmpList.append(plgEv.created)
elif col["column"] == "DateTimeChanged":
elif col["column"] == "dateTimeChanged":
tmpList.append(plgEv.changed)
elif col["column"] == "Watched_Value1":
elif col["column"] == "watchedValue1":
tmpList.append(plgEv.watched1)
elif col["column"] == "Watched_Value2":
elif col["column"] == "watchedValue2":
tmpList.append(plgEv.watched2)
elif col["column"] == "Watched_Value3":
elif col["column"] == "watchedValue3":
tmpList.append(plgEv.watched3)
elif col["column"] == "Watched_Value4":
elif col["column"] == "watchedValue4":
tmpList.append(plgEv.watched4)
elif col["column"] == "UserData":
elif col["column"] == "userData":
tmpList.append(plgEv.userData)
elif col["column"] == "Extra":
elif col["column"] == "extra":
tmpList.append(plgEv.extra)
elif col["column"] == "Status":
elif col["column"] == "status":
tmpList.append(plgEv.status)
elif col["column"] == "SyncHubNodeName":
elif col["column"] == "syncHubNodeName":
tmpList.append(plgEv.syncHubNodeName)
elif col["column"] == "HelpVal1":
elif col["column"] == "helpVal1":
tmpList.append(plgEv.helpVal1)
elif col["column"] == "HelpVal2":
elif col["column"] == "helpVal2":
tmpList.append(plgEv.helpVal2)
elif col["column"] == "HelpVal3":
elif col["column"] == "helpVal3":
tmpList.append(plgEv.helpVal3)
elif col["column"] == "HelpVal4":
elif col["column"] == "helpVal4":
tmpList.append(plgEv.helpVal4)
# Check if there's a default value specified for this column in the JSON.
@@ -1113,10 +1113,10 @@ class plugin_object_class:
# hash for comapring watched value changes
indexNameColumnMapping = [
(6, "Watched_Value1"),
(7, "Watched_Value2"),
(8, "Watched_Value3"),
(9, "Watched_Value4"),
(6, "watchedValue1"),
(7, "watchedValue2"),
(8, "watchedValue3"),
(9, "watchedValue4"),
]
if setObj is not None:

View File

@@ -581,8 +581,8 @@ def print_scan_stats(db):
row_dict = dict(row)
mylog("trace", f" {row_dict}")
mylog("trace", " ================ Events table content where eve_PendingAlertEmail = 1 ================",)
sql.execute("select * from Events where eve_PendingAlertEmail = 1")
mylog("trace", " ================ Events table content where evePendingAlertEmail = 1 ================",)
sql.execute("select * from Events where evePendingAlertEmail = 1")
rows = sql.fetchall()
for row in rows:
row_dict = dict(row)
@@ -611,9 +611,9 @@ def create_new_devices(db):
mylog("debug", '[New Devices] Insert "New Device" Events')
query_new_device_events = f"""
INSERT OR IGNORE INTO Events (
eve_MAC, eve_IP, eve_DateTime,
eve_EventType, eve_AdditionalInfo,
eve_PendingAlertEmail
eveMac, eveIp, eveDateTime,
eveEventType, eveAdditionalInfo,
evePendingAlertEmail
)
SELECT DISTINCT scanMac, scanLastIP, '{startTime}', 'New Device', scanVendor, 1
FROM CurrentScan
@@ -630,9 +630,9 @@ def create_new_devices(db):
mylog("debug", "[New Devices] Insert Connection into session table")
sql.execute(f"""INSERT INTO Sessions (
ses_MAC, ses_IP, ses_EventTypeConnection, ses_DateTimeConnection,
ses_EventTypeDisconnection, ses_DateTimeDisconnection,
ses_StillConnected, ses_AdditionalInfo
sesMac, sesIp, sesEventTypeConnection, sesDateTimeConnection,
sesEventTypeDisconnection, sesDateTimeDisconnection,
sesStillConnected, sesAdditionalInfo
)
SELECT scanMac, scanLastIP, 'Connected', '{startTime}', NULL, NULL, 1, scanVendor
FROM CurrentScan
@@ -642,7 +642,7 @@ def create_new_devices(db):
)
AND NOT EXISTS (
SELECT 1 FROM Sessions
WHERE ses_MAC = scanMac AND ses_StillConnected = 1
WHERE sesMac = scanMac AND sesStillConnected = 1
)
""")

View File

@@ -24,8 +24,8 @@ class NameResolver:
# Check by MAC
sql.execute(f"""
SELECT Watched_Value2 FROM Plugins_Objects
WHERE Plugin = '{plugin}' AND Object_PrimaryID = '{pMAC}'
SELECT watchedValue2 FROM Plugins_Objects
WHERE plugin = '{plugin}' AND objectPrimaryId = '{pMAC}'
""")
result = sql.fetchall()
# self.db.commitDB() # Issue #1251: Optimize name resolution lookup
@@ -37,8 +37,8 @@ class NameResolver:
if get_setting_value('NEWDEV_IP_MATCH_NAME'):
sql.execute(f"""
SELECT Watched_Value2 FROM Plugins_Objects
WHERE Plugin = '{plugin}' AND Object_SecondaryID = '{pIP}'
SELECT watchedValue2 FROM Plugins_Objects
WHERE plugin = '{plugin}' AND objectSecondaryId = '{pIP}'
""")
result = sql.fetchall()
# self.db.commitDB() # Issue #1251: Optimize name resolution lookup

View File

@@ -120,27 +120,27 @@ def pair_sessions_events(db):
mylog("debug", "[Pair Session] - 1 Connections / New Devices")
sql.execute("""UPDATE Events
SET eve_PairEventRowid =
SET evePairEventRowid =
(SELECT ROWID
FROM Events AS EVE2
WHERE EVE2.eve_EventType IN ('New Device', 'Connected', 'Down Reconnected',
WHERE EVE2.eveEventType IN ('New Device', 'Connected', 'Down Reconnected',
'Device Down', 'Disconnected')
AND EVE2.eve_MAC = Events.eve_MAC
AND EVE2.eve_Datetime > Events.eve_DateTime
ORDER BY EVE2.eve_DateTime ASC LIMIT 1)
WHERE eve_EventType IN ('New Device', 'Connected', 'Down Reconnected')
AND eve_PairEventRowid IS NULL
AND EVE2.eveMac = Events.eveMac
AND EVE2.eveDateTime > Events.eveDateTime
ORDER BY EVE2.eveDateTime ASC LIMIT 1)
WHERE eveEventType IN ('New Device', 'Connected', 'Down Reconnected')
AND evePairEventRowid IS NULL
""")
# Pair Disconnection / Device Down
mylog("debug", "[Pair Session] - 2 Disconnections")
sql.execute("""UPDATE Events
SET eve_PairEventRowid =
SET evePairEventRowid =
(SELECT ROWID
FROM Events AS EVE2
WHERE EVE2.eve_PairEventRowid = Events.ROWID)
WHERE eve_EventType IN ('Device Down', 'Disconnected')
AND eve_PairEventRowid IS NULL
WHERE EVE2.evePairEventRowid = Events.ROWID)
WHERE eveEventType IN ('Device Down', 'Disconnected')
AND evePairEventRowid IS NULL
""")
mylog("debug", "[Pair Session] Pair session end")
@@ -171,9 +171,9 @@ def insert_events(db):
# Check device down non-sleeping devices (immediate on first absence)
mylog("debug", "[Events] - 1a - Devices down (non-sleeping)")
sql.execute(f"""INSERT OR IGNORE INTO Events (eve_MAC, eve_IP, eve_DateTime,
eve_EventType, eve_AdditionalInfo,
eve_PendingAlertEmail)
sql.execute(f"""INSERT OR IGNORE INTO Events (eveMac, eveIp, eveDateTime,
eveEventType, eveAdditionalInfo,
evePendingAlertEmail)
SELECT devMac, devLastIP, '{startTime}', 'Device Down', '', 1
FROM DevicesView
WHERE devAlertDown != 0
@@ -185,9 +185,9 @@ def insert_events(db):
# Check device down sleeping devices whose sleep window has expired
mylog("debug", "[Events] - 1b - Devices down (sleep expired)")
sql.execute(f"""INSERT OR IGNORE INTO Events (eve_MAC, eve_IP, eve_DateTime,
eve_EventType, eve_AdditionalInfo,
eve_PendingAlertEmail)
sql.execute(f"""INSERT OR IGNORE INTO Events (eveMac, eveIp, eveDateTime,
eveEventType, eveAdditionalInfo,
evePendingAlertEmail)
SELECT devMac, devLastIP, '{startTime}', 'Device Down', '', 1
FROM DevicesView
WHERE devAlertDown != 0
@@ -197,33 +197,33 @@ def insert_events(db):
AND NOT EXISTS (SELECT 1 FROM CurrentScan
WHERE devMac = scanMac)
AND NOT EXISTS (SELECT 1 FROM Events
WHERE eve_MAC = devMac
AND eve_EventType = 'Device Down'
AND eve_DateTime >= devLastConnection
WHERE eveMac = devMac
AND eveEventType = 'Device Down'
AND eveDateTime >= devLastConnection
) """)
# Check new Connections or Down Reconnections
mylog("debug", "[Events] - 2 - New Connections")
sql.execute(f""" INSERT OR IGNORE INTO Events (eve_MAC, eve_IP, eve_DateTime,
eve_EventType, eve_AdditionalInfo,
eve_PendingAlertEmail)
sql.execute(f""" INSERT OR IGNORE INTO Events (eveMac, eveIp, eveDateTime,
eveEventType, eveAdditionalInfo,
evePendingAlertEmail)
SELECT DISTINCT c.scanMac, c.scanLastIP, '{startTime}',
CASE
WHEN last_event.eve_EventType = 'Device Down' and last_event.eve_PendingAlertEmail = 0 THEN 'Down Reconnected'
WHEN last_event.eveEventType = 'Device Down' and last_event.evePendingAlertEmail = 0 THEN 'Down Reconnected'
ELSE 'Connected'
END,
'',
1
FROM CurrentScan AS c
LEFT JOIN LatestEventsPerMAC AS last_event ON c.scanMac = last_event.eve_MAC
WHERE last_event.devPresentLastScan = 0 OR last_event.eve_MAC IS NULL
LEFT JOIN LatestEventsPerMAC AS last_event ON c.scanMac = last_event.eveMac
WHERE last_event.devPresentLastScan = 0 OR last_event.eveMac IS NULL
""")
# Check disconnections
mylog("debug", "[Events] - 3 - Disconnections")
sql.execute(f"""INSERT OR IGNORE INTO Events (eve_MAC, eve_IP, eve_DateTime,
eve_EventType, eve_AdditionalInfo,
eve_PendingAlertEmail)
sql.execute(f"""INSERT OR IGNORE INTO Events (eveMac, eveIp, eveDateTime,
eveEventType, eveAdditionalInfo,
evePendingAlertEmail)
SELECT devMac, devLastIP, '{startTime}', 'Disconnected', '',
devAlertEvents
FROM Devices
@@ -235,9 +235,9 @@ def insert_events(db):
# Check IP Changed
mylog("debug", "[Events] - 4 - IP Changes")
sql.execute(f"""INSERT OR IGNORE INTO Events (eve_MAC, eve_IP, eve_DateTime,
eve_EventType, eve_AdditionalInfo,
eve_PendingAlertEmail)
sql.execute(f"""INSERT OR IGNORE INTO Events (eveMac, eveIp, eveDateTime,
eveEventType, eveAdditionalInfo,
evePendingAlertEmail)
SELECT scanMac, scanLastIP, '{startTime}', 'IP Changed',
'Previous IP: '|| devLastIP, devAlertEvents
FROM Devices, CurrentScan
@@ -279,7 +279,7 @@ def insertOnlineHistory(db):
# Prepare the insert query using parameterized inputs
insert_query = """
INSERT INTO Online_History (Scan_Date, Online_Devices, Down_Devices, All_Devices, Archived_Devices, Offline_Devices)
INSERT INTO Online_History (scanDate, onlineDevices, downDevices, allDevices, archivedDevices, offlineDevices)
VALUES (?, ?, ?, ?, ?, ?)
"""

View File

@@ -245,7 +245,7 @@ def handle_empty(value):
# -------------------------------------------------------------------------------
# Get and return a plugin object based on key-value pairs
# keyValues example: getPluginObject({"Plugin":"MQTT", "Watched_Value4":"someValue"})
# keyValues example: getPluginObject({"plugin":"MQTT", "watchedValue4":"someValue"})
def getPluginObject(keyValues):
plugins_objects = apiPath + "table_plugins_objects.json"

View File

@@ -40,10 +40,10 @@ class UpdateFieldAction(Action):
processed = False
# currently unused
if isinstance(obj, dict) and "ObjectGUID" in obj:
if isinstance(obj, dict) and "objectGuid" in obj:
mylog("debug", f"[WF] Updating Object '{obj}' ")
plugin_instance = PluginObjectInstance()
plugin_instance.updateField(obj["ObjectGUID"], self.field, self.value)
plugin_instance.updateField(obj["objectGuid"], self.field, self.value)
processed = True
elif isinstance(obj, dict) and "devGUID" in obj:
@@ -77,10 +77,10 @@ class DeleteObjectAction(Action):
processed = False
# currently unused
if isinstance(obj, dict) and "ObjectGUID" in obj:
if isinstance(obj, dict) and "objectGuid" in obj:
mylog("debug", f"[WF] Updating Object '{obj}' ")
plugin_instance = PluginObjectInstance()
plugin_instance.delete(obj["ObjectGUID"])
plugin_instance.delete(obj["objectGuid"])
processed = True
elif isinstance(obj, dict) and "devGUID" in obj:

View File

@@ -23,29 +23,29 @@ class AppEvent_obj:
self.object_mapping = {
"Devices": {
"fields": {
"ObjectGUID": "NEW.devGUID",
"ObjectPrimaryID": "NEW.devMac",
"ObjectSecondaryID": "NEW.devLastIP",
"ObjectForeignKey": "NEW.devGUID",
"ObjectStatus": "CASE WHEN NEW.devPresentLastScan = 1 THEN 'online' ELSE 'offline' END",
"ObjectStatusColumn": "'devPresentLastScan'",
"ObjectIsNew": "NEW.devIsNew",
"ObjectIsArchived": "NEW.devIsArchived",
"ObjectPlugin": "'DEVICES'",
"objectGuid": "NEW.devGUID",
"objectPrimaryId": "NEW.devMac",
"objectSecondaryId": "NEW.devLastIP",
"objectForeignKey": "NEW.devGUID",
"objectStatus": "CASE WHEN NEW.devPresentLastScan = 1 THEN 'online' ELSE 'offline' END",
"objectStatusColumn": "'devPresentLastScan'",
"objectIsNew": "NEW.devIsNew",
"objectIsArchived": "NEW.devIsArchived",
"objectPlugin": "'DEVICES'",
}
}
# ,
# "Plugins_Objects": {
# "fields": {
# "ObjectGUID": "NEW.ObjectGUID",
# "ObjectPrimaryID": "NEW.Plugin",
# "ObjectSecondaryID": "NEW.Object_PrimaryID",
# "ObjectForeignKey": "NEW.ForeignKey",
# "ObjectStatus": "NEW.Status",
# "ObjectStatusColumn": "'Status'",
# "ObjectIsNew": "CASE WHEN NEW.Status = 'new' THEN 1 ELSE 0 END",
# "ObjectIsArchived": "0", # Default value
# "ObjectPlugin": "NEW.Plugin"
# "objectGuid": "NEW.objectGuid",
# "objectPrimaryId": "NEW.plugin",
# "objectSecondaryId": "NEW.objectPrimaryId",
# "objectForeignKey": "NEW.foreignKey",
# "objectStatus": "NEW.status",
# "objectStatusColumn": "'status'",
# "objectIsNew": "CASE WHEN NEW.status = 'new' THEN 1 ELSE 0 END",
# "objectIsArchived": "0", # Default value
# "objectPlugin": "NEW.plugin"
# }
# }
}
@@ -79,26 +79,26 @@ class AppEvent_obj:
"""Creates the AppEvents table if it doesn't exist."""
self.db.sql.execute("""
CREATE TABLE IF NOT EXISTS "AppEvents" (
"Index" INTEGER PRIMARY KEY AUTOINCREMENT,
"GUID" TEXT UNIQUE,
"AppEventProcessed" BOOLEAN,
"DateTimeCreated" TEXT,
"ObjectType" TEXT,
"ObjectGUID" TEXT,
"ObjectPlugin" TEXT,
"ObjectPrimaryID" TEXT,
"ObjectSecondaryID" TEXT,
"ObjectForeignKey" TEXT,
"ObjectIndex" TEXT,
"ObjectIsNew" BOOLEAN,
"ObjectIsArchived" BOOLEAN,
"ObjectStatusColumn" TEXT,
"ObjectStatus" TEXT,
"AppEventType" TEXT,
"Helper1" TEXT,
"Helper2" TEXT,
"Helper3" TEXT,
"Extra" TEXT
"index" INTEGER PRIMARY KEY AUTOINCREMENT,
"guid" TEXT UNIQUE,
"appEventProcessed" BOOLEAN,
"dateTimeCreated" TEXT,
"objectType" TEXT,
"objectGuid" TEXT,
"objectPlugin" TEXT,
"objectPrimaryId" TEXT,
"objectSecondaryId" TEXT,
"objectForeignKey" TEXT,
"objectIndex" TEXT,
"objectIsNew" BOOLEAN,
"objectIsArchived" BOOLEAN,
"objectStatusColumn" TEXT,
"objectStatus" TEXT,
"appEventType" TEXT,
"helper1" TEXT,
"helper2" TEXT,
"helper3" TEXT,
"extra" TEXT
);
""")
@@ -111,43 +111,43 @@ class AppEvent_obj:
AFTER {event.upper()} ON "{table_name}"
WHEN NOT EXISTS (
SELECT 1 FROM AppEvents
WHERE AppEventProcessed = 0
AND ObjectType = '{table_name}'
AND ObjectGUID = {manage_prefix(config["fields"]["ObjectGUID"], event)}
AND ObjectStatus = {manage_prefix(config["fields"]["ObjectStatus"], event)}
AND AppEventType = '{event.lower()}'
WHERE appEventProcessed = 0
AND objectType = '{table_name}'
AND objectGuid = {manage_prefix(config["fields"]["objectGuid"], event)}
AND objectStatus = {manage_prefix(config["fields"]["objectStatus"], event)}
AND appEventType = '{event.lower()}'
)
BEGIN
INSERT INTO "AppEvents" (
"GUID",
"DateTimeCreated",
"AppEventProcessed",
"ObjectType",
"ObjectGUID",
"ObjectPrimaryID",
"ObjectSecondaryID",
"ObjectStatus",
"ObjectStatusColumn",
"ObjectIsNew",
"ObjectIsArchived",
"ObjectForeignKey",
"ObjectPlugin",
"AppEventType"
"guid",
"dateTimeCreated",
"appEventProcessed",
"objectType",
"objectGuid",
"objectPrimaryId",
"objectSecondaryId",
"objectStatus",
"objectStatusColumn",
"objectIsNew",
"objectIsArchived",
"objectForeignKey",
"objectPlugin",
"appEventType"
)
VALUES (
{sql_generateGuid},
DATETIME('now'),
FALSE,
'{table_name}',
{manage_prefix(config["fields"]["ObjectGUID"], event)}, -- ObjectGUID
{manage_prefix(config["fields"]["ObjectPrimaryID"], event)}, -- ObjectPrimaryID
{manage_prefix(config["fields"]["ObjectSecondaryID"], event)}, -- ObjectSecondaryID
{manage_prefix(config["fields"]["ObjectStatus"], event)}, -- ObjectStatus
{manage_prefix(config["fields"]["ObjectStatusColumn"], event)}, -- ObjectStatusColumn
{manage_prefix(config["fields"]["ObjectIsNew"], event)}, -- ObjectIsNew
{manage_prefix(config["fields"]["ObjectIsArchived"], event)}, -- ObjectIsArchived
{manage_prefix(config["fields"]["ObjectForeignKey"], event)}, -- ObjectForeignKey
{manage_prefix(config["fields"]["ObjectPlugin"], event)}, -- ObjectForeignKey
{manage_prefix(config["fields"]["objectGuid"], event)}, -- objectGuid
{manage_prefix(config["fields"]["objectPrimaryId"], event)}, -- objectPrimaryId
{manage_prefix(config["fields"]["objectSecondaryId"], event)}, -- objectSecondaryId
{manage_prefix(config["fields"]["objectStatus"], event)}, -- objectStatus
{manage_prefix(config["fields"]["objectStatusColumn"], event)}, -- objectStatusColumn
{manage_prefix(config["fields"]["objectIsNew"], event)}, -- objectIsNew
{manage_prefix(config["fields"]["objectIsArchived"], event)}, -- objectIsArchived
{manage_prefix(config["fields"]["objectForeignKey"], event)}, -- objectForeignKey
{manage_prefix(config["fields"]["objectPlugin"], event)}, -- objectPlugin
'{event.lower()}'
);
END;

View File

@@ -33,8 +33,8 @@ class WorkflowManager:
"""Get new unprocessed events from the AppEvents table."""
result = self.db.sql.execute("""
SELECT * FROM AppEvents
WHERE AppEventProcessed = 0
ORDER BY DateTimeCreated ASC
WHERE appEventProcessed = 0
ORDER BY dateTimeCreated ASC
""").fetchall()
mylog("none", [f"[WF] get_new_app_events - new events count: {len(result)}"])
@@ -44,7 +44,7 @@ class WorkflowManager:
def process_event(self, event):
"""Process the events. Check if events match a workflow trigger"""
evGuid = event["GUID"]
evGuid = event["guid"]
mylog("verbose", [f"[WF] Processing event with GUID {evGuid}"])
@@ -67,10 +67,10 @@ class WorkflowManager:
self.db.sql.execute(
"""
UPDATE AppEvents
SET AppEventProcessed = 1
WHERE "Index" = ?
SET appEventProcessed = 1
WHERE "index" = ?
""",
(event["Index"],),
(event["index"],),
) # Pass the event's unique identifier
self.db.commitDB()

View File

@@ -21,7 +21,7 @@ class Trigger:
self.event_type = triggerJson["event_type"]
self.event = event # Store the triggered event context, if provided
self.triggered = (
self.object_type == event["ObjectType"] and self.event_type == event["AppEventType"]
self.object_type == event["objectType"] and self.event_type == event["appEventType"]
)
mylog("debug", f"""[WF] self.triggered '{self.triggered}' for event '{get_array_from_sql_rows(event)} and trigger {json.dumps(triggerJson)}' """)
@@ -33,7 +33,7 @@ class Trigger:
if db_table == "Devices":
refField = "devGUID"
elif db_table == "Plugins_Objects":
refField = "ObjectGUID"
refField = "objectGuid"
else:
m = f"[WF] Unsupported object_type: {self.object_type}"
mylog("none", [m])
@@ -42,7 +42,7 @@ class Trigger:
query = f"""
SELECT * FROM
{db_table}
WHERE {refField} = '{event["ObjectGUID"]}'
WHERE {refField} = '{event["objectGuid"]}'
"""
mylog("debug", [query])