Skip to content

Instantly share code, notes, and snippets.

@seratch
Last active October 17, 2020 14:56
Show Gist options
  • Save seratch/26c9ae7b07117553f783d5fc356618d1 to your computer and use it in GitHub Desktop.
Save seratch/26c9ae7b07117553f783d5fc356618d1 to your computer and use it in GitHub Desktop.
Deploying a Bolt for Python app using only AWS CLI
pip install -U awscli

# Create a new IAM policy
export policy_name=TODO
# lambda:InvokeFunction is required only for lazy listeners
aws iam create-policy \
  --policy-name ${policy_name} \
  --policy-document '{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["lambda:InvokeFunction"],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    }
  ]
}'
export policy_arn=TODO

# Create a new IAM role
export role_name=TODO
aws iam create-role \
  --role-name ${role_name} \
  --assume-role-policy-document '{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": { "Service": ["lambda.amazonaws.com"] },
      "Action": ["sts:AssumeRole"]
    }
  ]
}
'
export role_arn=TODO

aws iam attach-role-policy \
  --role-name ${role_name} \
  --policy-arn ${policy_arn}

# Check the current state
aws iam get-role \
  --role-name ${role_name}
aws iam list-attached-role-policies \
  --role-name ${role_name}

# Build the app
vi app.py
pip install -r requirements.txt --target ./libs
rm -f function.zip
cd libs/
zip ../function.zip -r *
cd -
zip -g function.zip app.py

export func_name=TODO
aws lambda create-function \
  --function-name ${func_name} \
  --runtime python3.8 \
  --role ${role_arn} \
  --handler app.handler \
  --zip-file fileb://./function.zip

export func_arn=TODO

# Create a Slack app
# Add bot scopes: commands, chat:write, im:write
# Install the app into your workspace

# env variables
export SLACK_BOT_TOKEN=TODO
export SLACK_SIGNING_SECRET=TODO

aws lambda update-function-configuration \
  --function-name ${func_name} \
  --environment "Variables={SLACK_BOT_TOKEN=$SLACK_BOT_TOKEN,SLACK_SIGNING_SECRET=$SLACK_SIGNING_SECRET}"

# Create an API
export api_name=TODO
aws apigatewayv2 create-api \
  --name ${api_name} \
  --protocol-type HTTP \
  --target ${func_arn}
export api_id=TODO

aws apigatewayv2 create-route \
  --route-key 'POST /slack/events' \
  --api-id ${api_id}
export route_id=TODO

aws apigatewayv2 create-integration \
  --api-id ${api_id} \
  --integration-type AWS_PROXY \
  --integration-uri=${func_arn} \
  --payload-format-version=2.0
export integration_id=TODO

aws apigatewayv2 update-route \
  --api-id ${api_id} \
  --route-id ${route_id} \
  --target integrations/${integration_id}


export statement_id=(your own random string)
export region=`aws configure list | grep region | awk '{print $2}'`
export account_id=`aws sts get-caller-identity | jq .Account | awk -F\" '{print $2}'`
export api_arn="arn:aws:execute-api:${region}:${account_id}:${api_id}/*/*/slack/events"

aws lambda add-permission \
  --statement-id ${statement_id} \
  --action lambda:InvokeFunction \
  --function-name ${func_arn} \
  --principal apigateway.amazonaws.com \
  --source-arn ${api_arn}

# Set the API Gateway Endpoint as the Request URL in Slack app configuration pages
# POST https://{api_id}.execute-api.{your region}.amazonaws.com/slack/events
from slack_bolt.adapter.aws_lambda import SlackRequestHandler
SlackRequestHandler.clear_all_log_handlers()
import logging
logging.basicConfig(format="%(asctime)s %(message)s", level=logging.DEBUG)
from slack_bolt import App, Ack
from slack_sdk.web import WebClient
# export SLACK_BOT_TOKEN=xoxb-
# export SLACK_SIGNING_SECRET=
app = App(process_before_response=True)
@app.shortcut("memo")
def handle_memo_shortcut(ack: Ack, body: dict, client: WebClient):
res = client.views_open(
trigger_id=body["trigger_id"],
view={
"type": "modal",
"callback_id": "memo-submission",
"title": {"type": "plain_text", "text": "Memo"},
"submit": {"type": "plain_text", "text": "Submit"},
"blocks": [
{
"type": "input",
"block_id": "memo",
"element": {
"action_id": "input",
"type": "plain_text_input",
"multiline": True
},
"label": {"type": "plain_text", "text": "Memo"}
},
],
},
)
ack()
def ack_view_submission(ack: Ack):
ack()
def send_dm_later(body: dict, client: WebClient):
conv = client.conversations_open(users=body["user"]["id"])
channel_id = conv["channel"]["id"]
memo = body["view"]["state"]["values"]["memo"]["input"]["value"]
client.chat_postMessage(channel=channel_id, text=memo)
app.view("memo-submission")(
ack=ack_view_submission,
lazy=[send_dm_later]
)
def handler(event, context):
slack_handler = SlackRequestHandler(app=app)
return slack_handler.handle(event, context)
if __name__ == "__main__":
app.start(3000)
slack-bolt>=0.9.3b0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment