├── NEXT_STEPS.md ├── slackbot_information_example.json ├── slackbot_commands_example.json ├── slackbot_send_message.py ├── README.md ├── slackbot_configuration_test.py ├── .gitignore └── slackbot_responding.py /NEXT_STEPS.md: -------------------------------------------------------------------------------- 1 | # NEXT_STEPS 2 | 3 | + support panic messages with a different avatar and use special notifications by default 4 | 5 | -------------------------------------------------------------------------------- /slackbot_information_example.json: -------------------------------------------------------------------------------- 1 | { 2 | "token" : "here you have to fill your token generated on Slack website", 3 | "bot_name" : "example bot name", 4 | "bot_id" : "will be filled when test_your_bot_configuration.py was executed", 5 | "avatar" : ":point_up_2:", 6 | "default_channel_send" : "channel you want to write messages to", 7 | "channels_to_read" : ["test1", "test2_without_beginning_hashTag_#"] 8 | } 9 | -------------------------------------------------------------------------------- /slackbot_commands_example.json: -------------------------------------------------------------------------------- 1 | { 2 | "bot_system_user": {"help": "Shows slack bot user on the system.", "command" : "id"}, 3 | "user_in_groups": {"help": "Shows all user and groups.", "command" : "less /etc/group"}, 4 | "w": {"help": "Shows all logged in users and what they are doing.", "command" : "w"}, 5 | "users": {"help": "Shows all logged in users.", "command" : "users"}, 6 | "disk_usage": {"help": "Shows free disk space.", "command" : "df -h"}, 7 | "hostname" : {"help": "Shows the hostname.", "command" : "hostname"}, 8 | "uptime" : {"help": "Shows the uptime.", "command" : "uptime"}, 9 | "network" : {"help": "Shows the uptime.", "command" : "ifconfig | grep -E \"(eth|inet)\""} 10 | 11 | } -------------------------------------------------------------------------------- /slackbot_send_message.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | import json 5 | 6 | from slackclient import SlackClient 7 | 8 | 9 | def transmit_message(token, transmit_channel, bot_name, avatar, message): 10 | slack_client = SlackClient(token) 11 | slack_client.api_call("chat.postMessage", 12 | channel="#" + str(transmit_channel), 13 | text=message, 14 | username=bot_name, 15 | icon_emoji=avatar) 16 | 17 | 18 | if __name__ == '__main__': 19 | file_name = sys.argv[0].split("/")[-1] 20 | path_name = sys.argv[0].split(file_name)[0] 21 | 22 | if len(sys.argv) == 2: 23 | f = open((path_name + 'slackbot_information.json'), 'r') 24 | string_bot_information = f.read() 25 | 26 | json_bot_information = json.loads(string_bot_information) 27 | 28 | # TODO follow these instructions: https://www.fullstackpython.com/blog/build-first-slack-bot-python.html to hide the key 29 | 30 | message = sys.argv[1] 31 | 32 | transmit_message(json_bot_information["token"], json_bot_information["default_channel_send"], 33 | json_bot_information["bot_name"], json_bot_information["avatar"], message) 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CADS_SLACKBOT 2 | This is CADS_SLACKBOT! 3 | 4 | ## First Steps 5 | First goal is to provide basic services, such as sending messages to a Slack channel. 6 | Be sure that your bot is a member of the specified channel. 7 | 8 | ## How to Configure 9 | ### SlackBot information 10 | Use the slackbot_information_example.json to setup your own slackbot_information.json file. 11 | The bot is using the information specified in the json file to get the wanted behaviour. 12 | 13 | ### SlackBot commands (only for slackbot_responding) 14 | Use the slackbot_commands_example.json to setup your own slackbot_commands.json file. 15 | The bot is using the commands specified in the json file to respond the way you want. 16 | The bot makes a console call and sends the response. 17 | 18 | ## Attention 19 | Make sure that you **not upload** your token! 20 | 21 | ## Examples 22 | 23 | Sending a message with the specified SlackBot. 24 | ``` 25 | python3 slackbot_send_message.py "hello from python script" 26 | ``` 27 | This posts a hello to the specified channel. 28 | 29 | The responding SlackBot could be started with: 30 | ``` 31 | python3 slackbot_responding.py 32 | ``` 33 | Now the SlackBot listens for the keywords. The keywords are specified in "slackbot_commands.json". 34 | 35 | 36 | ## Install Guide 37 | 38 | + install python3 39 | + install pip 40 | + install SlackClient, with the following command: 41 | ```` 42 | pip3 install SlackClient 43 | ```` 44 | + Clone the repository 45 | + Fill your information in a file named: "slackbot_information.json" inside of the repository. The field bot_id will be set automatically. 46 | + Run the configuration test. 47 | ```` 48 | python3 slackbot_configuration_test.py 49 | ```` 50 | + If the configuration was correct, the bot writes a message in the configured channel. 51 | + Now you can use the bot. Have a look at the example above. 52 | 53 | -------------------------------------------------------------------------------- /slackbot_configuration_test.py: -------------------------------------------------------------------------------- 1 | from slackclient import SlackClient 2 | import json 3 | import sys 4 | 5 | import slackbot_send_message as message_transmitter 6 | 7 | file_name = sys.argv[0].split("/")[-1] 8 | path_name = sys.argv[0].split(file_name)[0] 9 | slackbot_info_file = path_name + 'slackbot_information.json' 10 | 11 | f = open(slackbot_info_file, 'r') 12 | string_bot_information = f.read() 13 | f.close() 14 | 15 | ### parse jsonFile 16 | json_slack_bot_information = json.loads(string_bot_information) 17 | 18 | slack_client = SlackClient(json_slack_bot_information["token"]) 19 | response = slack_client.api_call("api.test") 20 | 21 | if response["ok"]: 22 | bot_id = 0 23 | api_call = slack_client.api_call("users.list") 24 | users = api_call.get('members') 25 | found_user = False 26 | 27 | for user in users: 28 | if 'name' in user and user.get('name') == json_slack_bot_information['bot_name']: 29 | bot_id = user.get('id') 30 | # print("Bot ID for '" + user['name'] + "' is " + user.get('id')) 31 | # get bot id and write id in config. 32 | json_slack_bot_information["bot_id"] = user.get('id') 33 | f = open(slackbot_info_file, 'w') 34 | f.write(json.dumps(json_slack_bot_information)) 35 | found_user = True 36 | 37 | if not found_user: 38 | print("Username not found: " + str(json_slack_bot_information['bot_name'])) 39 | 40 | api_call = slack_client.api_call("channels.list") 41 | found_send = False 42 | found_read = 0 43 | channels_to_read = json_slack_bot_information["channels_to_read"] 44 | channel_to_send = json_slack_bot_information["default_channel_send"] 45 | 46 | for channel in api_call["channels"]: 47 | channel_name = channel["name"] 48 | 49 | if channel_name == channel_to_send: 50 | found_send = True 51 | 52 | for read_channel in channels_to_read: 53 | if read_channel == channel_name: 54 | found_read += 1 55 | 56 | if not found_send: 57 | print("Default send channel is not correct: " + str(channel_to_send)) 58 | 59 | if len(channels_to_read) != found_read: 60 | print("Not all channels to read were found" + str(channels_to_read)) 61 | 62 | if found_user and found_send and len(channels_to_read) == found_read: 63 | message_transmitter.transmit_message(json_slack_bot_information["token"], 64 | json_slack_bot_information["default_channel_send"], 65 | json_slack_bot_information["bot_name"], 66 | json_slack_bot_information["avatar"], 67 | "Test successful passed!") 68 | 69 | else: 70 | print("Token is not correct!") 71 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/mac,macos,windows,linux,pycharm 3 | 4 | #!! ERROR: mac is undefined. Use list command to see defined gitignore types !!# 5 | **/.DS_Store 6 | slackbot_information.json 7 | slackbot_commands.json 8 | slackbot_information_save.json 9 | .idea 10 | __pycache__ 11 | 12 | 13 | ### macOS ### 14 | *.DS_Store 15 | .AppleDouble 16 | .LSOverride 17 | 18 | # Icon must end with two \r 19 | Icon 20 | 21 | 22 | # Thumbnails 23 | ._* 24 | 25 | # Files that might appear in the root of a volume 26 | .DocumentRevisions-V100 27 | .fseventsd 28 | .Spotlight-V100 29 | .TemporaryItems 30 | .Trashes 31 | .VolumeIcon.icns 32 | .com.apple.timemachine.donotpresent 33 | 34 | # Directories potentially created on remote AFP share 35 | .AppleDB 36 | .AppleDesktop 37 | Network Trash Folder 38 | Temporary Items 39 | .apdisk 40 | 41 | 42 | ### Windows ### 43 | # Windows image file caches 44 | Thumbs.db 45 | ehthumbs.db 46 | 47 | # Folder config file 48 | Desktop.ini 49 | 50 | # Recycle Bin used on file shares 51 | $RECYCLE.BIN/ 52 | 53 | # Windows Installer files 54 | *.cab 55 | *.msi 56 | *.msm 57 | *.msp 58 | 59 | # Windows shortcuts 60 | *.lnk 61 | 62 | 63 | ### Linux ### 64 | *~ 65 | 66 | # temporary files which can be created if a process still has a handle open of a deleted file 67 | .fuse_hidden* 68 | 69 | # KDE directory preferences 70 | .directory 71 | 72 | # Linux trash folder which might appear on any partition or disk 73 | .Trash-* 74 | 75 | # .nfs files are created when an open file is removed but is still being accessed 76 | .nfs* 77 | 78 | 79 | ### PyCharm ### 80 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 81 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 82 | 83 | # User-specific stuff: 84 | .idea/workspace.xml 85 | .idea/tasks.xml 86 | 87 | # Sensitive or high-churn files: 88 | .idea/dataSources.ids 89 | .idea/dataSources.xml 90 | .idea/dataSources.local.xml 91 | .idea/sqlDataSources.xml 92 | .idea/dynamic.xml 93 | .idea/uiDesigner.xml 94 | 95 | # Gradle: 96 | .idea/gradle.xml 97 | .idea/libraries 98 | 99 | # Mongo Explorer plugin: 100 | .idea/mongoSettings.xml 101 | 102 | ## File-based project format: 103 | *.iws 104 | 105 | ## Plugin-specific files: 106 | 107 | # IntelliJ 108 | /out/ 109 | 110 | # mpeltonen/sbt-idea plugin 111 | .idea_modules/ 112 | 113 | # JIRA plugin 114 | atlassian-ide-plugin.xml 115 | 116 | # Crashlytics plugin (for Android Studio and IntelliJ) 117 | com_crashlytics_export_strings.xml 118 | crashlytics.properties 119 | crashlytics-build.properties 120 | fabric.properties 121 | 122 | ### PyCharm Patch ### 123 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 124 | 125 | # *.iml 126 | # modules.xml 127 | # .idea/misc.xml 128 | # *.ipr 129 | -------------------------------------------------------------------------------- /slackbot_responding.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | import time 3 | import json 4 | import argparse 5 | import os 6 | 7 | from slackclient import SlackClient 8 | import slackbot_send_message as message_transmitter 9 | 10 | 11 | parser = argparse.ArgumentParser() 12 | parser.add_argument("--poll_time", type=int, default=1, help="Interval for the message polling") 13 | args = parser.parse_args() 14 | 15 | 16 | def evaluate_slack_text_and_react(text, responses, json_slack_bot_information): 17 | print("*************************** react **************************") 18 | print(text) 19 | to_send = "" 20 | if text['text'].find("help") != -1: 21 | to_send = "************* Help *************\n" 22 | for key in responses.keys(): 23 | to_send += "Key: " + key + " \t,HelpText: " + responses[key]["help"] +"\n" 24 | 25 | message_transmitter.transmit_message(json_slack_bot_information["token"], 26 | channel_name_dict[text['channel']], 27 | json_slack_bot_information["bot_name"], 28 | json_slack_bot_information["avatar"], 29 | to_send) 30 | return "test" 31 | 32 | # find keywords 33 | for key in responses.keys(): 34 | if text['text'].find(key) != -1: 35 | output = os.popen(responses[key]["command"]).read() 36 | print("************* " + responses[key]["command"] + "*************") 37 | to_send = "************* " + responses[key]["command"] + " *************\n" + output 38 | 39 | message_transmitter.transmit_message(json_slack_bot_information["token"], 40 | channel_name_dict[text['channel']], 41 | json_slack_bot_information["bot_name"], 42 | json_slack_bot_information["avatar"], 43 | to_send) 44 | 45 | 46 | def is_relevant_message(text): 47 | return text['type'] == 'message' and 'subtype' not in dict(text).keys() 48 | 49 | 50 | def channel_is_relevant(text, channel_id_list): 51 | return 'channel' in text and text['channel'] in channel_id_list 52 | 53 | 54 | def bot_tag_found(text, bot_id): 55 | return text['text'].find("<@" + str(bot_id) + ">", 0, len(text['text'])) != -1 56 | 57 | 58 | def create_channel_lists(channels): 59 | channel_id_list = [] 60 | channel_name_dict = {} 61 | 62 | for channel in channels: 63 | if channel['name'] in requested_channels_list: 64 | channel_id_list.append(channel['id']) 65 | channel_name_dict[channel['id']] = channel['name'] 66 | 67 | return channel_id_list, channel_name_dict 68 | 69 | 70 | def get_bot_id(slack_client, json_slack_bot_information): 71 | bot_id = -1 72 | api_call = slack_client.api_call("users.list") 73 | users = api_call.get('members') 74 | for user in users: 75 | if 'name' in user and user.get('name') == json_slack_bot_information['bot_name']: 76 | bot_id = user.get('id') 77 | print("Bot ID for '" + user['name'] + "' is " + user.get('id')) 78 | 79 | return bot_id 80 | 81 | 82 | def read_json_file(file_path): 83 | f = open(file_path, 'r') 84 | json_string = f.read() 85 | f.close() 86 | 87 | return json_string 88 | 89 | if __name__ == "__main__": 90 | poll_time = args.poll_time 91 | 92 | # read bot information 93 | string_slack_bot_information = read_json_file('slackbot_information.json') 94 | 95 | # read response information 96 | string_slack_bot_response = read_json_file('slackbot_commands.json') 97 | 98 | # parse bot information 99 | json_slack_bot_information = json.loads(string_slack_bot_information) 100 | 101 | # parse response information 102 | responses = json.loads(string_slack_bot_response) 103 | print(responses) 104 | 105 | # create SlackClient 106 | slack_client = SlackClient(json_slack_bot_information["token"]) 107 | 108 | # Get Bot ID 109 | bot_id = get_bot_id(slack_client, json_slack_bot_information) 110 | 111 | requested_channels_list = json_slack_bot_information['channels_to_read'] 112 | channel_id_list = [] 113 | channel_name_dict = {} 114 | 115 | api_call = slack_client.api_call("channels.list") 116 | channels = api_call.get('channels') 117 | 118 | channel_id_list, channel_name_dict = create_channel_lists(channels) 119 | 120 | # Poll messages 121 | if slack_client.rtm_connect(): 122 | while True: 123 | # read all inputs 124 | text_in = slack_client.rtm_read() 125 | 126 | for text in text_in: 127 | print() 128 | print("************************** NEXT ************************") 129 | print(text) 130 | 131 | if is_relevant_message(text): 132 | if channel_is_relevant(text, channel_id_list): 133 | # is message for bot 134 | if bot_tag_found(text, bot_id): 135 | #print(text['text']) 136 | evaluate_slack_text_and_react(text, responses, json_slack_bot_information) 137 | 138 | time.sleep(poll_time) 139 | 140 | else: 141 | print("Connection Failed, invalid token?") 142 | 143 | # Different way to read messages. This way is without message polling! 144 | # TODO more information on https://realpython.com/blog/python/getting-started-with-the-slack-api-using-python-and-flask/ 145 | --------------------------------------------------------------------------------