def notify(success, title, content, **kwargs): # escape the full content content = content.__class__( (k, escape_markdown(v) if isinstance(v, six.string_types) else v) for k, v in content.items()) # overwrite title with slack markdown markup title = "*Notification from* `{}`".format(content["Task"]) del content["Task"] # markup for traceback if "Traceback" in content: content["Traceback"] = "```{}```".format(content["Traceback"]) # prepend the status text to the message content # emojis are "party popper" and "exclamation mark" parts = list(content.items()) status_text = "success \xF0\x9F\x8E\x89" if success else "failure \xE2\x9D\x97" parts.insert(0, ("Status", status_text)) content = collections.OrderedDict(parts) # attachment color depends on success color = "#4bb543" if success else "#ff0033" # send the notification return notify_slack(title, content, attachment_color=color, **kwargs)
def notify_telegram(title, content, token=None, chat=None, mention_user=None, **kwargs): """ Sends a telegram notification and returns *True* on success. The communication with the telegram API might have some delays and is therefore handled by a thread. """ # test import import telegram # noqa: F401 cfg = Config.instance() # get default token and chat if not token: token = cfg.get_expanded("notifications", "telegram_token") if not chat: chat = cfg.get_expanded("notifications", "telegram_chat") if not token or not chat: logger.warning( "cannot send Telegram notification, token ({}) or chat ({}) empty". format(token, chat)) return False # append the user to mention to the title # unless explicitly set to empty string mention_text = "" if mention_user is None: mention_user = cfg.get_expanded("notifications", "telegram_mention_user") if mention_user: mention_text = " (@{})".format(escape_markdown(mention_user)) # request data for the API call request = {"parse_mode": "MarkdownV2"} # standard or attachment content? if isinstance(content, six.string_types): request["text"] = "{}{}\n\n{}".format(title, mention_text, content) else: # content is a dict, add some formatting request["text"] = "{}{}\n\n".format(title, mention_text) for key, value in content.items(): request["text"] += "_{}_: {}\n".format(key, value) # extend by arbitrary kwargs request.update(kwargs) # threaded, non-blocking API communication thread = threading.Thread(target=_notify_telegram, args=(token, chat, request)) thread.start() return True
def notify_slack(title, content, attachment_color="#4bb543", short_threshold=40, token=None, channel=None, mention_user=None, **kwargs): """ Sends a slack notification and returns *True* on success. The communication with the slack API might have some delays and is therefore handled by a thread. The format of the notification depends on *content*. If it is a string, a simple text notification is sent. Otherwise, it should be a dictionary whose fields are used to build a message attachment with two-column formatting. """ # test import import_slack() cfg = Config.instance() # get default token and channel if not token: token = cfg.get_expanded("notifications", "slack_token") if not channel: channel = cfg.get_expanded("notifications", "slack_channel") if not token or not channel: logger.warning( "cannot send Slack notification, token ({}) or channel ({}) empty". format(token, channel)) return False # append the user to mention to the title # unless explicitly set to empty string mention_text = "" if mention_user is None: mention_user = cfg.get_expanded("notifications", "slack_mention_user") if mention_user: mention_text = " (@{})".format(escape_markdown(mention_user)) # request data for the API call request = { "channel": channel, "as_user": True, "parse": "full", } # standard or attachment content? if isinstance(content, six.string_types): request["text"] = "{}{}\n\n{}".format(title, mention_text, content) else: # content is a dict, send its data as an attachment request["text"] = "{} {}".format(title, mention_text) request["attachments"] = at = { "color": attachment_color, "fields": [], "fallback": "{}{}\n\n".format(title, mention_text), } # fill the attachment fields and extend the fallback for key, value in content.items(): at["fields"].append({ "title": key, "value": value, "short": len(value) <= short_threshold, }) at["fallback"] += "_{}_: {}\n".format(key, value) # extend by arbitrary kwargs request.update(kwargs) # threaded, non-blocking API communication thread = threading.Thread(target=_notify_slack, args=(token, request)) thread.start() return True