Merge branch 'int' of ssh://git.poweron.swiss:2222/PowerOn/platform-core into int
All checks were successful
Deploy Plattform-Core (Int) / test (push) Successful in 1m1s
Deploy Plattform-Core (Int) / deploy (push) Successful in 9s

This commit is contained in:
ValueOn AG 2026-06-04 21:38:37 +02:00
commit f766219d4b
4 changed files with 45 additions and 9 deletions

View file

@ -15,6 +15,15 @@ from modules.connectors.connectorProviderBase import ProviderConnector, ServiceA
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def _connection_uuid(connection: Any) -> str:
"""Resolve UserConnection primary key (tokens are stored by UUID, not reference string)."""
if connection is None:
return ""
if isinstance(connection, dict):
return str(connection.get("id") or "").strip()
return str(getattr(connection, "id", None) or "").strip()
class ConnectorResolver: class ConnectorResolver:
"""Resolves connectionId → ProviderConnector (with fresh token) → ServiceAdapter.""" """Resolves connectionId → ProviderConnector (with fresh token) → ServiceAdapter."""
@ -79,9 +88,16 @@ class ConnectorResolver:
if not providerClass: if not providerClass:
raise ValueError(f"No ProviderConnector registered for authority: {authorityStr}") raise ValueError(f"No ProviderConnector registered for authority: {authorityStr}")
token = self._security.getFreshToken(connectionId) resolved_id = _connection_uuid(connection)
if not resolved_id:
raise ValueError(f"Connection {connectionId} has no id")
token = self._security.getFreshToken(resolved_id)
if not token or not token.tokenAccess: if not token or not token.tokenAccess:
raise ValueError(f"No valid token for connection {connectionId}") raise ValueError(
f"No valid token for connection {resolved_id}"
+ (f" (ref: {connectionId})" if connectionId != resolved_id else "")
)
return providerClass(connection, token.tokenAccess) return providerClass(connection, token.tokenAccess)

View file

@ -78,8 +78,8 @@ CLICKUP_NODES = [
{"name": "page", "type": "int", "required": False, "frontendType": "number", {"name": "page", "type": "int", "required": False, "frontendType": "number",
"description": t("Seite"), "default": 0}, "description": t("Seite"), "default": 0},
{"name": "listId", "type": "str", "required": False, "frontendType": "clickupList", {"name": "listId", "type": "str", "required": False, "frontendType": "clickupList",
"frontendOptions": {"dependsOn": "connectionReference"}, "frontendOptions": {"dependsOn": "connectionReference", "patchTeamId": True},
"description": t("In dieser Liste suchen")}, "description": t("Liste (optional — schränkt die Suche ein)")},
{"name": "includeClosed", "type": "bool", "required": False, "frontendType": "checkbox", {"name": "includeClosed", "type": "bool", "required": False, "frontendType": "checkbox",
"description": t("Erledigte einbeziehen"), "default": False}, "description": t("Erledigte einbeziehen"), "default": False},
{"name": "fullTaskData", "type": "bool", "required": False, "frontendType": "checkbox", {"name": "fullTaskData", "type": "bool", "required": False, "frontendType": "checkbox",
@ -106,7 +106,7 @@ CLICKUP_NODES = [
"description": t("ClickUp-Verbindung")}, "description": t("ClickUp-Verbindung")},
{"name": "pathQuery", "type": "str", "required": True, "frontendType": "clickupList", {"name": "pathQuery", "type": "str", "required": True, "frontendType": "clickupList",
"frontendOptions": {"dependsOn": "connectionReference"}, "frontendOptions": {"dependsOn": "connectionReference"},
"description": t("Pfad zur Liste")}, "description": t("Liste")},
{"name": "page", "type": "int", "required": False, "frontendType": "number", {"name": "page", "type": "int", "required": False, "frontendType": "number",
"description": t("Seite"), "default": 0}, "description": t("Seite"), "default": 0},
{"name": "includeClosed", "type": "bool", "required": False, "frontendType": "checkbox", {"name": "includeClosed", "type": "bool", "required": False, "frontendType": "checkbox",
@ -151,11 +151,9 @@ CLICKUP_NODES = [
{"name": "connectionReference", "type": "str", "required": True, "frontendType": "userConnection", {"name": "connectionReference", "type": "str", "required": True, "frontendType": "userConnection",
"frontendOptions": {"authority": "clickup"}, "frontendOptions": {"authority": "clickup"},
"description": t("ClickUp-Verbindung")}, "description": t("ClickUp-Verbindung")},
{"name": "pathQuery", "type": "str", "required": False, "frontendType": "clickupList", {"name": "pathQuery", "type": "str", "required": True, "frontendType": "clickupList",
"frontendOptions": {"dependsOn": "connectionReference"}, "frontendOptions": {"dependsOn": "connectionReference"},
"description": t("Pfad zur Liste")}, "description": t("Liste")},
{"name": "listId", "type": "str", "required": False, "frontendType": "text",
"description": t("Listen-ID")},
{"name": "name", "type": "str", "required": True, "frontendType": "text", {"name": "name", "type": "str", "required": True, "frontendType": "text",
"description": t("Name")}, "description": t("Name")},
{"name": "description", "type": "str", "required": False, "frontendType": "textarea", {"name": "description", "type": "str", "required": False, "frontendType": "textarea",

View file

@ -29,7 +29,12 @@ router = APIRouter(
def _getUserConnection(interface, connection_id: str, user_id: str) -> Optional[UserConnection]: def _getUserConnection(interface, connection_id: str, user_id: str) -> Optional[UserConnection]:
"""Resolve by UUID or connection:authority:username (same as browse / workflow)."""
try: try:
if hasattr(interface, "getUserConnectionById"):
conn = interface.getUserConnectionById(connection_id)
if conn is not None:
return conn
connections = interface.getUserConnections(user_id) connections = interface.getUserConnections(user_id)
for conn in connections: for conn in connections:
if conn.id == connection_id: if conn.id == connection_id:

View file

@ -0,0 +1,17 @@
# Copyright (c) 2025 Patrick Motsch
from types import SimpleNamespace
from modules.connectors.connectorResolver import _connection_uuid
def test_connection_uuid_from_model():
conn = SimpleNamespace(id="uuid-123")
assert _connection_uuid(conn) == "uuid-123"
def test_connection_uuid_from_dict():
assert _connection_uuid({"id": "uuid-456"}) == "uuid-456"
def test_connection_uuid_from_reference_string_returns_empty():
assert _connection_uuid("connection:clickup:Stephan Schellworth") == ""