mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-04-15 22:51:37 -07:00
BE+FE: refactor timezone UTC #1506
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
This commit is contained in:
@@ -116,7 +116,7 @@ function initializeEventsDatatable (eventsRows) {
|
||||
{
|
||||
targets: [0],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
$(td).html(translateHTMLcodes(localizeTimestamp(cellData)));
|
||||
$(td).html(translateHTMLcodes((cellData)));
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -447,6 +447,7 @@ function localizeTimestamp(input) {
|
||||
return formatSafe(input, tz);
|
||||
|
||||
function formatSafe(str, tz) {
|
||||
|
||||
// CHECK: Does the input string have timezone information?
|
||||
// - Ends with Z: "2026-02-11T11:37:02Z"
|
||||
// - Has GMT±offset: "Wed Feb 11 2026 12:34:12 GMT+1100 (...)"
|
||||
|
||||
+79
-55
@@ -1,10 +1,6 @@
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Register NetAlertX directories
|
||||
INSTALL_PATH = os.getenv("NETALERTX_APP", "/app")
|
||||
sys.path.extend([f"{INSTALL_PATH}/server"])
|
||||
|
||||
import conf
|
||||
from zoneinfo import ZoneInfo
|
||||
import datetime as dt
|
||||
from logger import mylog # noqa: E402 [flake8 lint suppression]
|
||||
from messaging.in_app import write_notification # noqa: E402 [flake8 lint suppression]
|
||||
|
||||
@@ -574,64 +570,92 @@ def is_timestamps_in_utc(sql) -> bool:
|
||||
|
||||
def migrate_timestamps_to_utc(sql) -> bool:
|
||||
"""
|
||||
Migrate all timestamp columns in the database from local time to UTC.
|
||||
Safely migrate timestamp columns from local time to UTC.
|
||||
|
||||
This function determines if migration is needed based on the VERSION setting:
|
||||
- Fresh installs (no VERSION): Skip migration - timestamps already UTC from timeNowUTC()
|
||||
- Version >= 26.2.6: Skip migration - already using UTC timestamps
|
||||
- Version < 26.2.6: Run migration - convert local timestamps to UTC
|
||||
|
||||
Affected tables:
|
||||
- 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
|
||||
Migration rules (fail-safe):
|
||||
- Default behaviour: RUN migration unless proven safe to skip
|
||||
- Version > 26.2.6 → timestamps already UTC → skip
|
||||
- Missing / unknown / unparsable version → migrate
|
||||
- Migration flag present → skip
|
||||
- Detection says already UTC → skip
|
||||
|
||||
Returns:
|
||||
bool: True if migration completed or wasn't needed, False on error
|
||||
bool: True if migration completed or not needed, False on error
|
||||
"""
|
||||
try:
|
||||
import conf
|
||||
from zoneinfo import ZoneInfo
|
||||
import datetime as dt
|
||||
|
||||
# Check VERSION from Settings table (from previous app run)
|
||||
sql.execute("SELECT setValue FROM Settings WHERE setKey = 'VERSION'")
|
||||
try:
|
||||
# -------------------------------------------------
|
||||
# Check migration flag (idempotency protection)
|
||||
# -------------------------------------------------
|
||||
try:
|
||||
sql.execute("SELECT setValue FROM Settings WHERE setKey='DB_TIMESTAMPS_UTC_MIGRATED'")
|
||||
result = sql.fetchone()
|
||||
if result and str(result[0]) == "1":
|
||||
mylog("verbose", "[db_upgrade] UTC timestamp migration already completed - skipping")
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# -------------------------------------------------
|
||||
# Read previous version
|
||||
# -------------------------------------------------
|
||||
sql.execute("SELECT setValue FROM Settings WHERE setKey='VERSION'")
|
||||
result = sql.fetchone()
|
||||
prev_version = result[0] if result else ""
|
||||
|
||||
# Fresh install: VERSION is empty → timestamps already UTC from timeNowUTC()
|
||||
if not prev_version or prev_version == "" or prev_version == "unknown":
|
||||
mylog("verbose", "[db_upgrade] Fresh install detected - timestamps already in UTC format")
|
||||
mylog("verbose", f"[db_upgrade] Version '{prev_version}' detected.")
|
||||
|
||||
# Default behaviour: migrate unless proven safe
|
||||
should_migrate = True
|
||||
|
||||
# -------------------------------------------------
|
||||
# Version-based safety check
|
||||
# -------------------------------------------------
|
||||
if prev_version and str(prev_version).lower() != "unknown":
|
||||
try:
|
||||
version_parts = prev_version.lstrip('v').split('.')
|
||||
major = int(version_parts[0]) if len(version_parts) > 0 else 0
|
||||
minor = int(version_parts[1]) if len(version_parts) > 1 else 0
|
||||
patch = int(version_parts[2]) if len(version_parts) > 2 else 0
|
||||
|
||||
# UTC timestamps introduced AFTER v26.2.6
|
||||
if (major, minor, patch) > (26, 2, 6):
|
||||
should_migrate = False
|
||||
mylog(
|
||||
"verbose",
|
||||
f"[db_upgrade] Version {prev_version} confirmed UTC timestamps - skipping migration",
|
||||
)
|
||||
|
||||
except (ValueError, IndexError) as e:
|
||||
mylog(
|
||||
"warn",
|
||||
f"[db_upgrade] Could not parse version '{prev_version}': {e} - running migration as safety measure",
|
||||
)
|
||||
else:
|
||||
mylog(
|
||||
"warn",
|
||||
"[db_upgrade] VERSION missing/unknown - running migration as safety measure",
|
||||
)
|
||||
|
||||
# -------------------------------------------------
|
||||
# Detection fallback
|
||||
# -------------------------------------------------
|
||||
if should_migrate:
|
||||
try:
|
||||
if is_timestamps_in_utc(sql):
|
||||
mylog(
|
||||
"verbose",
|
||||
"[db_upgrade] Timestamps appear already UTC - skipping migration",
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
mylog(
|
||||
"warn",
|
||||
f"[db_upgrade] UTC detection failed ({e}) - continuing with migration",
|
||||
)
|
||||
else:
|
||||
return True
|
||||
|
||||
# Parse version - format: "26.2.6" or "v26.2.6"
|
||||
try:
|
||||
version_parts = prev_version.strip('v').split('.')
|
||||
major = int(version_parts[0]) if len(version_parts) > 0 else 0
|
||||
minor = int(version_parts[1]) if len(version_parts) > 1 else 0
|
||||
patch = int(version_parts[2]) if len(version_parts) > 2 else 0
|
||||
|
||||
# UTC timestamps introduced in v26.2.6
|
||||
# If upgrading from 26.2.6 or later, timestamps are already UTC
|
||||
if (major > 26) or (major == 26 and minor > 2) or (major == 26 and minor == 2 and patch >= 6):
|
||||
mylog("verbose", f"[db_upgrade] Version {prev_version} already uses UTC timestamps - skipping migration")
|
||||
return True
|
||||
|
||||
mylog("verbose", f"[db_upgrade] Upgrading from {prev_version} (< v26.2.6) - migrating timestamps to UTC")
|
||||
|
||||
except (ValueError, IndexError) as e:
|
||||
mylog("warn", f"[db_upgrade] Could not parse version '{prev_version}': {e} - checking timestamps")
|
||||
# Fallback: use detection logic
|
||||
if is_timestamps_in_utc(sql):
|
||||
mylog("verbose", "[db_upgrade] Timestamps appear to be in UTC - skipping migration")
|
||||
return True
|
||||
|
||||
# Get timezone offset
|
||||
try:
|
||||
if isinstance(conf.tz, dt.tzinfo):
|
||||
|
||||
@@ -49,6 +49,18 @@ class PluginObjectInstance:
|
||||
"SELECT * FROM Plugins_Objects WHERE Plugin = ?", (plugin,)
|
||||
)
|
||||
|
||||
def getLastNCreatedPerPLugin(self, plugin, entries=1):
|
||||
return self._fetchall(
|
||||
"""
|
||||
SELECT *
|
||||
FROM Plugins_Objects
|
||||
WHERE Plugin = ?
|
||||
ORDER BY DateTimeCreated DESC
|
||||
LIMIT ?
|
||||
""",
|
||||
(plugin, entries),
|
||||
)
|
||||
|
||||
def getByField(self, plugPrefix, matchedColumn, matchedKey, returnFields=None):
|
||||
rows = self._fetchall(
|
||||
f"SELECT * FROM Plugins_Objects WHERE Plugin = ? AND {matchedColumn} = ?",
|
||||
|
||||
Reference in New Issue
Block a user