68 lines
2.6 KiB
Python
68 lines
2.6 KiB
Python
# Copyright (c) 2026 Patrick Motsch
|
|
# All rights reserved.
|
|
"""Workflow action: update a single Redmine ticket and refresh the mirror."""
|
|
|
|
import logging
|
|
from typing import Any, Dict
|
|
|
|
from modules.datamodels.datamodelChat import ActionResult
|
|
from modules.features.redmine.datamodelRedmine import RedmineTicketUpdateRequest
|
|
from modules.features.redmine.serviceRedmine import updateTicket
|
|
|
|
from ._shared import resolveInstanceContext, ticketToDict
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
async def updateTicketAction(self, parameters: Dict[str, Any]) -> ActionResult:
|
|
"""Update ``parameters['ticketId']`` with the given fields.
|
|
|
|
Only fields that are not ``None`` (and different from the current
|
|
Redmine state, enforced by the service) are sent to Redmine. An
|
|
optional ``notes`` string is appended as a journal entry.
|
|
"""
|
|
try:
|
|
user, mandateId, featureInstanceId = resolveInstanceContext(self.services, parameters)
|
|
except ValueError as exc:
|
|
return ActionResult.isFailure(error=str(exc))
|
|
|
|
raw_id = parameters.get("ticketId") or parameters.get("issueId")
|
|
if raw_id is None:
|
|
return ActionResult.isFailure(error="ticketId is required")
|
|
try:
|
|
ticketId = int(raw_id)
|
|
except (TypeError, ValueError):
|
|
return ActionResult.isFailure(error=f"ticketId must be an int, got {raw_id!r}")
|
|
|
|
try:
|
|
update = RedmineTicketUpdateRequest(
|
|
subject=parameters.get("subject"),
|
|
description=parameters.get("description"),
|
|
trackerId=_optInt(parameters.get("trackerId")),
|
|
statusId=_optInt(parameters.get("statusId")),
|
|
priorityId=_optInt(parameters.get("priorityId")),
|
|
assignedToId=_optInt(parameters.get("assignedToId")),
|
|
parentIssueId=_optInt(parameters.get("parentIssueId")),
|
|
fixedVersionId=_optInt(parameters.get("fixedVersionId")),
|
|
notes=parameters.get("notes"),
|
|
customFields=parameters.get("customFields") or None,
|
|
)
|
|
except Exception as exc:
|
|
return ActionResult.isFailure(error=f"Invalid update body: {exc}")
|
|
|
|
try:
|
|
updated = await updateTicket(user, mandateId, featureInstanceId, ticketId, update)
|
|
except Exception as exc:
|
|
logger.exception("redmine.updateTicket failed for ticket %s", ticketId)
|
|
return ActionResult.isFailure(error=f"Update ticket failed: {exc}")
|
|
|
|
return ActionResult.isSuccess(data={"ticket": ticketToDict(updated)})
|
|
|
|
|
|
def _optInt(value: Any):
|
|
if value is None or value == "":
|
|
return None
|
|
try:
|
|
return int(value)
|
|
except (TypeError, ValueError):
|
|
return None
|