gateway/modules/workflows/methods/methodOutlook/methodOutlook.py
2026-02-08 00:25:48 +01:00

241 lines
11 KiB
Python

# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
import logging
from datetime import datetime, UTC
from modules.workflows.methods.methodBase import MethodBase
from modules.datamodels.datamodelWorkflowActions import WorkflowActionDefinition, WorkflowActionParameter
from modules.shared.frontendTypes import FrontendType
# Import helpers
from .helpers.connection import ConnectionHelper
from .helpers.emailProcessing import EmailProcessingHelper
from .helpers.folderManagement import FolderManagementHelper
# Import actions
from .actions.readEmails import readEmails
from .actions.searchEmails import searchEmails
from .actions.composeAndDraftEmailWithContext import composeAndDraftEmailWithContext
from .actions.sendDraftEmail import sendDraftEmail
logger = logging.getLogger(__name__)
class MethodOutlook(MethodBase):
"""Outlook method implementation for email operations"""
def __init__(self, services):
"""Initialize the Outlook method"""
super().__init__(services)
self.name = "outlook"
self.description = "Handle Microsoft Outlook email operations"
# Initialize helper modules
self.connection = ConnectionHelper(self)
self.emailProcessing = EmailProcessingHelper(self)
self.folderManagement = FolderManagementHelper(self)
# RBAC-Integration: Action-Definitionen mit actionId
self._actions = {
"readEmails": WorkflowActionDefinition(
actionId="outlook.readEmails",
description="Read emails and metadata from a mailbox folder",
dynamicMode=True,
parameters={
"connectionReference": WorkflowActionParameter(
name="connectionReference",
type="str",
frontendType=FrontendType.USER_CONNECTION,
required=True,
description="Microsoft connection label"
),
"folder": WorkflowActionParameter(
name="folder",
type="str",
frontendType=FrontendType.SELECT,
frontendOptions="outlook.folder",
required=False,
default="Inbox",
description="Folder to read from"
),
"limit": WorkflowActionParameter(
name="limit",
type="int",
frontendType=FrontendType.NUMBER,
required=False,
default=1000,
description="Maximum items to return",
validation={"min": 1, "max": 10000}
),
"filter": WorkflowActionParameter(
name="filter",
type="str",
frontendType=FrontendType.TEXT,
required=False,
description="Sender, query operators, or subject text"
),
"outputMimeType": WorkflowActionParameter(
name="outputMimeType",
type="str",
frontendType=FrontendType.SELECT,
frontendOptions=["application/json", "text/plain", "text/csv"],
required=False,
default="application/json",
description="MIME type for output file"
)
},
execute=readEmails.__get__(self, self.__class__)
),
"searchEmails": WorkflowActionDefinition(
actionId="outlook.searchEmails",
description="Search emails by query and return matching items with metadata",
dynamicMode=True,
parameters={
"connectionReference": WorkflowActionParameter(
name="connectionReference",
type="str",
frontendType=FrontendType.USER_CONNECTION,
required=True,
description="Microsoft connection label"
),
"query": WorkflowActionParameter(
name="query",
type="str",
frontendType=FrontendType.TEXT,
required=True,
description="Search expression"
),
"folder": WorkflowActionParameter(
name="folder",
type="str",
frontendType=FrontendType.SELECT,
frontendOptions="outlook.folder",
required=False,
default="All",
description="Folder scope or All"
),
"limit": WorkflowActionParameter(
name="limit",
type="int",
frontendType=FrontendType.NUMBER,
required=False,
default=1000,
description="Maximum items to return",
validation={"min": 1, "max": 10000}
),
"outputMimeType": WorkflowActionParameter(
name="outputMimeType",
type="str",
frontendType=FrontendType.SELECT,
frontendOptions=["application/json", "text/plain", "text/csv"],
required=False,
default="application/json",
description="MIME type for output file"
)
},
execute=searchEmails.__get__(self, self.__class__)
),
"composeAndDraftEmailWithContext": WorkflowActionDefinition(
actionId="outlook.composeAndDraftEmailWithContext",
description="Compose email content using AI from context and optional documents, then create a draft",
dynamicMode=True,
parameters={
"connectionReference": WorkflowActionParameter(
name="connectionReference",
type="str",
frontendType=FrontendType.USER_CONNECTION,
required=True,
description="Microsoft connection label"
),
"to": WorkflowActionParameter(
name="to",
type="List[str]",
frontendType=FrontendType.MULTISELECT,
required=False,
description="Recipient email addresses (optional for drafts)"
),
"context": WorkflowActionParameter(
name="context",
type="str",
frontendType=FrontendType.TEXTAREA,
required=True,
description="Detailed context for composing the email"
),
"documentList": WorkflowActionParameter(
name="documentList",
type="List[str]",
frontendType=FrontendType.DOCUMENT_REFERENCE,
required=False,
description="Document references for context/attachments"
),
"cc": WorkflowActionParameter(
name="cc",
type="List[str]",
frontendType=FrontendType.MULTISELECT,
required=False,
description="CC recipients"
),
"bcc": WorkflowActionParameter(
name="bcc",
type="List[str]",
frontendType=FrontendType.MULTISELECT,
required=False,
description="BCC recipients"
),
"emailStyle": WorkflowActionParameter(
name="emailStyle",
type="str",
frontendType=FrontendType.SELECT,
frontendOptions=["formal", "casual", "business"],
required=False,
default="business",
description="Email style: formal, casual, or business"
),
"maxLength": WorkflowActionParameter(
name="maxLength",
type="int",
frontendType=FrontendType.NUMBER,
required=False,
default=1000,
description="Maximum length for generated content",
validation={"min": 100, "max": 10000}
)
},
execute=composeAndDraftEmailWithContext.__get__(self, self.__class__)
),
"sendDraftEmail": WorkflowActionDefinition(
actionId="outlook.sendDraftEmail",
description="Send draft email(s) using draft email JSON document(s) from action outlook.composeAndDraftEmailWithContext",
dynamicMode=True,
parameters={
"connectionReference": WorkflowActionParameter(
name="connectionReference",
type="str",
frontendType=FrontendType.USER_CONNECTION,
required=True,
description="Microsoft connection label"
),
"documentList": WorkflowActionParameter(
name="documentList",
type="List[str]",
frontendType=FrontendType.DOCUMENT_REFERENCE,
required=True,
description="Document reference(s) to draft emails in JSON format (outputs from outlook.composeAndDraftEmailWithContext function)"
)
},
execute=sendDraftEmail.__get__(self, self.__class__)
)
}
# Validate actions after definition
self._validateActions()
# Register actions as methods (optional, für direkten Zugriff)
self.readEmails = readEmails.__get__(self, self.__class__)
self.searchEmails = searchEmails.__get__(self, self.__class__)
self.composeAndDraftEmailWithContext = composeAndDraftEmailWithContext.__get__(self, self.__class__)
self.sendDraftEmail = sendDraftEmail.__get__(self, self.__class__)
def _format_timestamp_for_filename(self) -> str:
"""Format current timestamp as YYYYMMDD-hhmmss for filenames."""
return datetime.now(UTC).strftime("%Y%m%d-%H%M%S")