266 lines
9.7 KiB
Python
266 lines
9.7 KiB
Python
#!/usr/bin/env python
|
|
|
|
import json, httplib, urllib, ssl, copy, os
|
|
|
|
# import stock icons
|
|
try:
|
|
stock_icons = json.loads(open(os.path.dirname(__file__)+'/icons.json','r').read())
|
|
except:
|
|
raise Exception('Unable to load icon file')
|
|
|
|
# The Actual class
|
|
class MessageCard:
|
|
" Create and send a Teams Webhook "
|
|
|
|
card_template = {
|
|
'@type': 'MessageCard',
|
|
'@context': 'http://schema.org/extensions',
|
|
'summary': '',
|
|
'sections': [],
|
|
}
|
|
|
|
action_button_template = {
|
|
'@type': 'ActionCard',
|
|
'actions': [{
|
|
'@type': 'HttpPOST',
|
|
}]
|
|
}
|
|
|
|
action_textinput_template = {
|
|
'@type': 'ActionCard',
|
|
'inputs': [{
|
|
'@type': 'TextInput',
|
|
}],
|
|
'actions': [{
|
|
'@type': 'HttpPOST',
|
|
}]
|
|
}
|
|
|
|
action_dateinput_template = {
|
|
'@type': 'ActionCard',
|
|
'inputs': [{
|
|
'@type': 'DateInput',
|
|
}],
|
|
'actions': [{
|
|
'@type': 'HttpPOST',
|
|
}]
|
|
}
|
|
|
|
action_multichoice_template = {
|
|
'@type': 'ActionCard',
|
|
'inputs': [{
|
|
'@type': 'MultichoiceInput',
|
|
'choices': []
|
|
}],
|
|
'actions': [{
|
|
'@type': 'HttpPOST',
|
|
}]
|
|
}
|
|
|
|
channel_uri = None
|
|
icon = ''
|
|
title = ''
|
|
subtitle = ''
|
|
facts = []
|
|
actions = []
|
|
error = ''
|
|
|
|
def __init__(self, tls_verify_host=False, tls_verify_mode=ssl.CERT_NONE):
|
|
try:
|
|
self.SetupTLS(tls_verify_host,tls_verify_mode)
|
|
except:
|
|
raise Exception('Unable to setup TLS/SSL Context')
|
|
|
|
def SetupTLS(self,tls_verify_host,tls_verify_mode):
|
|
self.tls_ctx = ssl.create_default_context()
|
|
self.tls_ctx.check_hostname = tls_verify_host
|
|
self.tls_ctx.verify_mode = tls_verify_mode
|
|
|
|
def AddFacts(self, data_array):
|
|
" Add a 'fact' to the message"
|
|
if isinstance(data_array,dict):
|
|
for key, value in data_array.items():
|
|
self.facts.append({'name': key, 'value': value})
|
|
elif isinstance(data_array,list):
|
|
for fact in data_array:
|
|
if isinstance(fact,dict):
|
|
for key, value in fact.items():
|
|
self.facts.append({'name': key, 'value': value})
|
|
else:
|
|
raise Exception('No data provided for facts')
|
|
|
|
def AddButton(self, action_array):
|
|
" Add a button, expects a dict with action_name, button_label and post_uri "
|
|
thisAction = None
|
|
thisAction = copy.deepcopy(self.action_button_template)
|
|
if isinstance(action_array,dict):
|
|
try:
|
|
thisAction['name'] = action_array['action_name']
|
|
except:
|
|
raise Exception('action_name not present')
|
|
try:
|
|
thisAction['actions'][0]['name'] = action_array['button_label']
|
|
except:
|
|
raise Exception('button_label not present')
|
|
try:
|
|
thisAction['actions'][0]['target'] = action_array['post_uri']
|
|
except:
|
|
raise Exception('post_uri not present')
|
|
self.actions.append(thisAction)
|
|
else:
|
|
raise Exception('No data provided for action')
|
|
|
|
def AddTextInput(self, action_array):
|
|
" Add a Text Input, expects a dict with action_id, action_name, button_label, input_hint and post_uri, optional boolean multiline"
|
|
thisAction = None
|
|
thisAction = copy.deepcopy(self.action_textinput_template)
|
|
if isinstance(action_array,dict):
|
|
try:
|
|
thisId = action_array['action_id']
|
|
thisAction['inputs'][0]['id'] = thisId
|
|
thisAction['actions'][0]['body'] = str(thisId+"={{"+thisId+".value}}")
|
|
except:
|
|
raise Exception('action_id not present')
|
|
try:
|
|
thisAction['name'] = action_array['action_name']
|
|
except:
|
|
raise Exception('action_name not present')
|
|
try:
|
|
thisAction['actions'][0]['name'] = action_array['button_label']
|
|
except:
|
|
raise Exception('button_label not present')
|
|
try:
|
|
thisAction['actions'][0]['target'] = action_array['post_uri']
|
|
except:
|
|
raise Exception('post_uri not present')
|
|
try:
|
|
thisAction['inputs'][0]['title'] = action_array['input_hint']
|
|
except:
|
|
raise Exception('input_hint not present')
|
|
try:
|
|
if action_array['multiline'] == True:
|
|
thisAction['inputs'][0]['isMultiline'] = 'true'
|
|
except:
|
|
pass
|
|
self.actions.append(thisAction)
|
|
else:
|
|
raise Exception('No data provided for action')
|
|
|
|
def AddDateInput(self, action_array):
|
|
" Add a Date Input, expects a dict with action_id, action_name, button_label, input_hint and post_uri, optional boolean includetime"
|
|
thisAction = None
|
|
thisAction = copy.deepcopy(self.action_dateinput_template)
|
|
if isinstance(action_array,dict):
|
|
try:
|
|
thisId = action_array['action_id']
|
|
thisAction['inputs'][0]['id'] = thisId
|
|
thisAction['actions'][0]['body'] = str(thisId+"={{"+thisId+".value}}")
|
|
except:
|
|
raise Exception('action_id not present')
|
|
try:
|
|
thisAction['name'] = action_array['action_name']
|
|
except:
|
|
raise Exception('action_name not present')
|
|
try:
|
|
thisAction['actions'][0]['name'] = action_array['button_label']
|
|
except:
|
|
raise Exception('button_label not present')
|
|
try:
|
|
thisAction['actions'][0]['target'] = action_array['post_uri']
|
|
except:
|
|
raise Exception('post_uri not present')
|
|
try:
|
|
thisAction['inputs'][0]['title'] = action_array['input_hint']
|
|
except:
|
|
raise Exception('input_hint not present')
|
|
|
|
|
|
try:
|
|
if action_array['includetime'] == True:
|
|
thisAction['inputs'][0]['includeTime'] = 'true'
|
|
if action_array['includeTime'] == True:
|
|
thisAction['inputs'][0]['includeTime'] = 'true'
|
|
except:
|
|
pass
|
|
self.actions.append(thisAction)
|
|
else:
|
|
raise Exception('No data provided for action')
|
|
|
|
def AddMultichoice(self, action_array):
|
|
" Add a Multichoice Input, expects a dict with action_id, action_name, button_label, input_hint, post_uri and choices list (with display/value pairs as dicts), optional boolean multiselect"
|
|
thisAction = None
|
|
thisAction = copy.deepcopy(self.action_multichoice_template)
|
|
if isinstance(action_array,dict):
|
|
try:
|
|
thisId = action_array['action_id']
|
|
thisAction['inputs'][0]['id'] = thisId
|
|
thisAction['actions'][0]['body'] = str(thisId+"={{"+thisId+".value}}")
|
|
except:
|
|
raise Exception('action_id not present')
|
|
try:
|
|
thisAction['name'] = action_array['action_name']
|
|
except:
|
|
raise Exception('action_name not present')
|
|
try:
|
|
thisAction['actions'][0]['name'] = action_array['button_label']
|
|
except:
|
|
raise Exception('button_label not present')
|
|
try:
|
|
thisAction['actions'][0]['target'] = action_array['post_uri']
|
|
except:
|
|
raise Exception('post_uri not present')
|
|
try:
|
|
thisAction['inputs'][0]['title'] = action_array['input_hint']
|
|
except:
|
|
raise Exception('input_hint not present')
|
|
try:
|
|
if isinstance(action_array['choices'],list):
|
|
thisAction['inputs'][0]['choices'] = action_array['choices']
|
|
except:
|
|
raise Exception('choices list not present')
|
|
try:
|
|
if action_array['multiselect'] == True:
|
|
thisAction['inputs'][0]['isMultiSelect'] = 'true'
|
|
if action_array['multiSelect'] == True:
|
|
thisAction['inputs'][0]['isMultiSelect'] = 'true'
|
|
except:
|
|
pass
|
|
self.actions.append(thisAction)
|
|
else:
|
|
raise Exception('No data provided for action')
|
|
|
|
def GenerateCard(self):
|
|
" Generate the JSON for the card "
|
|
self.card = self.card_template
|
|
self.card['sections'].append({})
|
|
self.card['sections'][0]['activityTitle'] = self.title
|
|
self.card['sections'][0]['activitySubtitle'] = self.subtitle
|
|
self.card['sections'][0]['activityImage'] = self.icon
|
|
self.card['sections'][0]['facts'] = self.facts
|
|
self.card['potentialAction'] = self.actions
|
|
self.card['sections'][0]['markdown'] = 'true'
|
|
self.card['summary'] = self.title
|
|
|
|
def SendCard(self):
|
|
" Send the Card to the O365 API "
|
|
self.GenerateCard()
|
|
uri = self.channel_uri.split('/')
|
|
if not len(uri) == 8:
|
|
raise Exception('Invalid Channel URI')
|
|
endpoint = uri[2]
|
|
del uri[2], uri[1], uri[0]
|
|
uri = '/' + str('/'.join(uri))
|
|
|
|
try:
|
|
hookconnection = httplib.HTTPSConnection(endpoint, context=self.tls_ctx)
|
|
except:
|
|
raise Exception('Unable to open connection')
|
|
hookconnection.request('POST',uri,json.dumps(self.card))
|
|
self.response = hookconnection.getresponse()
|
|
#print(self.response.read())
|
|
|
|
def PrintJSON(self):
|
|
" Print the JSON of the card "
|
|
self.GenerateCard()
|
|
print(json.dumps(self.card,indent=1,sort_keys=True))
|
|
|