Prior to this commit, we were just including the rot result in the
response to the POST request. That was sufficient for Slack to take
the result and present it privately to the user that issued the
command. But that would not allow any other user in the same channel
to see the same result.
Here, instead, we use the Slack WebClient API to inject the result
into the user's channel as a new message. This takes advantage of a
new, encrypted SSM parameter SLACK_BOT_TOKEN to authenticate our
bot. It also requires bundling all of the virtualenv dependencies into
the zip file uploaded to AWS for the lambda, so that's what the
Makefile modifications do here.
deploy-lambda:
rm -rf .deploy-lambda-source
git clone . .deploy-lambda-source
deploy-lambda:
rm -rf .deploy-lambda-source
git clone . .deploy-lambda-source
+ make -C .deploy-lambda-source bootstrap
+ (cd .deploy-lambda-source; . env/bin/activate; make reqs)
+ (cd .deploy-lambda-source/env/lib/python3.8/site-packages; zip -r ../../../../turbot.zip .)
(cd .deploy-lambda-source/turbot_lambda; zip ../turbot.zip turbot_lambda.py)
(cd .deploy-lambda-source; zip turbot.zip $$(git ls-files -- turbot))
(cd .deploy-lambda-source; \
(cd .deploy-lambda-source/turbot_lambda; zip ../turbot.zip turbot_lambda.py)
(cd .deploy-lambda-source; zip turbot.zip $$(git ls-files -- turbot))
(cd .deploy-lambda-source; \
from urllib.parse import parse_qs
from turbot.rot import rot
from urllib.parse import parse_qs
from turbot.rot import rot
+from slack import WebClient
+import boto3
+import requests
+
+ssm = boto3.client('ssm')
+response = ssm.get_parameter(Name='SLACK_BOT_TOKEN', WithDecryption=True)
+slack_bot_token = response['Parameter']['Value']
+slack_client = WebClient(slack_bot_token)
def turbot_lambda(event, context):
"""Top-level entry point for our lambda function.
def turbot_lambda(event, context):
"""Top-level entry point for our lambda function.
args = body['text'][0]
if (command == "/rotlambda" or command == "/rot"):
args = body['text'][0]
if (command == "/rotlambda" or command == "/rot"):
- return rot_slash_command(args)
+ return rot_slash_command(body, args)
error = "Command {} not implemented.".format(command)
error = "Command {} not implemented.".format(command)
-def rot_slash_command(args):
+def rot_slash_command(body, args):
"""Implementation of the /rot command
The args string should be as follows:
"""Implementation of the /rot command
The args string should be as follows:
the body of the response so that Slack will provide it as a reply
to the user who submitted the slash command."""
the body of the response so that Slack will provide it as a reply
to the user who submitted the slash command."""
+ channel_name = body['channel_name'][0]
+ response_url = body['response_url'][0]
+ channel_id = body['channel_id'][0]
+
+ result = rot(args)
+
+ if (channel_name == "directmessage"):
+ requests.post(response_url,
+ json = {"text": result},
+ headers = {"Content-type": "application/json"})
+ else:
+ slack_client.chat_postMessage(channel=channel_id, text=result)
+
return {
'statusCode': 200,
return {
'statusCode': 200,