64 lines
2.2 KiB
Python
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)})
|