diff --git a/client/app/assets/images/destinations/hangouts_chat.png b/client/app/assets/images/destinations/hangouts_chat.png
new file mode 100644
index 0000000000..ef934b0a2c
Binary files /dev/null and b/client/app/assets/images/destinations/hangouts_chat.png differ
diff --git a/redash/destinations/hangoutschat.py b/redash/destinations/hangoutschat.py
new file mode 100644
index 0000000000..28951b6193
--- /dev/null
+++ b/redash/destinations/hangoutschat.py
@@ -0,0 +1,96 @@
+import logging
+import requests
+
+from redash.destinations import *
+from redash.utils import json_dumps
+
+
+class HangoutsChat(BaseDestination):
+ @classmethod
+ def name(cls):
+ return "Google Hangouts Chat"
+
+ @classmethod
+ def type(cls):
+ return "hangouts_chat"
+
+ @classmethod
+ def configuration_schema(cls):
+ return {
+ "type": "object",
+ "properties": {
+ "url": {
+ "type": "string",
+ "title": "Webhook URL (get it from the room settings)"
+ },
+ "icon_url": {
+ "type": "string",
+ "title": "Icon URL (32x32 or multiple, png format)"
+ }
+ },
+ "required": ["url"]
+ }
+
+ @classmethod
+ def icon(cls):
+ return 'fa-bolt'
+
+ def notify(self, alert, query, user, new_state, app, host, options):
+ try:
+ if new_state == "triggered":
+ message = "Triggered"
+ elif new_state == "ok":
+ message = "Went back to normal"
+ else:
+ message = "Unable to determine status. Check Query and Alert configuration."
+
+ data = {
+ "cards": [
+ {
+ "header": {
+ "title": alert.name
+ },
+ "sections": [
+ {
+ "widgets": [
+ {
+ "textParagraph": {
+ "text": message
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+
+ if options.get("icon_url"):
+ data["cards"][0]["header"]["imageUrl"] = options.get("icon_url")
+
+ # Hangouts Chat will create a blank card if an invalid URL (no hostname) is posted.
+ if host:
+ data["cards"][0]["sections"][0]["widgets"].append({
+ "buttons": [
+ {
+ "textButton": {
+ "text": "OPEN QUERY",
+ "onClick": {
+ "openLink": {
+ "url": "{host}/queries/{query_id}".format(host=host, query_id=query.id)
+ }
+ }
+ }
+ }
+ ]
+ })
+
+ headers = {"Content-Type": "application/json; charset=UTF-8"}
+ resp = requests.post(options.get("url"), data=json_dumps(data), headers=headers, timeout=5.0)
+ if resp.status_code != 200:
+ logging.error("webhook send ERROR. status_code => {status}".format(status=resp.status_code))
+ except Exception:
+ logging.exception("webhook send ERROR.")
+
+
+register(HangoutsChat)
diff --git a/redash/settings/__init__.py b/redash/settings/__init__.py
index 5dd7611a78..2b9e870100 100644
--- a/redash/settings/__init__.py
+++ b/redash/settings/__init__.py
@@ -216,6 +216,7 @@ def all_settings():
'redash.destinations.mattermost',
'redash.destinations.chatwork',
'redash.destinations.pagerduty',
+ 'redash.destinations.hangoutschat'
]
enabled_destinations = array_from_string(os.environ.get("REDASH_ENABLED_DESTINATIONS", ",".join(default_destinations)))