Skip to content

Commit

Permalink
feat: microsoft teams provider add support for adaptivecards (#2736)
Browse files Browse the repository at this point in the history
  • Loading branch information
talboren authored Dec 3, 2024
1 parent cd2eeb0 commit 036f406
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 37 deletions.
170 changes: 154 additions & 16 deletions docs/providers/documentation/teams-provider.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,19 @@ The `notify` function in the `TeamsProvider` class takes the following parameter
```python
kwargs (dict):
message (str): The message to send. *Required*
typeCard (str): The card type. (MessageCard is default)
themeColor (str): Hexadecimal color.
sections (array): Array of custom informations
typeCard (str): The card type. Can be "MessageCard" (legacy) or "message" (for Adaptive Cards). Default is "message"
themeColor (str): Hexadecimal color (only used with MessageCard type)
sections (array/str): For MessageCard: Array of custom information sections
For Adaptive Cards: Array of card elements following the Adaptive Card schema
Can be provided as a JSON string or array
attachments (array/str): Custom attachments array for Adaptive Cards (overrides default attachment structure)
Can be provided as a JSON string or array
schema (str): Schema URL for Adaptive Cards. Default is "http://adaptivecards.io/schemas/adaptive-card.json"
```

## Outputs

_No information yet, feel free to contribute it using the "Edit this page" link the bottom of the page_
The response as JSON, which is the response from the Microsoft Teams API.

## Authentication Parameters

Expand All @@ -28,26 +33,159 @@ The TeamsProviderAuthConfig class takes the following parameters:

## Connecting with the Provider

1. Open the Microsoft Teams application or website and select the team or channel where you want to add the webhook.
<Tabs>
<Tab title="New Teams">
1. In the New Teams client, select Teams and navigate to the channel where
you want to add an Incoming Webhook. 2. Select More options ••• on the right
side of the channel name. 3. Select Manage Channel
<Frame>
<img src="https://learn.microsoft.com/en-us/microsoftteams/platform/assets/images/manage-channel-new-teams.png" />
</Frame>
<Note>
For members who aren't admins of the channel, the Manage channel option is
available under the Open channel details option in the upper-right corner
of a channel.
</Note>
4. Select Edit
<Frame>
<img src="https://learn.microsoft.com/en-us/microsoftteams/platform/assets/images/edit-connector-new-teams.png" />
</Frame>
5. Search for Incoming Webhook and select Add.
<Frame>
<img src="https://learn.microsoft.com/en-us/microsoftteams/platform/assets/images/search-add-webhook.png" />
</Frame>
6. Select Add
<Frame>
<img src="https://learn.microsoft.com/en-us/microsoftteams/platform/assets/images/add-incoming-webhook-lightbox.png#lightbox" />
</Frame>
7. Provide a name for the webhook and upload an image if necessary. 8. Select
Create.
<Frame>
<img src="https://learn.microsoft.com/en-us/microsoftteams/platform/assets/images/create-incoming-webhook-new-teams.png" />
</Frame>
9. Copy and save the unique webhook URL present in the dialog. The URL maps to
the channel and you can use it to send information to Teams. 10. Select Done.
The webhook is now available in the Teams channel.
<Frame>
<img src="https://learn.microsoft.com/en-us/microsoftteams/platform/assets/images/url_1-new-teams.png" />
</Frame>
</Tab>
<Tab title="Classic Teams">
1. In the Classic Teams client, select Teams and navigate to the channel
where you want to add an Incoming Webhook. 2. Select More options ••• from
the upper-right corner. 3. Select Connectors from the dropdown menu.
<Frame>
<img src="https://learn.microsoft.com/en-us/microsoftteams/platform/assets/images/connectors_1.png" />
</Frame>
4. Search for Incoming Webhook and select Add.
<Frame>
<img src="https://learn.microsoft.com/en-us/microsoftteams/platform/assets/images/search-add-webhook.png" />
</Frame>
5. Select Add.
<Frame>
<img src="https://learn.microsoft.com/en-us/microsoftteams/platform/assets/images/add-incoming-webhook.png" />
</Frame>
6. Provide a name for the webhook and upload an image if necessary. 7.
Select Create.
<Frame>
<img src="https://learn.microsoft.com/en-us/microsoftteams/platform/assets/images/create-incoming-webhook.png" />
</Frame>
8. Copy and save the unique webhook URL present in the dialog. The URL maps
to the channel and you can use it to send information to Teams. 9. Select
Done.
<Frame>
<img src="https://learn.microsoft.com/en-us/microsoftteams/platform/assets/images/url_1.png" />
</Frame>
</Tab>
</Tabs>

2. Click on the three-dot icon next to the team or channel name and select "Connectors" from the dropdown menu.

3. Search for "Incoming Webhook" and click on the "Add" button.

4. Give your webhook a name and an optional icon, then click on the "Create" button.
## Notes

5. Copy the webhook URL that is generated and save it for later use.
When using Adaptive Cards (`typeCard="message"`):

- The `sections` parameter should follow the [Adaptive Cards schema](https://adaptivecards.io/explorer/)
- `themeColor` is ignored for Adaptive Cards
- If no sections are provided, the message will be displayed as a simple text block
- Both `sections` and `attachments` can be provided as JSON strings or arrays

### Workflow Example

You can also find this example in our [examples](https://github.com/keephq/keep/tree/main/examples/workflows/keep-teams-adaptive-cards.yaml) folder in the Keep GitHub repository.

```yaml
id: 6bc7c72e-ab3d-4913-84dd-08b9323195ae
description: Teams Adaptive Cards Example
disabled: false
triggers:
- type: manual
- filters:
- key: source
value: r".*"
type: alert
consts: {}
name: Keep Teams Adaptive Cards
owners: []
services: []
steps: []
actions:
- name: teams-action
provider:
config: "{{ providers.teams }}"
type: teams
with:
message: ""
sections: '[{"type": "TextBlock", "text": "{{alert.name}}"}, {"type": "TextBlock", "text": "Tal from Keep"}]'
typeCard: message
```

6. Select the options that you want to configure for your webhook, such as the default name and avatar that will be used when posting messages.
<Note>
The sections parameter is a JSON string that follows the Adaptive Cards schema, but can also be an object.
If it's a string, it will be parsed as a JSON string.
</Note>

7. Click on the "Save" button to save your webhook settings.
### Using Sections

You can now use the webhook URL to send messages to the selected channel or team in Microsoft Teams.
```python
provider.notify(
message="Fallback text",
typeCard="message",
sections=[
{
"type": "TextBlock",
"text": "Hello from Adaptive Card!"
},
{
"type": "Image",
"url": "https://example.com/image.jpg"
}
]
)
```

## Notes
### Using Custom Attachments

_No information yet, feel free to contribute it using the "Edit this page" link the bottom of the page_
```python
provider.notify(
typeCard="message",
attachments=[{
"contentType": "application/vnd.microsoft.card.adaptive",
"content": {
"type": "AdaptiveCard",
"version": "1.2",
"body": [
{
"type": "TextBlock",
"text": "Custom Attachment Example"
}
]
}
}]
)
```

## Useful Links

- https://learn.microsoft.com/pt-br/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook
- https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using
- https://adaptivecards.io/explorer/
- https://adaptivecards.io/schemas/adaptive-card.json
23 changes: 23 additions & 0 deletions examples/workflows/keep-teams-adaptive-cards.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
id: 6bc7c72e-ab3d-4913-84dd-08b9323195ae
description: Teams Adaptive Cards Example
disabled: false
triggers:
- type: manual
- filters:
- key: source
value: r".*"
type: alert
consts: {}
name: Keep Teams Adaptive Cards
owners: []
services: []
steps: []
actions:
- name: teams-action
provider:
config: "{{ providers.teams }}"
type: teams
with:
message: ""
sections: '[{"type": "TextBlock", "text": "{{alert.name}}"}, {"type": "TextBlock", "text": "Tal from Keep"}]'
typeCard: message
8 changes: 4 additions & 4 deletions keep-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion keep-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"postcss-nested": "^6.0.1",
"postcss-selector-parser": "^6.0.12",
"postcss-value-parser": "^4.2.0",
"posthog-js": "^1.194.1",
"posthog-js": "^1.194.2",
"posthog-node": "^3.1.1",
"pusher-js": "^8.3.0",
"react": "^18.3.1",
Expand Down
69 changes: 54 additions & 15 deletions keep/providers/teams_provider/teams_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import dataclasses

import json5 as json
import pydantic
import requests

Expand Down Expand Up @@ -51,37 +52,78 @@ def dispose(self):
def _notify(
self,
message="",
typeCard="MessageCard",
typeCard="message",
themeColor=None,
sections=[],
schema="http://adaptivecards.io/schemas/adaptive-card.json",
attachments=[],
**kwargs: dict,
):
"""
Notify alert message to Teams using the Teams Incoming Webhook API
https://learn.microsoft.com/pt-br/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using?tabs=cURL
Args:
kwargs (dict): The providers with context
message (str): The message to send
typeCard (str): Type of card to send ("MessageCard" or "message" for Adaptive Cards)
themeColor (str): Color theme for MessageCard
sections (list): Sections for MessageCard or Adaptive Card content
attachments (list): Attachments for Adaptive Card
**kwargs (dict): Additional arguments
"""
self.logger.debug("Notifying alert message to Teams")

webhook_url = self.authentication_config.webhook_url

response = requests.post(
webhook_url,
json={
if isinstance(sections, str):
try:
sections = json.loads(sections)
except json.JSONDecodeError as e:
self.logger.error(f"Failed to decode sections string to JSON: {e}")

if attachments and isinstance(attachments, str):
try:
attachments = json.loads(attachments)
except json.JSONDecodeError as e:
self.logger.error(f"Failed to decode attachments string to JSON: {e}")

if typeCard == "message":
# Adaptive Card format
payload = {
"type": "message",
"attachments": attachments
or [
{
"contentType": "application/vnd.microsoft.card.adaptive",
"contentUrl": None,
"content": {
"$schema": schema,
"type": "AdaptiveCard",
"version": "1.2",
"body": (
sections
if sections
else [{"type": "TextBlock", "text": message}]
),
},
}
],
}
else:
# Standard MessageCard format
payload = {
"@type": typeCard,
"themeColor": themeColor,
"text": message,
"sections": sections,
},
)
}

response = requests.post(webhook_url, json=payload)
if not response.ok:
raise ProviderException(
f"{self.__class__.__name__} failed to notify alert message to Teams: {response.text}"
)

self.logger.debug("Alert message notified to Teams")
return response.json()


if __name__ == "__main__":
Expand All @@ -106,12 +148,9 @@ def _notify(
)
provider = TeamsProvider(context_manager, provider_id="teams", config=config)
provider.notify(
typeCard="MessageCard",
themeColor="0076D7",
message="Microsoft Teams alert",
typeCard="message",
sections=[
{"name": "Assigned to", "value": "Danilo Vaz"},
{"name": "Sum", "value": 10},
{"name": "Count", "value": 100},
{"type": "TextBlock", "text": "Danilo Vaz"},
{"type": "TextBlock", "text": "Tal from Keep"},
],
)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "keep"
version = "0.30.7"
version = "0.31.0"
description = "Alerting. for developers, by developers."
authors = ["Keep Alerting LTD"]
packages = [{include = "keep"}]
Expand Down

0 comments on commit 036f406

Please sign in to comment.