From 20d2bf215fdea22246a5fa7085a3788ce85beccb Mon Sep 17 00:00:00 2001
From: ValueOn AG
Date: Sat, 28 Mar 2026 18:28:35 +0100
Subject: [PATCH] fixes
---
modules/auth/tokenManager.py | 2 +-
.../features/automation2/mainAutomation2.py | 13 +++++++++++
modules/interfaces/interfaceDbApp.py | 13 ++++-------
.../services/serviceChat/mainServiceChat.py | 3 ++-
modules/shared/dbMultiTenantOptimizations.py | 22 +++++++++++++++++++
5 files changed, 42 insertions(+), 11 deletions(-)
diff --git a/modules/auth/tokenManager.py b/modules/auth/tokenManager.py
index 5740a2ac..940de055 100644
--- a/modules/auth/tokenManager.py
+++ b/modules/auth/tokenManager.py
@@ -181,7 +181,7 @@ class TokenManager:
# Only allow a new refresh if at least 10 minutes passed since the token was created/refreshed
try:
nowTs = getUtcTimestamp()
- createdTs = parseTimestamp(oldToken.createdAt, default=0.0)
+ createdTs = parseTimestamp(oldToken.sysCreatedAt, default=0.0)
secondsSinceLastRefresh = nowTs - createdTs
if secondsSinceLastRefresh < 10 * 60:
logger.info(
diff --git a/modules/features/automation2/mainAutomation2.py b/modules/features/automation2/mainAutomation2.py
index 9ec97eca..08038e68 100644
--- a/modules/features/automation2/mainAutomation2.py
+++ b/modules/features/automation2/mainAutomation2.py
@@ -77,6 +77,19 @@ TEMPLATE_ROLES = [
{"context": "DATA", "item": None, "view": True, "read": "m", "create": "m", "update": "m", "delete": "m"},
]
},
+ {
+ "roleLabel": "automation2-admin",
+ "description": {
+ "en": "Automation2 Admin - Full UI and API for the instance; data remains user-scoped (MY)",
+ "de": "Automation2 Admin - Volle UI und API für die Instanz; Daten weiterhin benutzerspezifisch (MY)",
+ "fr": "Administrateur Automation2 - UI et API complets pour l'instance; donnees limitees a l'utilisateur (MY)",
+ },
+ "accessRules": [
+ {"context": "UI", "item": None, "view": True},
+ {"context": "RESOURCE", "item": None, "view": True},
+ {"context": "DATA", "item": None, "view": True, "read": "m", "create": "m", "update": "m", "delete": "m"},
+ ],
+ },
]
diff --git a/modules/interfaces/interfaceDbApp.py b/modules/interfaces/interfaceDbApp.py
index 2a6b0f78..ee1dc379 100644
--- a/modules/interfaces/interfaceDbApp.py
+++ b/modules/interfaces/interfaceDbApp.py
@@ -2858,8 +2858,8 @@ class AppObjects:
# Ensure token has required fields
if not token.id:
token.id = str(uuid.uuid4())
- if not token.createdAt:
- token.createdAt = getUtcTimestamp()
+ if not token.sysCreatedAt:
+ token.sysCreatedAt = getUtcTimestamp()
# If replace_existing is True, delete old access tokens for this user and authority first
if replace_existing:
@@ -2892,12 +2892,7 @@ class AppObjects:
)
# Continue with saving the new token even if deletion fails
- # Convert to dict and ensure all fields are properly set
token_dict = token.model_dump()
- # Ensure userId is set to current user
- # Convert to dict and ensure all fields are properly set
- token_dict = token.model_dump()
- # Ensure userId is set to current user
token_dict["userId"] = self.currentUser.id
# Save to database
@@ -2936,8 +2931,8 @@ class AppObjects:
# Ensure token has required fields
if not token.id:
token.id = str(uuid.uuid4())
- if not token.createdAt:
- token.createdAt = getUtcTimestamp()
+ if not token.sysCreatedAt:
+ token.sysCreatedAt = getUtcTimestamp()
# Convert to dict and ensure all fields are properly set
token_dict = token.model_dump()
diff --git a/modules/serviceCenter/services/serviceChat/mainServiceChat.py b/modules/serviceCenter/services/serviceChat/mainServiceChat.py
index b05b0c64..40769fae 100644
--- a/modules/serviceCenter/services/serviceChat/mainServiceChat.py
+++ b/modules/serviceCenter/services/serviceChat/mainServiceChat.py
@@ -333,7 +333,8 @@ class ChatService:
token_status = "expired"
else:
# Check if this token was recently refreshed (within last 5 minutes)
- time_since_creation = current_time - token.createdAt if hasattr(token, 'createdAt') else 0
+ createdTs = getattr(token, "sysCreatedAt", None)
+ time_since_creation = (current_time - createdTs) if createdTs else 0
if time_since_creation < 300: # 5 minutes
token_status = "valid (refreshed)"
else:
diff --git a/modules/shared/dbMultiTenantOptimizations.py b/modules/shared/dbMultiTenantOptimizations.py
index 95ad6cae..c178c376 100644
--- a/modules/shared/dbMultiTenantOptimizations.py
+++ b/modules/shared/dbMultiTenantOptimizations.py
@@ -21,6 +21,18 @@ from typing import Optional, List
logger = logging.getLogger(__name__)
+def _ensureUamTablesMatchModels(dbConnector) -> None:
+ """Run connector schema sync so sys* columns exist before we CREATE INDEX on them."""
+ if not hasattr(dbConnector, "_ensureTableExists"):
+ return
+ try:
+ from modules.datamodels.datamodelInvitation import Invitation
+
+ dbConnector._ensureTableExists(Invitation)
+ except Exception as e:
+ logger.debug(f"_ensureUamTablesMatchModels: {e}")
+
+
def _getConnection(dbConnector):
"""Get a connection from the DatabaseConnector.
@@ -176,6 +188,11 @@ def applyMultiTenantOptimizations(dbConnector, tables: Optional[List[str]] = Non
except Exception as autoErr:
logger.debug(f"Could not set autocommit: {autoErr}")
+ try:
+ _ensureUamTablesMatchModels(dbConnector)
+ except Exception as preIdxErr:
+ logger.debug(f"Pre-index table ensure: {preIdxErr}")
+
try:
with conn.cursor() as cursor:
# Apply indexes
@@ -214,6 +231,11 @@ def applyIndexesOnly(dbConnector, tables: Optional[List[str]] = None) -> int:
originalAutocommit = conn.autocommit
conn.autocommit = True
+ try:
+ _ensureUamTablesMatchModels(dbConnector)
+ except Exception as preIdxErr:
+ logger.debug(f"Pre-index table ensure: {preIdxErr}")
+
try:
with conn.cursor() as cursor:
return _applyIndexes(cursor, tables)