From 03fbe522229637f5bba3b56f1d365a1a96c874b8 Mon Sep 17 00:00:00 2001 From: Lars Kaltefleiter Date: Fri, 22 Nov 2024 15:39:45 +0100 Subject: [PATCH] Add support for Adaptive Cards in webhook integration Introduced a new field "json_format" to handle different message formats, extending the functionality to support Adaptive Cards alongside existing Message Cards. Modified methods to prepare and format payloads and actions based on selected JSON format for Microsoft Teams. format message to markdown --- datamodel.combodo-webhook-integration.xml | 277 ++++++++++++++++-- .../de.dict.combodo-webhook-integration.php | 6 +- .../en.dict.combodo-webhook-integration.php | 4 + 3 files changed, 255 insertions(+), 32 deletions(-) diff --git a/datamodel.combodo-webhook-integration.xml b/datamodel.combodo-webhook-integration.xml index b5e4113..98d0559 100644 --- a/datamodel.combodo-webhook-integration.xml +++ b/datamodel.combodo-webhook-integration.xml @@ -2263,6 +2263,15 @@ protected function ApplyParamsToJson(array $aContextArgs, string $sInputAsJson) true list + + + message_card + adaptive_card + + json_format + message_card + false + yes @@ -2309,6 +2318,31 @@ protected function ApplyParamsToJson(array $aContextArgs, string $sInputAsJson) * @inheritDoc */]]> Get('json_format'); + return match ($sJsonFormat) { + 'message_card' => $this->PreparePayloadMessageCard($aContextArgs), + 'adaptive_card' => $this->PreparePayloadAdaptiveCard($aContextArgs), + default => throw new Exception('Unknown json_format ($sJsonFormat)'), + }; + } +]]> + + + + false + protected + Custom + + 'MessageCard', @@ -2367,6 +2401,152 @@ protected function ApplyParamsToJson(array $aContextArgs, string $sInputAsJson) $aData['potentialAction'] = $aActions; } + return json_encode($aData); + } +]]> + + + + false + protected + Custom + + 'message', + ]; + + // Prepare theme + // - Color + // TODO: Not possible with adaptive card, you only could use accents + // "default", "emphasis", "good", "attention", "warning","accent" + $sContainerStyle = null; + $sThemeColor = MetaModel::ApplyParams($this->Get('theme_color'), $aContextArgs); + if (in_array($sThemeColor, ["default", "emphasis", "good", "attention", "warning","accent"])) { + $sContainerStyle = $sThemeColor; + } + + // - Image + $aImageBlock = null; + $sImageUrl = MetaModel::ApplyParams($this->Get('image_url'), $aContextArgs); + if (strlen($sImageUrl) > 0) { + $aImageBlock = [ + "type" => "Image", + "style" => "person", + "url" => $sImageUrl, + "size" => "small" + ]; + } + + // Prepare title + $aTitleBlock = null; + $sTitle = MetaModel::ApplyParams($this->Get('title'), $aContextArgs); + if (strlen($sTitle) > 0) { + // For summary + $aData['summary'] = $sTitle; + $aTitleBlock = [ + "type" => "TextBlock", + "size" => "Medium", + "weight" => "Bolder", + "text" => $sTitle + ]; + } + + // Prepare message + $aMessageBlock = null; + $sMessage = MetaModel::ApplyParams($this->Get('message'), $aContextArgs); + if (strlen($sMessage) > 0) { + $aMessageBlock = [ + "type" => "TextBlock", + "text" => static::TransformHTMLToMSTeamsMarkup($sMessage), + "wrap" => true + ]; + } + + // Prepare extra attributes + $aFactsBlock = null; + $aFacts = $this->PrepareExtraAttributesForMSTeamsAPI($aContextArgs, 'adaptive_card'); + if(!empty($aFacts)) + { + $aFactsBlock = [ + "type" => "FactSet", + "facts" => $aFacts + ]; + } + + // Prepare items + $aItems = []; + + // Add Header to items + if($aImageBlock) + { + $aItems[] = [ + "type" => "ColumnSet", + "columns" => [ + [ + "type" => "Column", + "items" => [ + $aImageBlock + ] + ], + [ + "type" => "Column", + "items" => [ + $aTitleBlock + ] + ] + ] + ]; + } + else + { + $aItems[] = $aTitleBlock; + } + + // Add Message to items + if($aMessageBlock) + { + $aItems[] = $aMessageBlock; + } + // Add Facts to items + if($aFactsBlock) + { + $aItems[] = $aFactsBlock; + } + + // Prepare action buttons + $aActions = $this->PrepareActionsForMSTeamsAPI($aContextArgs, 'adaptive_card'); + + // Add attachments to data + $aData['attachments'] = [ + [ + 'contentType' => 'application/vnd.microsoft.card.adaptive', + 'content' => [ + 'type' => 'AdaptiveCard', + '$schema'=> 'https://adaptivecards.io/schemas/adaptive-card.json', + 'version' => '1.6', + 'body' => [ + [ + 'type' => 'Container', + 'items' => $aItems, + 'style' => $sContainerStyle ?? 'default' + ] + ], + 'actions' => $aActions + ] + ] + ]; + return json_encode($aData); } ]]> @@ -2377,13 +2557,14 @@ protected function ApplyParamsToJson(array $aContextArgs, string $sInputAsJson) protected Overload-DBObject - object()']; @@ -2401,13 +2582,20 @@ protected function ApplyParamsToJson(array $aContextArgs, string $sInputAsJson) // Prepare facts structure $aFacts = array(); + // Check format in oder to build the appropriate structure + $sLabelKey = match ($sJsonFormat) { + 'message_card' => 'name', + 'adaptive_card' => 'title', + default => throw new Exception('Extra Attributes only supported for format "message_card" or "adaptive_card"'), + }; + foreach($aListItems as $sAttCode) { $oAttDef = MetaModel::GetAttributeDef($sObjClass, $sAttCode); // We have to decode HTML entities as they are added on the value by \AttributeDefinition::GetAsHtml() $sValueAsHtml = utils::HtmlEntityDecode($oObject->GetAsHtml($sAttCode)); $aFacts[] = array( - 'name' => $oAttDef->GetLabel(), + $sLabelKey => $oAttDef->GetLabel(), 'value' => static::TransformHTMLToMSTeamsMarkup($sValueAsHtml), ); } @@ -2425,10 +2613,11 @@ protected function ApplyParamsToJson(array $aContextArgs, string $sInputAsJson) * Return an array of actions formatted for Microsoft Teams "potential actions" system * * @param array $aContextArgs + * @param string $sJsonFormat * * @return array */]]> - Get('include_modify_button') === 'yes') { - $aActionElements[] = array( - '@type' => 'OpenUri', - 'name' => Dict::S('UI:Menu:Modify'), - 'targets' => array( - array( - 'os' => 'default', - 'uri' => sprintf('%spages/UI.php?operation=modify&class=%s&id=%d', $sBaseURL, $sObjClass, $iObjID), - ), - ), + $aActionElements[] = $this->PrepareActionElementForMSTeamsAPI( + Dict::S('UI:Menu:Modify'), + sprintf('%spages/UI.php?operation=modify&class=%s&id=%d', $sBaseURL, $sObjClass, $iObjID), + $sJsonFormat ); } @@ -2475,15 +2659,10 @@ protected function ApplyParamsToJson(array $aContextArgs, string $sInputAsJson) { if (isset($aTransitions[$sStimulusCode]) && is_a($aStimuli[$sStimulusCode], StimulusUserAction::class)) { - $aActionElements[] = array( - '@type' => 'OpenUri', - 'name' => $aStimuli[$sStimulusCode]->GetLabel(), - 'targets' => array( - array( - 'os' => 'default', - 'uri' => sprintf('%spages/UI.php?operation=stimulus&stimulus=%s&class=%s&id=%d', $sBaseURL, $sStimulusCode, $sObjClass, $iObjID), - ), - ), + $aActionElements[] = $this->PrepareActionElementForMSTeamsAPI( + $aStimuli[$sStimulusCode]->GetLabel(), + sprintf('%spages/UI.php?operation=stimulus&stimulus=%s&class=%s&id=%d', $sBaseURL, $sStimulusCode, $sObjClass, $iObjID), + $sJsonFormat ); } } @@ -2492,20 +2671,53 @@ protected function ApplyParamsToJson(array $aContextArgs, string $sInputAsJson) // Delete button if($this->Get('include_delete_button') === 'yes') { - $aActionElements[] = array( - '@type' => 'OpenUri', - 'name' => Dict::S('UI:Menu:Delete'), - 'targets' => array( - array( - 'os' => 'default', - 'uri' => sprintf('%spages/UI.php?operation=delete&class=%s&id=%d', $sBaseURL, $sObjClass, $iObjID), - ), - ), + $aActionElements[] = $this->PrepareActionElementForMSTeamsAPI( + Dict::S('UI:Menu:Delete'), + sprintf('%spages/UI.php?operation=delete&class=%s&id=%d', $sBaseURL, $sObjClass, $iObjID), + $sJsonFormat ); } return $aActionElements; } +]]> + + + + false + protected + Custom + + [ + '@type' => 'OpenUri', + 'name' => $sLabel, + 'targets' => [ + [ + 'os' => 'default', + 'uri' => $sUrl, + ], + ], + ], + 'adaptive_card' => [ + "type" => "Action.OpenUrl", + "title" => $sLabel, + "url" => $sUrl + ], + default => throw new Exception('Action Elements only supported for format "message_card" or "adaptive_card"'), + }; + } ]]> @@ -2604,6 +2816,9 @@ protected function ApplyParamsToJson(array $aContextArgs, string $sInputAsJson) 20 + + 30 + diff --git a/dictionnaries/de.dict.combodo-webhook-integration.php b/dictionnaries/de.dict.combodo-webhook-integration.php index 93dce11..58ec7a7 100755 --- a/dictionnaries/de.dict.combodo-webhook-integration.php +++ b/dictionnaries/de.dict.combodo-webhook-integration.php @@ -4,7 +4,7 @@ * * @copyright Copyright (C) 2010-2024 Combodo SAS * @license https://opensource.org/licenses/AGPL-3.0 - * + * */ /** * @@ -56,6 +56,10 @@ 'Class:ActionMicrosoftTeamsNotification/Attribute:include_other_actions_button/Value:no' => 'Nein', 'Class:ActionMicrosoftTeamsNotification/Attribute:include_other_actions_button/Value:specify' => 'Spezifisch', 'Class:ActionMicrosoftTeamsNotification/Attribute:include_other_actions_button/Value:yes' => 'Ja', + 'Class:ActionMicrosoftTeamsNotification/Attribute:json_format' => 'JSON-Format', + 'Class:ActionMicrosoftTeamsNotification/Attribute:json_format+' => 'Festlegung welches Format zur Übertragung verwendet werden soll.', + 'Class:ActionMicrosoftTeamsNotification/Attribute:json_format/Value:message_card' => 'Message Card', + 'Class:ActionMicrosoftTeamsNotification/Attribute:json_format/Value:adaptive_card' => 'Adaptive Card', 'Class:ActionMicrosoftTeamsNotification/Attribute:message' => 'Nachricht', 'Class:ActionMicrosoftTeamsNotification/Attribute:prepare_payload_callback+' => 'PHP-Methode zur Vorbereitung des Payloads, der während des Webhook-Aufrufs gesendet werden sollen. Wählen Sie diese Option, wenn die Standardoptionen nicht flexibel genug sind oder wenn Ihre Nutzlaststruktur dynamisch aufgebaut werden muss. diff --git a/dictionnaries/en.dict.combodo-webhook-integration.php b/dictionnaries/en.dict.combodo-webhook-integration.php index a7a79d2..55e2038 100644 --- a/dictionnaries/en.dict.combodo-webhook-integration.php +++ b/dictionnaries/en.dict.combodo-webhook-integration.php @@ -260,6 +260,10 @@ IMPORTANT: If set, the \'title\', \'message\' and all \'additional elements\' will be ignored.', // - Fieldsets 'ActionMicrosoftTeamsNotification:message' => 'Basis message', + 'Class:ActionMicrosoftTeamsNotification/Attribute:json_format' => 'JSON format', + 'Class:ActionMicrosoftTeamsNotification/Attribute:json_format+' => 'Determines which format should be used for transmission.', + 'Class:ActionMicrosoftTeamsNotification/Attribute:json_format/Value:message_card' => 'Message Card', + 'Class:ActionMicrosoftTeamsNotification/Attribute:json_format/Value:adaptive_card' => 'Adaptive Card', 'ActionMicrosoftTeamsNotification:additionalelements' => 'Additional elements to include', 'ActionMicrosoftTeamsNotification:theme' => 'Theme', ));