Skip to content

Instantly share code, notes, and snippets.

@mikloslorinczi
Created March 31, 2021 16:57
Show Gist options
  • Save mikloslorinczi/ea6686cafc5628a9b3966367ec8961e4 to your computer and use it in GitHub Desktop.
Save mikloslorinczi/ea6686cafc5628a9b3966367ec8961e4 to your computer and use it in GitHub Desktop.
Unified Python reporter class
'''
reporter.py provides a generic Reporter class, a SlackReporter and an MSTeamsReporter child classes
which are capable of sending messages via webhooks to channels in their respective services.
'''
import requests
import pymsteams
class SlackError(Exception):
pass
class MSTeamsError(Exception):
pass
class Reporter:
def __init__(self, webhook_url: str):
self.webhook_url = webhook_url
def post(self, title: str='DevOps Report', message: str='Message body', msg_type: str='info', buttons: list=[]):
pass
class SlackReporter(Reporter):
divider = {
'type': 'divider'
}
general_pic = {
'type': 'image',
'image_url': 'https://i.imgur.com/52oX1Gm.png',
'alt_text': 'message icon'
}
success_pic = {
'type': 'image',
'image_url': 'https://i.imgur.com/wB4IDMB.png',
'alt_text': 'success icon'
}
fail_pic = {
'type': 'image',
'image_url': 'https://i.imgur.com/29VM8ef.png',
'alt_text': 'fail icon'
}
picture_types = {
'ok': success_pic,
'success': success_pic,
'fail': fail_pic,
'error': fail_pic,
}
def __init__(self, webhook_url: str):
super().__init__(webhook_url)
def post(self, title: str, message: str, msg_type: str, buttons: list):
post_data = {
'blocks' : [
self.header(title),
self.text_with_pic(message, self.get_pic(msg_type)),
]
}
for button in buttons:
post_data['blocks'].extend([
self.divider,
self.button_with_link(
message = button['message'],
button_text = button['button_text'],
link = button['link'])])
self.__post_message(post_data)
def __post_message(self, post_data: dict):
try:
response = requests.post(self.webhook_url, json=post_data, headers={'content-type':'application/json'})
except Exception as err:
raise SlackError(f'Failed to send Slack message. Error: {err}')
if response.status_code != 200:
raise SlackError(f'Non-200 Slack status: {response.status_code} response: {response.text}')
return True
@classmethod
def get_pic(cls, pic_type: str):
lower = pic_type.lower()
if not lower in cls.picture_types:
return cls.general_pic
return cls.picture_types[lower]
@staticmethod
def header(title: str):
return {
'type': 'header',
'text': {
'type': 'plain_text',
'text': title,
'emoji': True
}
}
@staticmethod
def text_with_pic(text: str, pic: dict):
return {
'type': 'section',
'text': {
'type': 'mrkdwn',
'text': text,
},
'accessory': pic,
}
@staticmethod
def button_with_link(message: str, button_text: str, link: str):
return {
'type': 'section',
'text': {
'type': 'mrkdwn',
'text': message,
},
'accessory': {
'type': 'button',
'text': {
'type': 'plain_text',
'text': button_text,
'emoji': True
},
'value': 'click_me',
'url': link,
'action_id': 'button-action'
}
}
class MSTeamsReporter(Reporter):
# Blue
general_color = '#308edb'
# Green
success_color = '#4aed5f'
# Red
fail_color = '#e32e12'
color_types = {
'ok': success_color,
'success': success_color,
'fail': fail_color,
'error': fail_color,
}
def __init__(self, webhook_url: str):
super().__init__(webhook_url)
@classmethod
def get_color(cls, color_type: str):
lower = color_type.lower()
if not lower in cls.color_types:
return cls.general_color
return cls.color_types[lower]
def post(self, title: str, message: str, msg_type: str, buttons: list):
msg = pymsteams.connectorcard(self.webhook_url)
msg.title(title)
msg.text(message)
msg.color(self.get_color(msg_type))
for button in buttons:
section = pymsteams.cardsection()
section.title(button['message'])
section.linkButton(button['button_text'], button['link'])
msg.addSection(section)
try:
msg.send()
except Exception as err:
raise MSTeamsError(f'Failed to send MS Teams message: {err}')
return True
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment