Workflows v0.1.1 🆕

This commit is contained in:
Jokob-sk
2024-02-04 13:17:41 +11:00
parent 528caa900c
commit 519cf9f69a
20 changed files with 440 additions and 102 deletions

View File

@@ -52,7 +52,8 @@ services:
- ${DEV_LOCATION}/front/settings.php:/home/pi/pialert/front/settings.php - ${DEV_LOCATION}/front/settings.php:/home/pi/pialert/front/settings.php
- ${DEV_LOCATION}/front/systeminfo.php:/home/pi/pialert/front/systeminfo.php - ${DEV_LOCATION}/front/systeminfo.php:/home/pi/pialert/front/systeminfo.php
- ${DEV_LOCATION}/front/report.php:/home/pi/pialert/front/report.php - ${DEV_LOCATION}/front/report.php:/home/pi/pialert/front/report.php
- ${DEV_LOCATION}/front/flows.php:/home/pi/pialert/front/flows.php - ${DEV_LOCATION}/front/workflows.php:/home/pi/pialert/front/workflows.php
- ${DEV_LOCATION}/front/appEventsCore.php:/home/pi/pialert/front/appEventsCore.php
- ${DEV_LOCATION}/front/donations.php:/home/pi/pialert/front/donations.php - ${DEV_LOCATION}/front/donations.php:/home/pi/pialert/front/donations.php
- ${DEV_LOCATION}/front/plugins:/home/pi/pialert/front/plugins - ${DEV_LOCATION}/front/plugins:/home/pi/pialert/front/plugins
# DELETE END anyone trying to use this file: comment out / delete ABOVE lines, they are only for development purposes # DELETE END anyone trying to use this file: comment out / delete ABOVE lines, they are only for development purposes

View File

