gateway/modules/workflows/methods/methodRedmine/actions/getStats.py
2026-04-21 21:30:11 +02:00

64 lines
2.2 KiB
Python

# Copyright (c) 2026 Patrick Motsch
# All rights reserved.
"""Workflow action: fetch aggregated Redmine statistics from the mirror."""
import logging
from typing import Any, Dict, List, Optional
from modules.datamodels.datamodelChat import ActionResult
from modules.features.redmine.serviceRedmineStats import getStats
from ._shared import resolveInstanceContext
logger = logging.getLogger(__name__)
def _normalizeIntList(value: Any) -> Optional[List[int]]:
"""Accept ``None | int | "1,2,3" | [..]`` and return a list of ints."""
if value is None or value == "":
return None
if isinstance(value, int):
return [value]
if isinstance(value, str):
value = [v.strip() for v in value.split(",") if v.strip()]
if isinstance(value, list):
ids: List[int] = []
for v in value:
try:
ids.append(int(v))
except (TypeError, ValueError):
continue
return ids or None
return None
async def getStatsAction(self, parameters: Dict[str, Any]) -> ActionResult:
"""Return the same DTO as the ``/stats`` endpoint, cached per filter."""
try:
user, mandateId, featureInstanceId = resolveInstanceContext(self.services, parameters)
except ValueError as exc:
return ActionResult.isFailure(error=str(exc))
bucket = (parameters.get("bucket") or "week").lower()
if bucket not in {"day", "week", "month"}:
bucket = "week"
status_filter = (parameters.get("statusFilter") or "*").lower()
if status_filter not in {"*", "open", "closed"}:
status_filter = "*"
try:
stats = await getStats(
user, mandateId, featureInstanceId,
dateFrom=parameters.get("dateFrom") or None,
dateTo=parameters.get("dateTo") or None,
bucket=bucket,
trackerIds=_normalizeIntList(parameters.get("trackerIds")),
categoryIds=_normalizeIntList(parameters.get("categoryIds")),
statusFilter=status_filter,
)
except Exception as exc:
logger.exception("redmine.getStats failed")
return ActionResult.isFailure(error=f"Stats failed: {exc}")
return ActionResult.isSuccess(data={"stats": stats.model_dump(exclude_none=True)})