diff --git a/client/app/assets/images/destinations/microsoft_teams_webhook.png b/client/app/assets/images/destinations/microsoft_teams_webhook.png new file mode 100644 index 0000000000..8ada5c8c69 Binary files /dev/null and b/client/app/assets/images/destinations/microsoft_teams_webhook.png differ diff --git a/docker-compose.yml b/docker-compose.yml index fdfcdd1a5d..fcfedf41d8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ x-redash-service: &redash-service build: context: . args: - skip_frontend_build: "true" + skip_frontend_build: "true" # set to empty string to build volumes: - .:/app env_file: diff --git a/redash/destinations/microsoft_teams_webhook.py b/redash/destinations/microsoft_teams_webhook.py new file mode 100644 index 0000000000..c8a320c6c0 --- /dev/null +++ b/redash/destinations/microsoft_teams_webhook.py @@ -0,0 +1,128 @@ +import logging +import requests +from string import Template + +from redash.destinations import * +from redash.utils import json_dumps +from redash.serializers import serialize_alert + + +def json_string_substitute(j, substitutions): + """ + Alternative to string.format when the string has braces. + :param j: json string that will have substitutions + :type j: str + :param substitutions: dictionary of values to be replaced + :type substitutions: dict + """ + if substitutions: + substitution_candidate = j.replace("{", "${") + string_template = Template(substitution_candidate) + substituted = string_template.safe_substitute(substitutions) + out_str = substituted.replace("${", "{") + return out_str + else: + return j + + +class MicrosoftTeamsWebhook(BaseDestination): + ALERTS_DEFAULT_MESSAGE_TEMPLATE = json_dumps({ + "@type": "MessageCard", + "@context": "http://schema.org/extensions", + "themeColor": "0076D7", + "summary": "A Redash Alert was Triggered", + "sections": [{ + "activityTitle": "A Redash Alert was Triggered", + "facts": [{ + "name": "Alert Name", + "value": "{alert_name}" + }, { + "name": "Alert URL", + "value": "{alert_url}" + }, { + "name": "Query", + "value": "{query_text}" + }, { + "name": "Query URL", + "value": "{query_url}" + }], + "markdown": True + }] + }) + + + @classmethod + def name(cls): + return "Microsoft Teams Webhook" + + @classmethod + def type(cls): + return "microsoft_teams_webhook" + + @classmethod + def configuration_schema(cls): + return { + "type": "object", + "properties": { + "url": { + "type": "string", + "title": "Microsoft Teams Webhook URL" + }, + "message_template": { + "type": "string", + "default": MicrosoftTeamsWebhook.ALERTS_DEFAULT_MESSAGE_TEMPLATE, + "title": "Message Template", + }, + }, + "required": ["url"], + } + + @classmethod + def icon(cls): + return "fa-bolt" + + def notify(self, alert, query, user, new_state, app, host, options): + """ + :type app: redash.Redash + """ + try: + alert_url = "{host}/alerts/{alert_id}".format( + host=host, alert_id=alert.id + ) + + query_url = "{host}/queries/{query_id}".format( + host=host, query_id=query.id + ) + + message_template = options.get( + "message_template", MicrosoftTeamsWebhook.ALERTS_DEFAULT_MESSAGE_TEMPLATE + ) + + # Doing a string Template substitution here because the template contains braces, which + # result in keyerrors when attempting string.format + payload = json_string_substitute(message_template, { + "alert_name": alert.name, + "alert_url": alert_url, + "query_text": query.query_text, + "query_url": query_url + }) + + headers = {"Content-Type": "application/json"} + + resp = requests.post( + options.get("url"), + data=payload, + headers=headers, + timeout=5.0, + ) + if resp.status_code != 200: + logging.error( + "MS Teams Webhook send ERROR. status_code => {status}".format( + status=resp.status_code + ) + ) + except Exception: + logging.exception("MS Teams Webhook send ERROR.") + + +register(MicrosoftTeamsWebhook) diff --git a/redash/settings/__init__.py b/redash/settings/__init__.py index 4879ddb309..c2cee79683 100644 --- a/redash/settings/__init__.py +++ b/redash/settings/__init__.py @@ -419,6 +419,7 @@ def email_server_is_configured(): "redash.destinations.chatwork", "redash.destinations.pagerduty", "redash.destinations.hangoutschat", + "redash.destinations.microsoft_teams_webhook", ] enabled_destinations = array_from_string(