gateway/modules/workflows/methods/methodJira/methodJira.py
2026-04-25 01:13:01 +02:00

331 lines
16 KiB
Python

# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
import logging
from typing import Dict, Any
from modules.workflows.methods.methodBase import MethodBase
from modules.datamodels.datamodelWorkflowActions import WorkflowActionDefinition, WorkflowActionParameter
from modules.shared.frontendTypes import FrontendType
# Import helpers
from .helpers.adfConverter import AdfConverterHelper
from .helpers.documentParsing import DocumentParsingHelper
# Import actions
from .actions.connectJira import connectJira
from .actions.exportTicketsAsJson import exportTicketsAsJson
from .actions.importTicketsFromJson import importTicketsFromJson
from .actions.mergeTicketData import mergeTicketData
from .actions.parseCsvContent import parseCsvContent
from .actions.parseExcelContent import parseExcelContent
from .actions.createCsvContent import createCsvContent
from .actions.createExcelContent import createExcelContent
logger = logging.getLogger(__name__)
class MethodJira(MethodBase):
"""JIRA operations methods."""
def __init__(self, services):
super().__init__(services)
self.name = "jira"
self.description = "JIRA operations methods"
# Store connections in memory (keyed by connectionId)
self._connections: Dict[str, Any] = {}
# Initialize helper modules
self.adfConverter = AdfConverterHelper(self)
self.documentParsing = DocumentParsingHelper(self)
# RBAC-Integration: Action-Definitionen mit actionId
self._actions = {
"connectJira": WorkflowActionDefinition(
actionId="jira.connectJira",
description="Connect to JIRA instance and create ticket interface",
outputType="ActionResult",
parameters={
"apiUsername": WorkflowActionParameter(
name="apiUsername",
type="str",
frontendType=FrontendType.EMAIL,
required=True,
description="JIRA API username/email"
),
"apiTokenConfigKey": WorkflowActionParameter(
name="apiTokenConfigKey",
type="str",
frontendType=FrontendType.TEXT,
required=True,
description="APP_CONFIG key name for JIRA API token"
),
"apiUrl": WorkflowActionParameter(
name="apiUrl",
type="str",
frontendType=FrontendType.TEXT,
required=True,
description="JIRA instance URL (e.g., https://example.atlassian.net)"
),
"projectCode": WorkflowActionParameter(
name="projectCode",
type="str",
frontendType=FrontendType.TEXT,
required=True,
description="JIRA project code (e.g., DCS)"
),
"issueType": WorkflowActionParameter(
name="issueType",
type="str",
frontendType=FrontendType.TEXT,
required=True,
description="JIRA issue type (e.g., Task)"
),
"taskSyncDefinition": WorkflowActionParameter(
name="taskSyncDefinition",
type="str",
uiHint="textarea",
frontendType=FrontendType.TEXTAREA,
required=True,
description="Field mapping definition as JSON string or dict"
)
},
execute=connectJira.__get__(self, self.__class__)
),
"exportTicketsAsJson": WorkflowActionDefinition(
actionId="jira.exportTicketsAsJson",
description="Export tickets from JIRA as JSON list",
outputType="DocumentList",
parameters={
"connectionId": WorkflowActionParameter(
name="connectionId",
type="str",
frontendType=FrontendType.TEXT,
required=True,
description="Connection ID from connectJira action result"
),
"taskSyncDefinition": WorkflowActionParameter(
name="taskSyncDefinition",
type="str",
frontendType=FrontendType.TEXTAREA,
required=False,
description="Field mapping definition (if not provided, uses stored definition)"
)
},
execute=exportTicketsAsJson.__get__(self, self.__class__)
),
"importTicketsFromJson": WorkflowActionDefinition(
actionId="jira.importTicketsFromJson",
description="Import ticket data from JSON back to JIRA",
outputType="ActionResult",
parameters={
"connectionId": WorkflowActionParameter(
name="connectionId",
type="str",
frontendType=FrontendType.TEXT,
required=True,
description="Connection ID from connectJira action result"
),
"ticketData": WorkflowActionParameter(
name="ticketData",
type="DocumentList",
frontendType=FrontendType.DOCUMENT_REFERENCE,
required=True,
description="Document reference containing ticket data as JSON"
),
"taskSyncDefinition": WorkflowActionParameter(
name="taskSyncDefinition",
type="str",
frontendType=FrontendType.TEXTAREA,
required=False,
description="Field mapping definition (if not provided, uses stored definition)"
)
},
execute=importTicketsFromJson.__get__(self, self.__class__)
),
"mergeTicketData": WorkflowActionDefinition(
actionId="jira.mergeTicketData",
description="Merge JIRA export data with existing SharePoint data",
outputType="DocumentList",
parameters={
"jiraData": WorkflowActionParameter(
name="jiraData",
type="DocumentList",
frontendType=FrontendType.DOCUMENT_REFERENCE,
required=True,
description="Document reference containing JIRA ticket data as JSON array"
),
"existingData": WorkflowActionParameter(
name="existingData",
type="DocumentList",
frontendType=FrontendType.DOCUMENT_REFERENCE,
required=True,
description="Document reference containing existing SharePoint data as JSON array"
),
"taskSyncDefinition": WorkflowActionParameter(
name="taskSyncDefinition",
type="str",
frontendType=FrontendType.TEXTAREA,
required=True,
description="Field mapping definition"
),
"idField": WorkflowActionParameter(
name="idField",
type="str",
frontendType=FrontendType.TEXT,
required=False,
default="ID",
description="Field name to use as ID for merging"
)
},
execute=mergeTicketData.__get__(self, self.__class__)
),
"parseCsvContent": WorkflowActionDefinition(
actionId="jira.parseCsvContent",
description="Parse CSV content with custom headers",
outputType="DocumentList",
parameters={
"csvContent": WorkflowActionParameter(
name="csvContent",
type="DocumentList",
frontendType=FrontendType.DOCUMENT_REFERENCE,
required=True,
description="Document reference containing CSV file content as bytes"
),
"skipRows": WorkflowActionParameter(
name="skipRows",
type="int",
frontendType=FrontendType.NUMBER,
required=False,
default=2,
description="Number of header rows to skip",
validation={"min": 0, "max": 100}
),
"hasCustomHeaders": WorkflowActionParameter(
name="hasCustomHeaders",
type="bool",
frontendType=FrontendType.CHECKBOX,
required=False,
default=True,
description="Whether CSV has custom header rows"
)
},
execute=parseCsvContent.__get__(self, self.__class__)
),
"parseExcelContent": WorkflowActionDefinition(
actionId="jira.parseExcelContent",
description="Parse Excel content with custom headers",
outputType="DocumentList",
parameters={
"excelContent": WorkflowActionParameter(
name="excelContent",
type="DocumentList",
frontendType=FrontendType.DOCUMENT_REFERENCE,
required=True,
description="Document reference containing Excel file content as bytes"
),
"skipRows": WorkflowActionParameter(
name="skipRows",
type="int",
frontendType=FrontendType.NUMBER,
required=False,
default=3,
description="Number of header rows to skip",
validation={"min": 0, "max": 100}
),
"hasCustomHeaders": WorkflowActionParameter(
name="hasCustomHeaders",
type="bool",
frontendType=FrontendType.CHECKBOX,
required=False,
default=True,
description="Whether Excel has custom header rows"
)
},
execute=parseExcelContent.__get__(self, self.__class__)
),
"createCsvContent": WorkflowActionDefinition(
actionId="jira.createCsvContent",
description="Create CSV content with custom headers",
outputType="DocumentList",
parameters={
"data": WorkflowActionParameter(
name="data",
type="DocumentList",
frontendType=FrontendType.DOCUMENT_REFERENCE,
required=True,
description="Document reference containing data as JSON (with data field from mergeTicketData)"
),
"headers": WorkflowActionParameter(
name="headers",
type="DocumentList",
frontendType=FrontendType.DOCUMENT_REFERENCE,
required=False,
description="Document reference containing headers JSON (from parseCsvContent/parseExcelContent)"
),
"columns": WorkflowActionParameter(
name="columns",
type="List[str]",
frontendType=FrontendType.MULTISELECT,
required=False,
description="List of column names (if not provided, extracted from taskSyncDefinition or data)"
),
"taskSyncDefinition": WorkflowActionParameter(
name="taskSyncDefinition",
type="str",
frontendType=FrontendType.TEXTAREA,
required=False,
description="Field mapping definition (used to extract column names if columns not provided)"
)
},
execute=createCsvContent.__get__(self, self.__class__)
),
"createExcelContent": WorkflowActionDefinition(
actionId="jira.createExcelContent",
description="Create Excel content with custom headers",
outputType="DocumentList",
parameters={
"data": WorkflowActionParameter(
name="data",
type="DocumentList",
frontendType=FrontendType.DOCUMENT_REFERENCE,
required=True,
description="Document reference containing data as JSON (with data field from mergeTicketData)"
),
"headers": WorkflowActionParameter(
name="headers",
type="DocumentList",
frontendType=FrontendType.DOCUMENT_REFERENCE,
required=False,
description="Document reference containing headers JSON (from parseExcelContent)"
),
"columns": WorkflowActionParameter(
name="columns",
type="List[str]",
frontendType=FrontendType.MULTISELECT,
required=False,
description="List of column names (if not provided, extracted from taskSyncDefinition or data)"
),
"taskSyncDefinition": WorkflowActionParameter(
name="taskSyncDefinition",
type="str",
frontendType=FrontendType.TEXTAREA,
required=False,
description="Field mapping definition (used to extract column names if columns not provided)"
)
},
execute=createExcelContent.__get__(self, self.__class__)
)
}
# Validate actions after definition
self._validateActions()
# Register actions as methods (optional, für direkten Zugriff)
self.connectJira = connectJira.__get__(self, self.__class__)
self.exportTicketsAsJson = exportTicketsAsJson.__get__(self, self.__class__)
self.importTicketsFromJson = importTicketsFromJson.__get__(self, self.__class__)
self.mergeTicketData = mergeTicketData.__get__(self, self.__class__)
self.parseCsvContent = parseCsvContent.__get__(self, self.__class__)
self.parseExcelContent = parseExcelContent.__get__(self, self.__class__)
self.createCsvContent = createCsvContent.__get__(self, self.__class__)
self.createExcelContent = createExcelContent.__get__(self, self.__class__)