Webex Teams recently released support for Adaptive Cards, which allow the user to interact with a teams user (typically a bot) without leaving the page. This is great for taking quick polls, and also piping data from other applications like help desk, travel and expenses, crm, etc.

I love that Cisco adopted the Microsoft standard for Adaptive Cards instead of trying to create their own unnecessarily. The website, adaptivecards.io has great documentation, and a designer to help get started. There is an author sdk as well, but I find that using a templating system such as Jinja2 does the job without learning anything new.

adaptivecards.io/designer

I teach a class at our companywide conference every year called UC Automation, and I thought what a better way to teach about Buttons and Cards (aka Adaptive Cards) than by using it in the class itself. A month prior to the conference, I sent a poll to everyone that registered so they could pick the topics they want to hear about most.

UC Automation: Drinking From the Firehose

To use Adaptive Cards in Webex Teams, I created an example in 🐍Python

First install prerequisites:

pip install requests
pip install webexteamssdk
pip install flask

brew install ngrok
ngrok http 3000

Next

import json
import os
import requests
from webexteamssdk import WebexTeamAPI, ApiError
from flask import Flask, request
app = Flask(__name__)

'''
For prototyping, we use ngrok.
We'll request the tunnel and parse the url to use for a webhook
'''
tunnel = json.loads(
  requests.request('GET', url = 'http://localhost:4040/api/tunnels'
  ).text
)
public_url = tunnel['tunnels'][0]['public_url']

'''
Specify the webex token and roomId to use
'''
token = os.environ['token']
roomId = os.environ['roomId']

'''
Using webexteamssdk but also need requests
for attachment action endpoint which is not in sdk yet!
'''
wbx = WebexTeamsAPI(access_token = token)
headers = {
  'Authorization': 'Bearer ' + token
}

'''
Register webhook to ngrok for attachmentActions
'''
for webhook in wbx.webhooks.list():
  wbx.webhooks.delete(webhook.id)

wbx.webhooks.create(
  name = 'Development - ngrok',
  targetUrl = public_url,
  resource = 'attachmentActions',
  event = 'created'
)

'''
Paste Card from adaptivecards.io/designer to a file named card.json 
'''
attachments = []
attachment = {}
attachment['contentType'] = "application/vnd.microsoft.card.adaptive"
attachment['content'] = json.loads(open('card.json').read())
attachments.append(attachment)

'''
Send Message
'''
wbx.messages.create(
  roomId = roomId, 
  markdown = '.', 
  attachments = attachments
)

'''
Receive Data in Webhook and Request Action Payload
'''
@app.route('/', methods = ['POST'])
def index():
  action = request.json['data']['id']
  results = requests.request('GET',
  headers = headers,
  url = f '{wbx.base_url}attachment/actions/{action}'
)
  print(json.loads(results.text))
  return ('', 200, None)

if __name__ == '__main__':
  app.run(port = 3000, use_reloader = True)

Just like with the messages webhook resource, the payload does not include the data, but rather an action id that is used along with the token to retrieve the data, shown below:

{'created': '2019-11-08T21:47:14.436Z',
 'id': 'asdfasdfasdfasdf',
 'inputs': {
  'comments': 'Here’s a great idea.  Get a real job!'
 },
 'messageId': 'qwerqwerqwerqwerqwerqwer',
 'personId': 'fghjfghjfghjfghjfghjfghj',
 'roomId': 'vbnmbnmvbnmvbnmvbnmvbnm',
 'type': 'submit'}

For my UC Automation class, I stored the results in AWS. Below is a fun script to gather the results and display them with emojis.

from boto3 import *
table = resource('dynamodb').Table('count')

results = table.get_item(Key={'use': 'uc250'})
results = rd.replace_decimals(results['Item'])
del results['use']
results = list(results.items())

for topic in results:
    chart = 😎
    for i in range(0, int(topic[1])):
        chart = chart+'😎 '
    print(topic[0]+': '+chart)

$ python collect.py

expressway: 😎 😎 😎 😎 
guest: 😎 😎 😎 😎 😎 😎 😎 😎 😎 😎 😎 😎 😎 😎 
cucm: 😎 😎 😎 😎 😎 😎 😎 
buttons: 😎 😎 😎 😎 😎 
admin: 😎 😎 😎 😎 😎 😎 😎 😎 😎 😎 😎 😎 😎 😎 😎 😎 
xapi: 😎 😎 😎 
browser: 😎 😎 
curri: 😎 😎  
cms: 😎 
meetings: 😎 😎 😎