BE/PLG: TZ timestamp work #1251

Signed-off-by: jokob-sk <jokob.sk@gmail.com>
This commit is contained in:
jokob-sk
2025-11-03 10:19:39 +11:00
parent 4c92a941a8
commit 288427c939
9 changed files with 33 additions and 44 deletions

View File

@@ -14,7 +14,7 @@ INSTALL_PATH="/app"
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
from database import get_temp_db_connection
from helper import is_random_mac, format_date, get_setting_value
from helper import is_random_mac, format_date, get_setting_value, timeNowTZ
from db.db_helper import row_to_json, get_date_from_period
# --------------------------
@@ -30,7 +30,7 @@ def get_device_data(mac):
# Special case for new device
if mac.lower() == "new":
now = datetime.now().strftime("%Y-%m-%d %H:%M")
now = timeNowTZ().astimezone().isoformat()
device_data = {
"devMac": "",
"devName": "",
@@ -78,7 +78,6 @@ def get_device_data(mac):
# Compute period date for sessions/events
period = request.args.get('period', '') # e.g., '7 days', '1 month', etc.
period_date_sql = get_date_from_period(period)
current_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# Fetch device info + computed fields
sql = f"""
@@ -106,7 +105,7 @@ def get_device_data(mac):
AND eve_EventType = 'Device Down') AS devDownAlerts,
(SELECT CAST(MAX(0, SUM(
julianday(IFNULL(ses_DateTimeDisconnection,'{current_date}')) -
julianday(IFNULL(ses_DateTimeDisconnection,'{now}')) -
julianday(CASE WHEN ses_DateTimeConnection < {period_date_sql}
THEN {period_date_sql} ELSE ses_DateTimeConnection END)
) * 24) AS INT)
@@ -186,8 +185,8 @@ def set_device_data(mac, data):
data.get("devSkipRepeated", 0),
data.get("devIsNew", 0),
data.get("devIsArchived", 0),
data.get("devLastConnection", datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
data.get("devFirstConnection", datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
data.get("devLastConnection", timeNowTZ().astimezone().isoformat()),
data.get("devFirstConnection", timeNowTZ().astimezone().isoformat()),
data.get("devLastIP", ""),
data.get("devGUID", ""),
data.get("devCustomProps", ""),

View File

@@ -59,7 +59,7 @@ class app_state_class:
previousState = ""
# Update self
self.lastUpdated = str(timeNowTZ())
self.lastUpdated = str(timeNowTZ().astimezone().isoformat())
if os.path.exists(stateFile):
try:
@@ -107,7 +107,7 @@ class app_state_class:
if pluginsStates is not None:
for plugin, state in pluginsStates.items():
if plugin in self.pluginsStates:
# Only update existing keys if both are dicts
# Only update existing keys if both are dicts
if isinstance(self.pluginsStates[plugin], dict) and isinstance(state, dict):
self.pluginsStates[plugin].update(state)
else:

View File

@@ -58,25 +58,6 @@ def get_timezone_offset():
# Date and time methods
#-------------------------------------------------------------------------------
# # -------------------------------------------------------------------------------------------
# def format_date(date_str: str) -> str:
# """Format a date string as 'YYYY-MM-DD HH:MM'"""
# dt = datetime.datetime.fromisoformat(date_str) if isinstance(date_str, str) else date_str
# return dt.strftime('%Y-%m-%d %H:%M')
# # -------------------------------------------------------------------------------------------
# def format_date_diff(date1: str, date2: str) -> str:
# """Return difference between two dates formatted as 'Xd HH:MM'"""
# dt1 = datetime.datetime.fromisoformat(date1) if isinstance(date1, str) else date1
# dt2 = datetime.datetime.fromisoformat(date2) if isinstance(date2, str) else date2
# delta = dt2 - dt1
# days = delta.days
# hours, remainder = divmod(delta.seconds, 3600)
# minutes = remainder // 60
# return f"{days}d {hours:02}:{minutes:02}"
# -------------------------------------------------------------------------------------------
def format_date_iso(date1: str) -> str:
"""Return ISO 8601 string for a date or None if empty"""

View File

@@ -93,6 +93,9 @@ class plugin_manager:
# Update plugin states in app_state
current_plugin_state = self.get_plugin_states(prefix) # get latest plugin state
# mylog('debug', f'current_plugin_state: {current_plugin_state}')
updateState(pluginsStates={prefix: current_plugin_state.get(prefix, {})})
# update last run time
@@ -218,6 +221,7 @@ class plugin_manager:
"""
sql = self.db.sql
plugin_states = {}
now_str = timeNowTZ().isoformat()
if plugin_name: # Only compute for single plugin
sql.execute("""
@@ -228,7 +232,7 @@ class plugin_manager:
WHERE Plugin = ?
""", (plugin_name,))
row = sql.fetchone()
last_changed, total_objects, new_objects, state_updated = row if row else ("", 0, 0)
last_changed, total_objects, new_objects = row if row else ("", 0, 0)
new_objects = new_objects or 0 # ensure it's int
changed_objects = total_objects - new_objects
@@ -237,7 +241,7 @@ class plugin_manager:
"totalObjects": total_objects or 0,
"newObjects": new_objects or 0,
"changedObjects": changed_objects or 0,
"stateUpdated": timeNowTZ()
"stateUpdated": now_str
}
# Save in memory
@@ -252,7 +256,7 @@ class plugin_manager:
FROM Plugins_Objects
GROUP BY Plugin
""")
for plugin, last_changed, total_objects, new_objects, state_updated in sql.fetchall():
for plugin, last_changed, total_objects, new_objects in sql.fetchall():
new_objects = new_objects or 0 # ensure it's int
changed_objects = total_objects - new_objects
plugin_states[plugin] = {
@@ -260,7 +264,7 @@ class plugin_manager:
"totalObjects": total_objects or 0,
"newObjects": new_objects or 0,
"changedObjects": changed_objects or 0,
"stateUpdated": timeNowTZ()
"stateUpdated": now_str
}
# Save in memory
@@ -755,7 +759,7 @@ def process_plugin_events(db, plugin, plugEventsArr):
if isMissing:
# if wasn't missing before, mark as changed
if tmpObj.status != "missing-in-last-scan":
tmpObj.changed = timeNowTZ().strftime('%Y-%m-%d %H:%M:%S')
tmpObj.changed = timeNowTZ().astimezone().isoformat()
tmpObj.status = "missing-in-last-scan"
# mylog('debug', [f'[Plugins] Missing from last scan (PrimaryID | SecondaryID): {tmpObj.primaryId} | {tmpObj.secondaryId}'])

View File

@@ -3,6 +3,7 @@ import subprocess
import conf
import os
import re
import datetime
from dateutil import parser
# Register NetAlertX directories
@@ -55,7 +56,7 @@ def exclude_ignored_devices(db):
#-------------------------------------------------------------------------------
def update_devices_data_from_scan (db):
sql = db.sql #TO-DO
startTime = timeNowTZ().strftime('%Y-%m-%d %H:%M:%S')
startTime = timeNowTZ().astimezone().isoformat()
# Update Last Connection
mylog('debug', '[Update Devices] 1 Last Connection')
@@ -528,23 +529,27 @@ def update_devices_names(pm):
# --- Short-circuit if no name-resolution plugin has changed ---
name_plugins = ["DIGSCAN", "NSLOOKUP", "NBTSCAN", "AVAHISCAN"]
# Retrieve last time name resolution was checked (string or datetime)
last_checked_str = pm.name_plugins_checked
last_checked_dt = parser.parse(last_checked_str) if isinstance(last_checked_str, str) else last_checked_str
# Retrieve last time name resolution was checked
last_checked = pm.name_plugins_checked
# Collect valid state update timestamps for name-related plugins
state_times = []
for p in name_plugins:
state_updated = pm.plugin_states.get(p, {}).get("stateUpdated")
if state_updated and state_updated.strip(): # skip empty or None
if state_updated: # skip empty or None
state_times.append(state_updated)
# Determine the latest valid stateUpdated timestamp
latest_state_str = max(state_times, default=None)
latest_state_dt = parser.parse(latest_state_str) if latest_state_str else None
if isinstance(latest_state_str, datetime.datetime):
latest_state = latest_state_str
elif latest_state_str:
latest_state = parser.parse(latest_state_str)
else:
latest_state = None
# Skip if no plugin state changed since last check
if last_checked_dt and latest_state_dt and latest_state_dt <= last_checked_dt:
if last_checked and latest_state and latest_state <= last_checked:
mylog('debug', '[Update Device Name] No relevant name plugin changes since last check — skipping update.')
return