38 lines
1.4 KiB
Python
38 lines
1.4 KiB
Python
# Copyright (c) 2026 Patrick Motsch
|
|
# All rights reserved.
|
|
"""Shared helpers for Redmine workflow actions.
|
|
|
|
Keeps each action file focused on the business logic -- parameter
|
|
resolution, services lookup and ActionResult shaping live here.
|
|
"""
|
|
|
|
from typing import Any, Dict, Optional, Tuple
|
|
|
|
|
|
def resolveInstanceContext(services, parameters: Dict[str, Any]) -> Tuple[Any, Optional[str], str]:
|
|
"""Resolve ``(user, mandateId, featureInstanceId)`` for a workflow action.
|
|
|
|
The workflow runtime wires up ``services.user`` / ``services.mandateId``
|
|
/ ``services.featureInstanceId``. The action may override the instance
|
|
explicitly via ``parameters['featureInstanceId']`` so that the same
|
|
workflow template can be reused against different Redmine instances.
|
|
"""
|
|
featureInstanceId = parameters.get("featureInstanceId") or getattr(
|
|
services, "featureInstanceId", None
|
|
)
|
|
if not featureInstanceId:
|
|
raise ValueError("featureInstanceId is required")
|
|
mandateId = getattr(services, "mandateId", None)
|
|
user = getattr(services, "user", None)
|
|
if user is None:
|
|
raise ValueError("services.user is not available")
|
|
return user, mandateId, str(featureInstanceId)
|
|
|
|
|
|
def ticketToDict(ticket) -> Dict[str, Any]:
|
|
"""Compact dict representation for AI consumption -- strips ``raw``."""
|
|
if ticket is None:
|
|
return {}
|
|
payload = ticket.model_dump(exclude_none=True)
|
|
payload.pop("raw", None)
|
|
return payload
|