@@ -1,6 +1,6 @@
## How to setup your Network page ## How to setup your Network page
Make sure you have a root device with the MAC `Internet` (No other MAC addresses are currently supported as the root node). Make sure you have a root device with the MAC `Internet` (No other MAC addresses are currently supported as the root node) set to a network device type (e.g.: **Type**:`Router`).
> 💡 Tip: You can add dummy devices via the [Undiscoverables plugin](https://github.com/jokob-sk/Pi.Alert/blob/main/front/plugins/undiscoverables/README.md) > 💡 Tip: You can add dummy devices via the [Undiscoverables plugin](https://github.com/jokob-sk/Pi.Alert/blob/main/front/plugins/undiscoverables/README.md)

86
front/appEventsCore.php Executable file
View File

@@ -0,0 +1,86 @@
<section class="content">
<div class="nav-tabs-custom app-event-content" style="margin-bottom: 0px;">
<ul id="tabs-location" class="nav nav-tabs col-sm-2">
<li class="left-nav"><a class="col-sm-12" href="#" id="" data-toggle="tab">Events</a></li>
</ul>
<div id="tabs-content-location" class="tab-content col-sm-10">
<table class="table table-striped" id="appevents-table" data-my-dbtable="AppEvents"></table>
</div>
</div>
</section>
<script>
$(document).ready(function() {
// Load JSON data from the provided URL
$.getJSON('/api/table_appevents.json', function(data) {
// Process the JSON data and generate UI dynamically
processData(data)
});
});
function processData(data) {
// Create an object to store unique ObjectType values as app event identifiers
var appEventIdentifiers = {};
// Array to accumulate data for DataTable
var allData = [];
// Iterate through the data and generate tabs and content dynamically
$.each(data.data, function(index, item) {
// Accumulate data for DataTable
allData.push(item);
});
// Initialize DataTable for all app events
$('#appevents-table').DataTable({
data: allData,
paging: true,
lengthChange: true,
lengthMenu: [[10, 25, 50, 100, 500, -1], [10, 25, 50, 100, 500, 'All']],
searching: true,
ordering: true,
info: true,
autoWidth: false,
pageLength: 25, // Set the default paging to 25
columns: [
{ data: 'DateTimeCreated', title: getString('AppEvents_DateTimeCreated') },
{ data: 'AppEventType', title: getString('AppEvents_Type') },
{ data: 'ObjectType', title: getString('AppEvents_ObjectType') },
{ data: 'ObjectMAC', title: getString('AppEvents_ObjectMAC') },
{ data: 'ObjectIP', title: getString('AppEvents_ObjectIP') },
{ data: 'ObjectStatus', title: getString('AppEvents_ObjectStatus') },
{ data: 'Extra', title: getString('AppEvents_Extra') },
// Add other columns as needed
],
// Add column-specific configurations if needed
columnDefs: [
{ className: 'text-center', targets: [3] },
{ width: '80px', targets: [6] },
// ... Add other columnDefs as needed
// Full MAC
{targets: [3],
'createdCell': function (td, cellData, rowData, row, col) {
if (!emptyArr.includes(cellData)){
$(td).html (createDeviceLink(cellData));
} else {
$(td).html ('');
}
} },
]
});
// Activate the first tab
$('#tabs-location li:first-child').addClass('active');
$('#tabs-content-location .tab-pane:first-child').addClass('active');
}
</script>
<!-- Datatable -->
<link rel="stylesheet" href="lib/AdminLTE/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css"/>
<script src="lib/AdminLTE/bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
<script src="lib/AdminLTE/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>

View File

@@ -1475,7 +1475,7 @@ function updateApi()
{ {
// value has to be in format event|param. e.g. run|ARPSCAN // value has to be in format event|param. e.g. run|ARPSCAN
action = `update_api|devices` action = `update_api|devices,appevents`
$.ajax({ $.ajax({
method: "POST", method: "POST",

View File

@@ -418,6 +418,14 @@ function saveData(functionName, id, value) {
} }
// -----------------------------------------------------------------------------
// create a link to the device
function createDeviceLink(mac)
{
return `<span class="anonymizeMac"><a href="/deviceDetails.php?mac=${mac}" target="_blank">${getNameByMacAddress(mac)}</a><span>`
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// remove an item from an array // remove an item from an array
function removeItemFromArray(arr, value) { function removeItemFromArray(arr, value) {

View File

@@ -252,9 +252,9 @@ if ($ENABLED_DARKMODE === True) {
<li class=" <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('settings.php') ) ){ echo 'active'; } ?>"> <li class=" <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('settings.php') ) ){ echo 'active'; } ?>">
<a href="settings.php"><i class="fa fa-cog"></i> <span><?= lang('Navigation_Settings');?></span></a> <a href="settings.php"><i class="fa fa-cog"></i> <span><?= lang('Navigation_Settings');?></span></a>
</li> </li>
<!-- <li class=" <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('flows.php') ) ){ echo 'active'; } ?>"> <li class=" <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('flows.php') ) ){ echo 'active'; } ?>">
<a href="flows.php"><i class="fa fa-shuffle"></i> <span><?= lang('Navigation_Flows');?></span></a> <a href="workflows.php"><i class="fa fa-shuffle"></i> <span><?= lang('Navigation_Workflows');?></span></a>
</li> --> </li>
<li class=" <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('systeminfo.php') ) ){ echo 'active'; } ?>"> <li class=" <?php if (in_array (basename($_SERVER['SCRIPT_NAME']), array('systeminfo.php') ) ){ echo 'active'; } ?>">
<a href="systeminfo.php"><i class="fa fa-microchip"></i> <span><?= lang('Navigation_SystemInfo');?></span></a> <a href="systeminfo.php"><i class="fa fa-microchip"></i> <span><?= lang('Navigation_SystemInfo');?></span></a>
</li> </li>

View File

@@ -3,6 +3,25 @@
"About_Title": "Open Source Network Guard", "About_Title": "Open Source Network Guard",
"About_Design" : "Designed for:", "About_Design" : "Designed for:",
"About_Exit" : "Sign out", "About_Exit" : "Sign out",
"AppEvents_GUID" : "Application Event GUID",
"AppEvents_DateTimeCreated" : "Logged",
"AppEvents_ObjectType" : "Object Type",
"AppEvents_ObjectPlugin" : "Linked Plugin",
"AppEvents_ObjectMAC" : "Linked MAC (at log time)",
"AppEvents_ObjectIP" : "Linked IP (at log time)",
"AppEvents_ObjectPrimaryID" : "Primary ID",
"AppEvents_ObjectSecondaryID" : "Secondary ID",
"AppEvents_ObjectForeignKey" : "Foreign Key",
"AppEvents_ObjectIndex" : "Index",
"AppEvents_ObjectIsNew" : "Is new (at log time)",
"AppEvents_ObjectIsArchived" : "Is archived (at log time)",
"AppEvents_ObjectStatusColumn" : "Status column",
"AppEvents_ObjectStatus" : "Status (at log time)",
"AppEvents_Type" : "Type",
"AppEvents_Helper1" : "Helper 1",
"AppEvents_Helper2" : "Helper 2",
"AppEvents_Helper3" : "Helper 3",
"AppEvents_Extra" : "Extra",
"Gen_Delete" : "Delete", "Gen_Delete" : "Delete",
"Gen_DeleteAll" : "Delete all", "Gen_DeleteAll" : "Delete all",
"Gen_Cancel" : "Cancel", "Gen_Cancel" : "Cancel",
@@ -44,7 +63,7 @@
"Navigation_Maintenance" : "Maintenance", "Navigation_Maintenance" : "Maintenance",
"Navigation_Settings" : "Settings", "Navigation_Settings" : "Settings",
"Navigation_SystemInfo" : "System info", "Navigation_SystemInfo" : "System info",
"Navigation_Flows" : "Flows", "Navigation_Workflows" : "Workflows",
"Navigation_HelpFAQ" : "Help / FAQ", "Navigation_HelpFAQ" : "Help / FAQ",
"Navigation_Donations" : "Donations", "Navigation_Donations" : "Donations",
"Device_Title" : "Devices", "Device_Title" : "Devices",

0
front/php/templates/language/fr_fr.json Normal file → Executable file
View File

View File

@@ -188,7 +188,7 @@
"description": [ "description": [
{ {
"language_code": "en_us", "language_code": "en_us",
"string": "How many historical entries of Notifications should be kept. This influences how mane entries are also available in the Report section in the UI" "string": "How many historical entries of Notifications should be kept. This influences how many entries are also available in the Report section in the UI"
} }
] ]
} }

View File

@@ -66,17 +66,20 @@ def cleanup_database (dbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP
conn = sqlite3.connect(dbPath) conn = sqlite3.connect(dbPath)
cursor = conn.cursor() cursor = conn.cursor()
# -----------------------------------------------------
# Cleanup Online History # Cleanup Online History
mylog('verbose', [f'[{pluginName}] Online_History: Delete all but keep latest 150 entries']) mylog('verbose', [f'[{pluginName}] Online_History: Delete all but keep latest 150 entries'])
cursor.execute ("""DELETE from Online_History where "Index" not in ( cursor.execute ("""DELETE from Online_History where "Index" not in (
SELECT "Index" from Online_History SELECT "Index" from Online_History
order by Scan_Date desc limit 150)""") order by Scan_Date desc limit 150)""")
mylog('verbose', [f'[{pluginName}] Optimize Database'])
# -----------------------------------------------------
# Cleanup Events # Cleanup Events
mylog('verbose', [f'[{pluginName}] Events: Delete all older than {str(DAYS_TO_KEEP_EVENTS)} days (DAYS_TO_KEEP_EVENTS setting)']) mylog('verbose', [f'[{pluginName}] Events: Delete all older than {str(DAYS_TO_KEEP_EVENTS)} days (DAYS_TO_KEEP_EVENTS setting)'])
cursor.execute (f"""DELETE FROM Events cursor.execute (f"""DELETE FROM Events
WHERE eve_DateTime <= date('now', '-{str(DAYS_TO_KEEP_EVENTS)} day')""") WHERE eve_DateTime <= date('now', '-{str(DAYS_TO_KEEP_EVENTS)} day')""")
# -----------------------------------------------------
# Trim Plugins_History entries to less than PLUGINS_KEEP_HIST setting per unique "Plugin" column entry # Trim Plugins_History entries to less than PLUGINS_KEEP_HIST setting per unique "Plugin" column entry
mylog('verbose', [f'[{pluginName}] Plugins_History: Trim Plugins_History entries to less than {str(PLUGINS_KEEP_HIST)} per Plugin (PLUGINS_KEEP_HIST setting)']) mylog('verbose', [f'[{pluginName}] Plugins_History: Trim Plugins_History entries to less than {str(PLUGINS_KEEP_HIST)} per Plugin (PLUGINS_KEEP_HIST setting)'])
@@ -94,7 +97,7 @@ def cleanup_database (dbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP
cursor.execute(delete_query) cursor.execute(delete_query)
# -----------------------------------------------------
# Trim Notifications entries to less than DBCLNP_NOTIFI_HIST setting # Trim Notifications entries to less than DBCLNP_NOTIFI_HIST setting
histCount = get_setting_value('DBCLNP_NOTIFI_HIST') histCount = get_setting_value('DBCLNP_NOTIFI_HIST')
@@ -115,19 +118,58 @@ def cleanup_database (dbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP
cursor.execute(delete_query) cursor.execute(delete_query)
# Cleanup Pholus_Scan
if PHOLUS_DAYS_DATA != 0: # -----------------------------------------------------
mylog('verbose', [f'[{pluginName}] Pholus_Scan: Delete all older than ' + str(PHOLUS_DAYS_DATA) + ' days (PHOLUS_DAYS_DATA setting)']) # Trim Workflow entries to less than WORKFLOWS_AppEvents_hist setting
# todo: improvement possibility: keep at least N per mac histCount = get_setting_value('WORKFLOWS_AppEvents_hist')
cursor.execute (f"""DELETE FROM Pholus_Scan
WHERE Time <= date('now', '-{str(PHOLUS_DAYS_DATA)} day')""") mylog('verbose', [f'[{pluginName}] Trim AppEvents to less than {histCount}'])
# Build the SQL query to delete entries
delete_query = f"""DELETE FROM AppEvents
WHERE "Index" NOT IN (
SELECT "Index"
FROM (
SELECT "Index",
ROW_NUMBER() OVER(PARTITION BY "AppEvents" ORDER BY DateTimeCreated DESC) AS row_num
FROM AppEvents
) AS ranked_objects
WHERE row_num <= {histCount}
);"""
cursor.execute(delete_query)
# -----------------------------------------------------
# Cleanup New Devices # Cleanup New Devices
if HRS_TO_KEEP_NEWDEV != 0: if HRS_TO_KEEP_NEWDEV != 0:
mylog('verbose', [f'[{pluginName}] Devices: Delete all New Devices older than {str(HRS_TO_KEEP_NEWDEV)} hours (HRS_TO_KEEP_NEWDEV setting)']) mylog('verbose', [f'[{pluginName}] Devices: Delete all New Devices older than {str(HRS_TO_KEEP_NEWDEV)} hours (HRS_TO_KEEP_NEWDEV setting)'])
cursor.execute (f"""DELETE FROM Devices cursor.execute (f"""DELETE FROM Devices
WHERE dev_NewDevice = 1 AND dev_FirstConnection < date('now', '+{str(HRS_TO_KEEP_NEWDEV)} hour')""") WHERE dev_NewDevice = 1 AND dev_FirstConnection < date('now', '+{str(HRS_TO_KEEP_NEWDEV)} hour')""")
# -----------------------------------------------------
# Cleanup Pholus_Scan
if PHOLUS_DAYS_DATA != 0:
mylog('verbose', [f'[{pluginName}] Pholus_Scan: Delete all older than ' + str(PHOLUS_DAYS_DATA) + ' days (PHOLUS_DAYS_DATA setting)'])
# todo: improvement possibility: keep at least N per mac
cursor.execute (f"""DELETE FROM Pholus_Scan
WHERE Time <= date('now', '-{str(PHOLUS_DAYS_DATA)} day')""")
# -----------------------------------------------------
# De-Dupe (de-duplicate - remove duplicate entries) from the Pholus_Scan table
mylog('verbose', [f'[{pluginName}] Pholus_Scan: Delete all duplicates'])
cursor.execute ("""DELETE FROM Pholus_Scan
WHERE rowid > (
SELECT MIN(rowid) FROM Pholus_Scan p2
WHERE Pholus_Scan.MAC = p2.MAC
AND Pholus_Scan.Value = p2.Value
AND Pholus_Scan.Record_Type = p2.Record_Type
);""")
# -----------------------------------------------------
# De-dupe (de-duplicate) from the Plugins_Objects table # De-dupe (de-duplicate) from the Plugins_Objects table
# TODO This shouldn't be necessary - probably a concurrency bug somewhere in the code :( # TODO This shouldn't be necessary - probably a concurrency bug somewhere in the code :(
mylog('verbose', [f'[{pluginName}] Plugins_Objects: Delete all duplicates']) mylog('verbose', [f'[{pluginName}] Plugins_Objects: Delete all duplicates'])
@@ -142,15 +184,6 @@ def cleanup_database (dbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP
) )
""") """)
# De-Dupe (de-duplicate - remove duplicate entries) from the Pholus_Scan table
mylog('verbose', [f'[{pluginName}] Pholus_Scan: Delete all duplicates'])
cursor.execute ("""DELETE FROM Pholus_Scan
WHERE rowid > (
SELECT MIN(rowid) FROM Pholus_Scan p2
WHERE Pholus_Scan.MAC = p2.MAC
AND Pholus_Scan.Value = p2.Value
AND Pholus_Scan.Record_Type = p2.Record_Type
);""")
conn.commit() conn.commit()

View File

@@ -0,0 +1,7 @@
## Overview
TBC
### Usage
- Check the Settings page for details.

View File

@@ -0,0 +1,57 @@
{
"code_name": "workflows",
"unique_prefix": "WORKFLOWS",
"plugin_type": "system",
"enabled": true,
"data_source": "script",
"show_ui": false,
"localized": ["display_name", "description", "icon"],
"display_name": [
{
"language_code": "en_us",
"string": "Workflows"
}
],
"icon": [
{
"language_code": "en_us",
"string": "<i class=\"fa-solid fa-shuffle\"></i>"
}
],
"description": [
{
"language_code": "en_us",
"string": "A plugin to adjust behavior of workflows."
}
],
"params" : [
],
"settings": [
{
"function": "AppEvents_hist",
"type": "integer",
"default_value": 10000,
"options": [],
"localized": ["name", "description"],
"name": [
{
"language_code": "en_us",
"string": "App Events History"
}
],
"description": [
{
"language_code": "en_us",
"string": "How many historical entries of Application Events should be kept. This influences how many entries are also available in the Workflows section in the UI."
}
]
}
],
"database_column_definitions":
[
]
}

View File

@@ -123,7 +123,7 @@ function processColumnValue(dbColumnDef, value, index, type) {
<span>`; <span>`;
break; break;
case 'device_name_mac': case 'device_name_mac':
value = `<span class="anonymizeMac"><a href="/deviceDetails.php?mac=${value}" target="_blank">${getNameByMacAddress(value)}</a><span>`; value = createDeviceLink(value);
break; break;
case 'device_mac': case 'device_mac':
value = `<span class="anonymizeMac"><a href="/deviceDetails.php?mac=${value}" target="_blank">${value}</a><span>`; value = `<span class="anonymizeMac"><a href="/deviceDetails.php?mac=${value}" target="_blank">${value}</a><span>`;

View File

@@ -13,14 +13,14 @@
<section class="content-header"> <section class="content-header">
<h1 id="pageTitle"> <h1 id="pageTitle">
<i class="fa fa-fw fa-plug"></i> <?= lang('Navigation_Flows');?> <i class="fa fa-fw fa-plug"></i> <?= lang('Navigation_Workflows');?>
<span class="pageHelp"> <a target="_blank" href="https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins"><i class="fa fa-circle-question"></i></a><span> <span class="pageHelp"> <a target="_blank" href="https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins"><i class="fa fa-circle-question"></i></a><span>
</h1> </h1>
</section> </section>
<?php <?php
// require 'pluginsCore.php'; require 'appEventsCore.php';
?> ?>

View File

@@ -3,7 +3,7 @@ import json
# pialert modules # pialert modules
import conf import conf
from const import (apiPath, sql_devices_all, sql_events_pending_alert, sql_settings, sql_plugins_events, sql_plugins_history, sql_plugins_objects,sql_language_strings, sql_notifications_all) from const import (apiPath, sql_appevents, sql_devices_all, sql_events_pending_alert, sql_settings, sql_plugins_events, sql_plugins_history, sql_plugins_objects,sql_language_strings, sql_notifications_all)
from logger import mylog from logger import mylog
from helper import write_file from helper import write_file
@@ -23,6 +23,7 @@ def update_api(db, isNotification = False, updateOnlyDataSources = []):
# prepare database tables we want to expose # prepare database tables we want to expose
dataSourcesSQLs = [ dataSourcesSQLs = [
["appevents", sql_appevents],
["devices", sql_devices_all], ["devices", sql_devices_all],
["events_pending_alert", sql_events_pending_alert], ["events_pending_alert", sql_events_pending_alert],
["settings", sql_settings], ["settings", sql_settings],

View File

@@ -16,6 +16,15 @@ class AppEvent_obj:
def __init__(self, db): def __init__(self, db):
self.db = db self.db = db
# drop table
self.db.sql.execute("""DROP TABLE IF EXISTS "AppEvents" """)
# Drop all triggers
self.db.sql.execute('DROP TRIGGER IF EXISTS trg_create_device;')
self.db.sql.execute('DROP TRIGGER IF EXISTS trg_read_device;')
self.db.sql.execute('DROP TRIGGER IF EXISTS trg_update_device;')
self.db.sql.execute('DROP TRIGGER IF EXISTS trg_delete_device;')
# Create AppEvent table if missing # Create AppEvent table if missing
self.db.sql.execute("""CREATE TABLE IF NOT EXISTS "AppEvents" ( self.db.sql.execute("""CREATE TABLE IF NOT EXISTS "AppEvents" (
"Index" INTEGER, "Index" INTEGER,
@@ -29,18 +38,133 @@ class AppEvent_obj:
"ObjectPrimaryID" TEXT, "ObjectPrimaryID" TEXT,
"ObjectSecondaryID" TEXT, "ObjectSecondaryID" TEXT,
"ObjectForeignKey" TEXT, "ObjectForeignKey" TEXT,
"ObjectIndex" TEXT, "ObjectIndex" TEXT,
"ObjectRowID" TEXT, "ObjectIsNew" BOOLEAN,
"ObjectIsArchived" BOOLEAN,
"ObjectStatusColumn" TEXT, -- Status (Notifications, Plugins), eve_EventType (Events) "ObjectStatusColumn" TEXT, -- Status (Notifications, Plugins), eve_EventType (Events)
"ObjectStatus" TEXT, -- new_devices, down_devices, events, new, watched-changed, watched-not-changed, missing-in-last-scan, Device down, New Device, IP Changed, Connected, Disconnected, VOIDED - Disconnected, VOIDED - Connected, <missing event> "ObjectStatus" TEXT, -- new_devices, down_devices, events, new, watched-changed, watched-not-changed, missing-in-last-scan, Device down, New Device, IP Changed, Connected, Disconnected, VOIDED - Disconnected, VOIDED - Connected, <missing event>
"AppEventStatus" TEXT, -- TBD "new", "used", "cleanup-next" "AppEventType" TEXT, -- "create", "update", "delete" (+TBD)
"Extra" TEXT, "Helper1" TEXT,
"Helper2" TEXT,
"Helper3" TEXT,
"Extra" TEXT,
PRIMARY KEY("Index" AUTOINCREMENT) PRIMARY KEY("Index" AUTOINCREMENT)
); );
""") """)
# Generate a GUID
sql_generateGuid = '''
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))
)
'''
sql_mappedColumns = '''
"GUID",
"DateTimeCreated",
"ObjectType",
"ObjectMAC",
"ObjectIP",
"ObjectStatus",
"ObjectStatusColumn",
"ObjectIsNew",
"ObjectIsArchived",
"ObjectForeignKey",
"AppEventType"
'''
# Trigger for create event
self.db.sql.execute(f'''
CREATE TRIGGER IF NOT EXISTS "trg_create_device"
AFTER INSERT ON "Devices"
BEGIN
INSERT INTO "AppEvents" (
{sql_mappedColumns}
)
VALUES (
-- below generates a GUID
{sql_generateGuid},
DATETIME('now'),
'Devices',
NEW.dev_MAC,
NEW.dev_LastIP,
CASE WHEN NEW.dev_PresentLastScan = 1 THEN 'online' ELSE 'offline' END,
'dev_PresentLastScan',
NEW.dev_NewDevice,
NEW.dev_Archived,
NEW.dev_MAC,
'create'
);
END;
''')
# 🔴 This would generate too many events, disabled for now
# # Trigger for read event
# self.db.sql.execute('''
# TODO
# ''')
# Trigger for update event
self.db.sql.execute(f'''
CREATE TRIGGER IF NOT EXISTS "trg_update_device"
AFTER UPDATE ON "Devices"
BEGIN
INSERT INTO "AppEvents" (
{sql_mappedColumns}
)
VALUES (
-- below generates a GUID
{sql_generateGuid},
DATETIME('now'),
'Devices',
NEW.dev_MAC,
NEW.dev_LastIP,
CASE WHEN NEW.dev_PresentLastScan = 1 THEN 'online' ELSE 'offline' END,
'dev_PresentLastScan',
NEW.dev_NewDevice,
NEW.dev_Archived,
NEW.dev_MAC,
'update'
);
END;
''')
# Trigger for delete event
self.db.sql.execute(f'''
CREATE TRIGGER IF NOT EXISTS "trg_delete_device"
AFTER DELETE ON "Devices"
BEGIN
INSERT INTO "AppEvents" (
{sql_mappedColumns}
)
VALUES (
-- below generates a GUID
{sql_generateGuid},
DATETIME('now'),
'Devices',
OLD.dev_MAC,
OLD.dev_LastIP,
CASE WHEN OLD.dev_PresentLastScan = 1 THEN 'online' ELSE 'offline' END,
'dev_PresentLastScan',
OLD.dev_NewDevice,
OLD.dev_Archived,
OLD.dev_MAC,
'delete'
);
END;
''')
self.save() self.save()
# -------------------------------------------------------------------------------
# -------------------------------------------------------------------------------
# below code is unused
# -------------------------------------------------------------------------------
# Create a new DB entry if new notifications are available, otherwise skip # Create a new DB entry if new notifications are available, otherwise skip
def create(self, Extra="", **kwargs): def create(self, Extra="", **kwargs):
# Check if nothing to report, end # Check if nothing to report, end
@@ -72,11 +196,6 @@ class AppEvent_obj:
return True return True
# Update the status of the entry
def updateStatus(self, newStatus):
self.ObjectStatus = newStatus
self.upsert()
def upsert(self): def upsert(self):
self.db.sql.execute(""" self.db.sql.execute("""
INSERT OR REPLACE INTO AppEvents ( INSERT OR REPLACE INTO AppEvents (

View File

@@ -23,6 +23,7 @@ vendorsPath = '/usr/share/arp-scan/ieee-oui.txt'
# SQL queries # SQL queries
#=============================================================================== #===============================================================================
sql_devices_all = """select rowid, * from Devices""" sql_devices_all = """select rowid, * from Devices"""
sql_appevents = """select * from AppEvents"""
sql_devices_stats = """SELECT Online_Devices as online, Down_Devices as down, All_Devices as 'all', Archived_Devices as archived, sql_devices_stats = """SELECT Online_Devices as online, Down_Devices as down, All_Devices as 'all', Archived_Devices as archived,
(select count(*) from Devices a where dev_NewDevice = 1 ) as new, (select count(*) from Devices a where dev_NewDevice = 1 ) as new,
(select count(*) from Devices a where dev_Name = '(unknown)' or dev_Name = '(name not found)' ) as unknown (select count(*) from Devices a where dev_Name = '(unknown)' or dev_Name = '(name not found)' ) as unknown

View File

@@ -7,6 +7,7 @@ from const import fullDbPath, sql_devices_stats, sql_devices_all
from logger import mylog from logger import mylog
from helper import json_obj, initOrSetParam, row_to_json, timeNowTZ #, updateState from helper import json_obj, initOrSetParam, row_to_json, timeNowTZ #, updateState
from appevent import AppEvent_obj
@@ -83,8 +84,8 @@ class DB():
# indicates, if Online_History table is available # indicates, if Online_History table is available
onlineHistoryAvailable = self.sql.execute(""" onlineHistoryAvailable = self.sql.execute("""
SELECT name FROM sqlite_master WHERE type='table' SELECT name FROM sqlite_master WHERE type='table'
AND name='Online_History'; AND name='Online_History';
""").fetchall() != [] """).fetchall() != []
# Check if it is incompatible (Check if table has all required columns) # Check if it is incompatible (Check if table has all required columns)
@@ -92,8 +93,8 @@ class DB():
if onlineHistoryAvailable : if onlineHistoryAvailable :
isIncompatible = self.sql.execute (""" isIncompatible = self.sql.execute ("""
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Online_History') WHERE name='Archived_Devices' SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Online_History') WHERE name='Archived_Devices'
""").fetchone()[0] == 0 """).fetchone()[0] == 0
# Drop table if available, but incompatible # Drop table if available, but incompatible
if onlineHistoryAvailable and isIncompatible: if onlineHistoryAvailable and isIncompatible:
@@ -119,35 +120,35 @@ class DB():
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# dev_Network_Node_MAC_ADDR column # dev_Network_Node_MAC_ADDR column
dev_Network_Node_MAC_ADDR_missing = self.sql.execute (""" dev_Network_Node_MAC_ADDR_missing = self.sql.execute ("""
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='dev_Network_Node_MAC_ADDR' SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='dev_Network_Node_MAC_ADDR'
""").fetchone()[0] == 0 """).fetchone()[0] == 0
if dev_Network_Node_MAC_ADDR_missing : if dev_Network_Node_MAC_ADDR_missing :
mylog('verbose', ["[upgradeDB] Adding dev_Network_Node_MAC_ADDR to the Devices table"]) mylog('verbose', ["[upgradeDB] Adding dev_Network_Node_MAC_ADDR to the Devices table"])
self.sql.execute(""" self.sql.execute("""
ALTER TABLE "Devices" ADD "dev_Network_Node_MAC_ADDR" TEXT ALTER TABLE "Devices" ADD "dev_Network_Node_MAC_ADDR" TEXT
""") """)
# dev_Network_Node_port column # dev_Network_Node_port column
dev_Network_Node_port_missing = self.sql.execute (""" dev_Network_Node_port_missing = self.sql.execute ("""
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='dev_Network_Node_port' SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='dev_Network_Node_port'
""").fetchone()[0] == 0 """).fetchone()[0] == 0
if dev_Network_Node_port_missing : if dev_Network_Node_port_missing :
mylog('verbose', ["[upgradeDB] Adding dev_Network_Node_port to the Devices table"]) mylog('verbose', ["[upgradeDB] Adding dev_Network_Node_port to the Devices table"])
self.sql.execute(""" self.sql.execute("""
ALTER TABLE "Devices" ADD "dev_Network_Node_port" INTEGER ALTER TABLE "Devices" ADD "dev_Network_Node_port" INTEGER
""") """)
# dev_Icon column # dev_Icon column
dev_Icon_missing = self.sql.execute (""" dev_Icon_missing = self.sql.execute ("""
SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='dev_Icon' SELECT COUNT(*) AS CNTREC FROM pragma_table_info('Devices') WHERE name='dev_Icon'
""").fetchone()[0] == 0 """).fetchone()[0] == 0
if dev_Icon_missing : if dev_Icon_missing :
mylog('verbose', ["[upgradeDB] Adding dev_Icon to the Devices table"]) mylog('verbose', ["[upgradeDB] Adding dev_Icon to the Devices table"])
self.sql.execute(""" self.sql.execute("""
ALTER TABLE "Devices" ADD "dev_Icon" TEXT ALTER TABLE "Devices" ADD "dev_Icon" TEXT
""") """)
@@ -263,61 +264,61 @@ class DB():
# Plugin state # Plugin state
sql_Plugins_Objects = """ CREATE TABLE IF NOT EXISTS Plugins_Objects( sql_Plugins_Objects = """ CREATE TABLE IF NOT EXISTS Plugins_Objects(
"Index" INTEGER, "Index" INTEGER,
Plugin TEXT NOT NULL, Plugin TEXT NOT NULL,
Object_PrimaryID TEXT NOT NULL, Object_PrimaryID TEXT NOT NULL,
Object_SecondaryID TEXT NOT NULL, Object_SecondaryID TEXT NOT NULL,
DateTimeCreated TEXT NOT NULL, DateTimeCreated TEXT NOT NULL,
DateTimeChanged TEXT NOT NULL, DateTimeChanged TEXT NOT NULL,
Watched_Value1 TEXT NOT NULL, Watched_Value1 TEXT NOT NULL,
Watched_Value2 TEXT NOT NULL, Watched_Value2 TEXT NOT NULL,
Watched_Value3 TEXT NOT NULL, Watched_Value3 TEXT NOT NULL,
Watched_Value4 TEXT NOT NULL, Watched_Value4 TEXT NOT NULL,
Status TEXT NOT NULL, Status TEXT NOT NULL,
Extra TEXT NOT NULL, Extra TEXT NOT NULL,
UserData TEXT NOT NULL, UserData TEXT NOT NULL,
ForeignKey TEXT NOT NULL, ForeignKey TEXT NOT NULL,
PRIMARY KEY("Index" AUTOINCREMENT) PRIMARY KEY("Index" AUTOINCREMENT)
); """ ); """
self.sql.execute(sql_Plugins_Objects) self.sql.execute(sql_Plugins_Objects)
# Plugin execution results # Plugin execution results
sql_Plugins_Events = """ CREATE TABLE IF NOT EXISTS Plugins_Events( sql_Plugins_Events = """ CREATE TABLE IF NOT EXISTS Plugins_Events(
"Index" INTEGER, "Index" INTEGER,
Plugin TEXT NOT NULL, Plugin TEXT NOT NULL,
Object_PrimaryID TEXT NOT NULL, Object_PrimaryID TEXT NOT NULL,
Object_SecondaryID TEXT NOT NULL, Object_SecondaryID TEXT NOT NULL,
DateTimeCreated TEXT NOT NULL, DateTimeCreated TEXT NOT NULL,
DateTimeChanged TEXT NOT NULL, DateTimeChanged TEXT NOT NULL,
Watched_Value1 TEXT NOT NULL, Watched_Value1 TEXT NOT NULL,
Watched_Value2 TEXT NOT NULL, Watched_Value2 TEXT NOT NULL,
Watched_Value3 TEXT NOT NULL, Watched_Value3 TEXT NOT NULL,
Watched_Value4 TEXT NOT NULL, Watched_Value4 TEXT NOT NULL,
Status TEXT NOT NULL, Status TEXT NOT NULL,
Extra TEXT NOT NULL, Extra TEXT NOT NULL,
UserData TEXT NOT NULL, UserData TEXT NOT NULL,
ForeignKey TEXT NOT NULL, ForeignKey TEXT NOT NULL,
PRIMARY KEY("Index" AUTOINCREMENT) PRIMARY KEY("Index" AUTOINCREMENT)
); """ ); """
self.sql.execute(sql_Plugins_Events) self.sql.execute(sql_Plugins_Events)
# Plugin execution history # Plugin execution history
sql_Plugins_History = """ CREATE TABLE IF NOT EXISTS Plugins_History( sql_Plugins_History = """ CREATE TABLE IF NOT EXISTS Plugins_History(
"Index" INTEGER, "Index" INTEGER,
Plugin TEXT NOT NULL, Plugin TEXT NOT NULL,
Object_PrimaryID TEXT NOT NULL, Object_PrimaryID TEXT NOT NULL,
Object_SecondaryID TEXT NOT NULL, Object_SecondaryID TEXT NOT NULL,
DateTimeCreated TEXT NOT NULL, DateTimeCreated TEXT NOT NULL,
DateTimeChanged TEXT NOT NULL, DateTimeChanged TEXT NOT NULL,
Watched_Value1 TEXT NOT NULL, Watched_Value1 TEXT NOT NULL,
Watched_Value2 TEXT NOT NULL, Watched_Value2 TEXT NOT NULL,
Watched_Value3 TEXT NOT NULL, Watched_Value3 TEXT NOT NULL,
Watched_Value4 TEXT NOT NULL, Watched_Value4 TEXT NOT NULL,
Status TEXT NOT NULL, Status TEXT NOT NULL,
Extra TEXT NOT NULL, Extra TEXT NOT NULL,
UserData TEXT NOT NULL, UserData TEXT NOT NULL,
ForeignKey TEXT NOT NULL, ForeignKey TEXT NOT NULL,
PRIMARY KEY("Index" AUTOINCREMENT) PRIMARY KEY("Index" AUTOINCREMENT)
); """ ); """
self.sql.execute(sql_Plugins_History) self.sql.execute(sql_Plugins_History)
@@ -328,12 +329,12 @@ class DB():
# Dynamically generated language strings # Dynamically generated language strings
self.sql.execute("DROP TABLE IF EXISTS Plugins_Language_Strings;") self.sql.execute("DROP TABLE IF EXISTS Plugins_Language_Strings;")
self.sql.execute(""" CREATE TABLE IF NOT EXISTS Plugins_Language_Strings( self.sql.execute(""" CREATE TABLE IF NOT EXISTS Plugins_Language_Strings(
"Index" INTEGER, "Index" INTEGER,
Language_Code TEXT NOT NULL, Language_Code TEXT NOT NULL,
String_Key TEXT NOT NULL, String_Key TEXT NOT NULL,
String_Value TEXT NOT NULL, String_Value TEXT NOT NULL,
Extra TEXT NOT NULL, Extra TEXT NOT NULL,
PRIMARY KEY("Index" AUTOINCREMENT) PRIMARY KEY("Index" AUTOINCREMENT)
); """) ); """)
self.commitDB() self.commitDB()
@@ -355,6 +356,9 @@ class DB():
); );
""") """)
# Init the AppEvent database table
AppEvent_obj(self)
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# DELETING OBSOLETE TABLES - to remove with updated db file after 1/1/2024 # DELETING OBSOLETE TABLES - to remove with updated db file after 1/1/2024
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------

View File

@@ -194,6 +194,8 @@ def create_new_devices (db):
'{get_setting_value('NEWDEV_dev_Icon')}' '{get_setting_value('NEWDEV_dev_Icon')}'
""" """
# Bulk-inserting devices from the CurrentScan table as new devices in the table Devices ...
# ... with new device defaults and ignoring specidfied IPs and MACs)
sqlQuery = f"""INSERT OR IGNORE INTO Devices (dev_MAC, dev_name, dev_Vendor, sqlQuery = f"""INSERT OR IGNORE INTO Devices (dev_MAC, dev_name, dev_Vendor,
dev_LastIP, dev_FirstConnection, dev_LastConnection, dev_LastIP, dev_FirstConnection, dev_LastConnection,
{newDevColumns}) {newDevColumns})

View File

@@ -374,7 +374,7 @@ def execute_plugin(db, plugin, pluginsState = plugins_state() ):
pluginsState = process_plugin_events(db, plugin, pluginsState, sqlParams) pluginsState = process_plugin_events(db, plugin, pluginsState, sqlParams)
# update API endpoints # update API endpoints
update_api(db, False, ["plugins_events","plugins_objects", "plugins_history"]) update_api(db, False, ["plugins_events","plugins_objects", "plugins_history", "appevents"])
return pluginsState return pluginsState