diff --git a/print_bot_id.py b/print_bot_id.py deleted file mode 100644 index 4f6688b..0000000 --- a/print_bot_id.py +++ /dev/null @@ -1,19 +0,0 @@ -import os -from slackclient import SlackClient - - -BOT_NAME = 'starterbot' - -slack_client = SlackClient(os.environ.get('SLACK_BOT_TOKEN')) - - -if __name__ == "__main__": - api_call = slack_client.api_call("users.list") - if api_call.get('ok'): - # retrieve all users so we can find our bot - users = api_call.get('members') - for user in users: - if 'name' in user and user.get('name') == BOT_NAME: - print("Bot ID for '" + user['name'] + "' is " + user.get('id')) - else: - print("could not find bot user with the name " + BOT_NAME) diff --git a/requirements.txt b/requirements.txt index 6d05ab4..cddd676 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -slackclient==1.0.0 +slackclient>=1.1.0 diff --git a/starterbot.py b/starterbot.py index 2bee625..8443527 100644 --- a/starterbot.py +++ b/starterbot.py @@ -1,57 +1,70 @@ import os import time +import re from slackclient import SlackClient -# starterbot's ID as an environment variable -BOT_ID = os.environ.get("BOT_ID") +# instantiate Slack client +slack_client = SlackClient(os.environ.get('SLACK_BOT_TOKEN')) +# starterbot's user ID in Slack: value is assigned after the bot starts up +starterbot_id = None # constants -AT_BOT = "<@" + BOT_ID + ">" +RTM_READ_DELAY = 1 # 1 second delay between reading from RTM EXAMPLE_COMMAND = "do" +MENTION_REGEX = "^<@(|[WU].+)>(.*)" -# instantiate Slack & Twilio clients -slack_client = SlackClient(os.environ.get('SLACK_BOT_TOKEN')) +def parse_bot_commands(slack_events): + """ + Parses a list of events coming from the Slack RTM API to find bot commands. + If a bot command is found, this function returns a tuple of command and channel. + If its not found, then this function returns None, None. + """ + for event in slack_events: + if event["type"] == "message" and not "subtype" in event: + user_id, message = parse_direct_mention(event["text"]) + if user_id == starterbot_id: + return message, event["channel"] + return None, None +def parse_direct_mention(message_text): + """ + Finds a direct mention (a mention that is at the beginning) in message text + and returns the user ID which was mentioned. If there is no direct mention, returns None + """ + matches = re.search(MENTION_REGEX, message_text) + # the first group contains the username, the second group contains the remaining message + return (matches.group(1), matches.group(2).strip()) if matches else (None, None) def handle_command(command, channel): """ - Receives commands directed at the bot and determines if they - are valid commands. If so, then acts on the commands. If not, - returns back what it needs for clarification. + Executes bot command if the command is known """ - response = "Not sure what you mean. Use the *" + EXAMPLE_COMMAND + \ - "* command with numbers, delimited by spaces." + # Default response is help text for the user + default_response = "Not sure what you mean. Try *{}*.".format(EXAMPLE_COMMAND) + + # Finds and executes the given command, filling in response + response = None + # This is where you start to implement more commands! if command.startswith(EXAMPLE_COMMAND): response = "Sure...write some more code then I can do that!" - slack_client.api_call("chat.postMessage", channel=channel, - text=response, as_user=True) - - -def parse_slack_output(slack_rtm_output): - """ - The Slack Real Time Messaging API is an events firehose. - this parsing function returns None unless a message is - directed at the Bot, based on its ID. - """ - output_list = slack_rtm_output - if output_list and len(output_list) > 0: - for output in output_list: - if output and 'text' in output and AT_BOT in output['text']: - # return text after the @ mention, whitespace removed - return output['text'].split(AT_BOT)[1].strip().lower(), \ - output['channel'] - return None, None + # Sends the response back to the channel + slack_client.api_call( + "chat.postMessage", + channel=channel, + text=response or default_response + ) if __name__ == "__main__": - READ_WEBSOCKET_DELAY = 1 # 1 second delay between reading from firehose - if slack_client.rtm_connect(): - print("StarterBot connected and running!") + if slack_client.rtm_connect(with_team_state=False): + print("Starter Bot connected and running!") + # Read bot's user ID by calling Web API method `auth.test` + starterbot_id = slack_client.api_call("auth.test")["user_id"] while True: - command, channel = parse_slack_output(slack_client.rtm_read()) - if command and channel: + command, channel = parse_bot_commands(slack_client.rtm_read()) + if command: handle_command(command, channel) - time.sleep(READ_WEBSOCKET_DELAY) + time.sleep(RTM_READ_DELAY) else: - print("Connection failed. Invalid Slack token or bot ID?") + print("Connection failed. Exception traceback printed above.")