3 from flask import Flask, request
5 from slackeventsapi import SlackEventAdapter
6 from slack import WebClient
7 from slack.errors import SlackApiError
8 from slack.signature import SignatureVerifier
15 slack_signing_secret = os.environ['SLACK_SIGNING_SECRET']
16 slack_bot_token = os.environ['SLACK_BOT_TOKEN']
18 slack_events = SlackEventAdapter(slack_signing_secret, "/slack/events", app)
19 signature_verifier = SignatureVerifier(slack_signing_secret)
20 slack_client = WebClient(slack_bot_token)
22 def rot_string(str, n=13):
23 """Return a rotated version of a string
25 Specifically, this functions returns a version of the input string
26 where each uppercase letter has been advanced 'n' positions in the
27 alphabet (wrapping around). Lowercase letters and any non-alphabetic
28 characters will be unchanged."""
33 result += chr(ord("A") + (ord(letter) - ord("A") + n) % 26)
38 @app.route('/rot', methods = ['POST'])
40 """Implements the /rot route for the /rot slash command in Slack
42 This implements the /rot command of our Slack bot. The format of this
43 command is as follows:
45 /rot [count|*] String to be rotated
47 The optional count indicates an amount to rotate each character in the
48 string. If the count is '*' or is not present, then the string will
49 be rotated through all possible 25 values.
51 The result of the rotation is provided as a message in Slack. If the
52 slash command was issued in a direct message, the response is made by
53 using the "response_url" from the request. This allows the bot to reply
54 in a direct message that it is not a member of. Otherwise, if the slash
55 command was issued in a channel, the bot will reply in that channel."""
57 data = request.get_data();
58 headers = request.headers;
59 response_url = request.form.get('response_url')
60 channel_name = request.form.get('channel_name')
61 channel = request.form.get('channel_id')
62 query = request.form.get('text')
64 if not signature_verifier.is_valid_request(data, headers):
65 return make_response("invalid request", 403)
67 match = re.match('^([0-9]+|\*) (.*)$', query)
70 count = int(match.group(1))
80 reply = "```/rot {} {}\n".format(count if count else '*', text)
83 reply += rot_string(text, count)
85 reply += "\n".join(["{:02d} ".format(count) + rot_string(text, count) for count in range(1,26)])
89 if (channel_name == "directmessage"):
90 resp = requests.post(response_url,
91 json = {"text": reply},
92 headers = {"Content-type": "application/json"})
93 if (resp.status_code != 200):
94 app.logger.error("Error posting request to Slack: " + resp.text)
97 slack_client.chat_postMessage(channel=channel, text=reply)
98 except SlackApiError as e:
99 app.logger.error("Slack API error: " + e.response["error"])
102 @slack_events.on("error")
103 def handle_error(error):
104 app.logger.error("Error from Slack: " + str(error))
106 if __name__ == '__main__':