mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-04-15 22:51:37 -07:00
refactor db upgrade
This commit is contained in:
+1
-1
@@ -22,4 +22,4 @@ For a comparison, this is how the UI looks like if you are on the latest stable
|
|||||||
|
|
||||||
## Implementation details
|
## Implementation details
|
||||||
|
|
||||||
During build a [/app/front/buildtimestamp.txt](https://github.com/jokob-sk/NetAlertX/blob/092797e75ccfa8359444ad149e727358ac4da05f/Dockerfile#L44) file is created. The app then periodically checks if a new release is available with a newer timestamp in GitHub's rest-based JSON endpoint (check the `def isNewVersion():` method for details).
|
During build a [/app/front/buildtimestamp.txt](https://github.com/jokob-sk/NetAlertX/blob/092797e75ccfa8359444ad149e727358ac4da05f/Dockerfile#L44) file is created. The app then periodically checks if a new release is available with a newer timestamp in GitHub's rest-based JSON endpoint (check the `def isNewVersion:` method for details).
|
||||||
Regular → Executable
+2
-2
@@ -78,8 +78,8 @@ def main ():
|
|||||||
db.open()
|
db.open()
|
||||||
sql = db.sql # To-Do replace with the db class
|
sql = db.sql # To-Do replace with the db class
|
||||||
|
|
||||||
# Upgrade DB if needed
|
# Init DB
|
||||||
db.upgradeDB()
|
db.initDB()
|
||||||
|
|
||||||
# Initialize the WorkflowManager
|
# Initialize the WorkflowManager
|
||||||
workflow_manager = WorkflowManager(db)
|
workflow_manager = WorkflowManager(db)
|
||||||
|
|||||||
+18
-269
@@ -10,6 +10,7 @@ from const import fullDbPath, sql_devices_stats, sql_devices_all, sql_generateGu
|
|||||||
from logger import mylog
|
from logger import mylog
|
||||||
from helper import json_obj, initOrSetParam, row_to_json, timeNowTZ
|
from helper import json_obj, initOrSetParam, row_to_json, timeNowTZ
|
||||||
from workflows.app_events import AppEvent_obj
|
from workflows.app_events import AppEvent_obj
|
||||||
|
from db.db_upgrade import ensure_column, ensure_views, ensure_CurrentScan, ensure_plugins_tables, ensure_Parameters, ensure_Settings
|
||||||
|
|
||||||
class DB():
|
class DB():
|
||||||
"""
|
"""
|
||||||
@@ -76,287 +77,35 @@ class DB():
|
|||||||
return arr
|
return arr
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
def upgradeDB(self):
|
def initDB(self):
|
||||||
"""
|
"""
|
||||||
Check the current tables in the DB and upgrade them if neccessary
|
Check the current tables in the DB and upgrade them if neccessary
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# Add Devices fields if missing
|
||||||
# Alter Devices table
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# VIEWS
|
|
||||||
|
|
||||||
self.sql.execute(""" DROP VIEW IF EXISTS Events_Devices;""")
|
|
||||||
self.sql.execute(""" CREATE VIEW Events_Devices AS
|
|
||||||
SELECT *
|
|
||||||
FROM Events
|
|
||||||
LEFT JOIN Devices ON eve_MAC = devMac;
|
|
||||||
""")
|
|
||||||
|
|
||||||
|
|
||||||
self.sql.execute(""" DROP VIEW IF EXISTS LatestEventsPerMAC;""")
|
|
||||||
self.sql.execute("""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
|
|
||||||
FROM Events AS e
|
|
||||||
)
|
|
||||||
SELECT
|
|
||||||
e.*,
|
|
||||||
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.cur_MAC
|
|
||||||
WHERE e.row_num = 1;""")
|
|
||||||
|
|
||||||
self.sql.execute(""" DROP VIEW IF EXISTS Sessions_Devices;""")
|
|
||||||
self.sql.execute("""CREATE VIEW Sessions_Devices AS SELECT * FROM Sessions LEFT JOIN "Devices" ON ses_MAC = devMac;""")
|
|
||||||
|
|
||||||
|
|
||||||
# add fields if missing
|
|
||||||
|
|
||||||
# devFQDN missing?
|
# devFQDN
|
||||||
devFQDN_missing = self.sql.execute ("""
|
if ensure_column(self.sql, "Devices", "devFQDN", "TEXT") is False:
|
||||||
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='devFQDN'
|
return # addition failed
|
||||||
""").fetchone()[0] == 0
|
|
||||||
|
|
||||||
if devFQDN_missing:
|
|
||||||
|
|
||||||
mylog('verbose', ["[upgradeDB] Adding devFQDN to the Devices table"])
|
|
||||||
self.sql.execute("""
|
|
||||||
ALTER TABLE "Devices" ADD "devFQDN" TEXT
|
|
||||||
""")
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# Settings table setup
|
# Settings table setup
|
||||||
# -------------------------------------------------------------------------
|
ensure_Settings(self.sql)
|
||||||
|
|
||||||
|
# Parameters tables setup
|
||||||
|
ensure_Parameters(self.sql)
|
||||||
|
|
||||||
# Re-creating Settings table
|
|
||||||
mylog('verbose', ["[upgradeDB] Re-creating Settings table"])
|
|
||||||
|
|
||||||
self.sql.execute(""" DROP TABLE IF EXISTS Settings;""")
|
|
||||||
self.sql.execute("""
|
|
||||||
CREATE TABLE "Settings" (
|
|
||||||
"setKey" TEXT,
|
|
||||||
"setName" TEXT,
|
|
||||||
"setDescription" TEXT,
|
|
||||||
"setType" TEXT,
|
|
||||||
"setOptions" TEXT,
|
|
||||||
"setGroup" TEXT,
|
|
||||||
"setValue" TEXT,
|
|
||||||
"setEvents" TEXT,
|
|
||||||
"setOverriddenByEnv" INTEGER
|
|
||||||
);
|
|
||||||
""")
|
|
||||||
|
|
||||||
|
|
||||||
# Create Pholus_Scan table if missing
|
|
||||||
mylog('verbose', ["[upgradeDB] Removing Pholus_Scan table"])
|
|
||||||
self.sql.execute("""DROP TABLE IF EXISTS Pholus_Scan""")
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# Parameters table setup
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# Re-creating Parameters table
|
|
||||||
mylog('verbose', ["[upgradeDB] Re-creating Parameters table"])
|
|
||||||
self.sql.execute("DROP TABLE Parameters;")
|
|
||||||
|
|
||||||
self.sql.execute("""
|
|
||||||
CREATE TABLE "Parameters" (
|
|
||||||
"par_ID" TEXT PRIMARY KEY,
|
|
||||||
"par_Value" TEXT
|
|
||||||
);
|
|
||||||
""")
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# Plugins tables setup
|
# Plugins tables setup
|
||||||
# -------------------------------------------------------------------------
|
ensure_plugins_tables(self.sql)
|
||||||
|
|
||||||
# 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)
|
|
||||||
); """
|
|
||||||
self.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)
|
|
||||||
); """
|
|
||||||
self.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)
|
|
||||||
); """
|
|
||||||
self.sql.execute(sql_Plugins_History)
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# Plugins_Language_Strings table setup
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# Dynamically generated language strings
|
|
||||||
self.sql.execute("DROP TABLE IF EXISTS Plugins_Language_Strings;")
|
|
||||||
self.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)
|
|
||||||
); """)
|
|
||||||
|
|
||||||
self.commitDB()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# CurrentScan table setup
|
# CurrentScan table setup
|
||||||
# -------------------------------------------------------------------------
|
ensure_CurrentScan(self.sql)
|
||||||
|
|
||||||
# indicates, if CurrentScan table is available
|
|
||||||
# 🐛 CurrentScan DEBUG: comment out below when debugging to keep the CurrentScan table after restarts/scan finishes
|
|
||||||
self.sql.execute("DROP TABLE IF EXISTS CurrentScan;")
|
|
||||||
self.sql.execute(""" CREATE TABLE IF NOT EXISTS CurrentScan (
|
|
||||||
cur_MAC STRING(50) NOT NULL COLLATE NOCASE,
|
|
||||||
cur_IP STRING(50) NOT NULL COLLATE NOCASE,
|
|
||||||
cur_Vendor STRING(250),
|
|
||||||
cur_ScanMethod STRING(10),
|
|
||||||
cur_Name STRING(250),
|
|
||||||
cur_LastQuery STRING(250),
|
|
||||||
cur_DateTime STRING(250),
|
|
||||||
cur_SyncHubNodeName STRING(50),
|
|
||||||
cur_NetworkSite STRING(250),
|
|
||||||
cur_SSID STRING(250),
|
|
||||||
cur_NetworkNodeMAC STRING(250),
|
|
||||||
cur_PORT STRING(250),
|
|
||||||
cur_Type STRING(250),
|
|
||||||
UNIQUE(cur_MAC)
|
|
||||||
);
|
|
||||||
""")
|
|
||||||
|
|
||||||
self.commitDB()
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# Create the LatestEventsPerMAC view
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# Dynamically generated language strings
|
|
||||||
self.sql.execute(""" CREATE VIEW IF NOT EXISTS LatestEventsPerMAC AS
|
|
||||||
WITH RankedEvents AS (
|
|
||||||
SELECT
|
|
||||||
e.*,
|
|
||||||
ROW_NUMBER() OVER (PARTITION BY e.eve_MAC ORDER BY e.eve_DateTime DESC) AS row_num
|
|
||||||
FROM Events AS e
|
|
||||||
)
|
|
||||||
SELECT
|
|
||||||
e.*,
|
|
||||||
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.cur_MAC
|
|
||||||
WHERE e.row_num = 1;
|
|
||||||
""")
|
|
||||||
|
|
||||||
# handling the Convert_Events_to_Sessions / Sessions screens
|
|
||||||
self.sql.execute("""DROP VIEW IF EXISTS Convert_Events_to_Sessions;""")
|
|
||||||
self.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
|
|
||||||
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')
|
|
||||||
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
|
|
||||||
FROM Events AS EVE1
|
|
||||||
WHERE (eve_EventType = 'Device Down' OR
|
|
||||||
eve_EventType = 'Disconnected') AND
|
|
||||||
EVE1.eve_PairEventRowID IS NULL;
|
|
||||||
""")
|
|
||||||
|
|
||||||
self.commitDB()
|
|
||||||
|
|
||||||
|
# Views
|
||||||
|
ensure_views(self.sql)
|
||||||
|
|
||||||
|
# commit changes
|
||||||
|
self.commitDB()
|
||||||
|
|
||||||
# Init the AppEvent database table
|
# Init the AppEvent database table
|
||||||
AppEvent_obj(self)
|
AppEvent_obj(self)
|
||||||
|
|
||||||
|
|||||||
Executable
+330
@@ -0,0 +1,330 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
# Register NetAlertX directories
|
||||||
|
INSTALL_PATH="/app"
|
||||||
|
sys.path.extend([f"{INSTALL_PATH}/server"])
|
||||||
|
|
||||||
|
from logger import mylog
|
||||||
|
from messaging.in_app import write_notification
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_column(sql, table: str, column_name: str, column_type: str) -> bool:
|
||||||
|
"""
|
||||||
|
Ensures a column exists in the specified table. If missing, attempts to add it.
|
||||||
|
Returns True on success, False on failure.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- sql: database cursor or connection wrapper (must support execute() and fetchall()).
|
||||||
|
- table: name of the table (e.g., "Devices").
|
||||||
|
- column_name: name of the column to ensure.
|
||||||
|
- column_type: SQL type of the column (e.g., "TEXT", "INTEGER", "BOOLEAN").
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Get actual columns from DB
|
||||||
|
sql.execute(f'PRAGMA table_info("{table}")')
|
||||||
|
actual_columns = [row[1] for row in sql.fetchall()]
|
||||||
|
|
||||||
|
# Check if target column is already present
|
||||||
|
if column_name in actual_columns:
|
||||||
|
return True # Already exists
|
||||||
|
|
||||||
|
# Define the expected columns (hardcoded base schema) [v25.5.24] - available in teh default app.db
|
||||||
|
expected_columns = [
|
||||||
|
'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'
|
||||||
|
]
|
||||||
|
|
||||||
|
# Check for mismatches in base schema
|
||||||
|
missing = set(expected_columns) - set(actual_columns)
|
||||||
|
extra = set(actual_columns) - set(expected_columns)
|
||||||
|
|
||||||
|
if missing:
|
||||||
|
msg = (f"[db_upgrade] ⚠ ERROR: Unexpected DB structure "
|
||||||
|
f"(missing: {', '.join(missing) if missing else 'none'}, "
|
||||||
|
f"extra: {', '.join(extra) if extra else 'none'}) - "
|
||||||
|
"aborting schema change to prevent corruption. "
|
||||||
|
"Check https://github.com/jokob-sk/NetAlertX/blob/main/docs/UPDATES.md")
|
||||||
|
mylog('none', [msg])
|
||||||
|
write_notification(msg)
|
||||||
|
return False
|
||||||
|
|
||||||
|
if extra:
|
||||||
|
msg = f'[db_upgrade] Extra DB columns detected in {table}: {', '.join(extra)}'
|
||||||
|
mylog('none', [msg])
|
||||||
|
|
||||||
|
# Add missing column
|
||||||
|
mylog('verbose', [f"[db_upgrade] Adding '{column_name}' ({column_type}) to {table} table"])
|
||||||
|
sql.execute(f'ALTER TABLE "{table}" ADD "{column_name}" {column_type}')
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
mylog('none', [f"[db_upgrade] ERROR while adding '{column_name}': {e}"])
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_views(sql) -> bool:
|
||||||
|
"""
|
||||||
|
Ensures required views exist.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- sql: database cursor or connection wrapper (must support execute() and fetchall()).
|
||||||
|
"""
|
||||||
|
sql.execute(""" DROP VIEW IF EXISTS Events_Devices;""")
|
||||||
|
sql.execute(""" CREATE VIEW Events_Devices AS
|
||||||
|
SELECT *
|
||||||
|
FROM Events
|
||||||
|
LEFT JOIN Devices ON eve_MAC = devMac;
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
sql.execute(""" DROP VIEW IF EXISTS LatestEventsPerMAC;""")
|
||||||
|
sql.execute("""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
|
||||||
|
FROM Events AS e
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
e.*,
|
||||||
|
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.cur_MAC
|
||||||
|
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;""")
|
||||||
|
|
||||||
|
sql.execute(""" CREATE VIEW IF NOT EXISTS LatestEventsPerMAC AS
|
||||||
|
WITH RankedEvents AS (
|
||||||
|
SELECT
|
||||||
|
e.*,
|
||||||
|
ROW_NUMBER() OVER (PARTITION BY e.eve_MAC ORDER BY e.eve_DateTime DESC) AS row_num
|
||||||
|
FROM Events AS e
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
e.*,
|
||||||
|
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.cur_MAC
|
||||||
|
WHERE e.row_num = 1;
|
||||||
|
""")
|
||||||
|
|
||||||
|
# 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
|
||||||
|
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')
|
||||||
|
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
|
||||||
|
FROM Events AS EVE1
|
||||||
|
WHERE (eve_EventType = 'Device Down' OR
|
||||||
|
eve_EventType = 'Disconnected') AND
|
||||||
|
EVE1.eve_PairEventRowID IS NULL;
|
||||||
|
""")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def ensure_CurrentScan(sql) -> bool:
|
||||||
|
"""
|
||||||
|
Ensures required CurrentScan table exist.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- sql: database cursor or connection wrapper (must support execute() and fetchall()).
|
||||||
|
"""
|
||||||
|
# 🐛 CurrentScan DEBUG: comment out below when debugging to keep the CurrentScan table after restarts/scan finishes
|
||||||
|
sql.execute("DROP TABLE IF EXISTS CurrentScan;")
|
||||||
|
sql.execute(""" CREATE TABLE IF NOT EXISTS CurrentScan (
|
||||||
|
cur_MAC STRING(50) NOT NULL COLLATE NOCASE,
|
||||||
|
cur_IP STRING(50) NOT NULL COLLATE NOCASE,
|
||||||
|
cur_Vendor STRING(250),
|
||||||
|
cur_ScanMethod STRING(10),
|
||||||
|
cur_Name STRING(250),
|
||||||
|
cur_LastQuery STRING(250),
|
||||||
|
cur_DateTime STRING(250),
|
||||||
|
cur_SyncHubNodeName STRING(50),
|
||||||
|
cur_NetworkSite STRING(250),
|
||||||
|
cur_SSID STRING(250),
|
||||||
|
cur_NetworkNodeMAC STRING(250),
|
||||||
|
cur_PORT STRING(250),
|
||||||
|
cur_Type STRING(250),
|
||||||
|
UNIQUE(cur_MAC)
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def ensure_Parameters(sql) -> bool:
|
||||||
|
"""
|
||||||
|
Ensures required Parameters table exist.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- sql: database cursor or connection wrapper (must support execute() and fetchall()).
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Re-creating Parameters table
|
||||||
|
mylog('verbose', ["[db_upgrade] Re-creating Parameters table"])
|
||||||
|
sql.execute("DROP TABLE Parameters;")
|
||||||
|
|
||||||
|
sql.execute("""
|
||||||
|
CREATE TABLE "Parameters" (
|
||||||
|
"par_ID" TEXT PRIMARY KEY,
|
||||||
|
"par_Value" TEXT
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def ensure_Settings(sql) -> bool:
|
||||||
|
"""
|
||||||
|
Ensures required Settings table exist.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- sql: database cursor or connection wrapper (must support execute() and fetchall()).
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Re-creating Settings table
|
||||||
|
mylog('verbose', ["[db_upgrade] Re-creating Settings table"])
|
||||||
|
|
||||||
|
sql.execute(""" DROP TABLE IF EXISTS Settings;""")
|
||||||
|
sql.execute("""
|
||||||
|
CREATE TABLE "Settings" (
|
||||||
|
"setKey" TEXT,
|
||||||
|
"setName" TEXT,
|
||||||
|
"setDescription" TEXT,
|
||||||
|
"setType" TEXT,
|
||||||
|
"setOptions" TEXT,
|
||||||
|
"setGroup" TEXT,
|
||||||
|
"setValue" TEXT,
|
||||||
|
"setEvents" TEXT,
|
||||||
|
"setOverriddenByEnv" INTEGER
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_plugins_tables(sql) -> bool:
|
||||||
|
"""
|
||||||
|
Ensures required plugins tables exist.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- sql: database cursor or connection wrapper (must support execute() and fetchall()).
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
); """
|
||||||
|
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)
|
||||||
|
); """
|
||||||
|
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)
|
||||||
|
); """
|
||||||
|
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)
|
||||||
|
); """)
|
||||||
|
|
||||||
|
return True
|
||||||
Reference in New Issue
Block a user