def main(): sc = SlackClient(BOT_TOKEN) if sc.rtm_connect(): # print sc.server.channels bot_id = sc.server.users.find(bot).id while True: data = sc.rtm_read() if data != []: print data[0] if "type" in data[0] and data[0]["type"] == "message" and "subtype" not in data[0]: if data[0]["user"] != bot_id: text = data[0]["text"] channel_id = data[0]["channel"] channel = sc.server.channels.find(channel_id) if phrase in text: try: test = text.replace(phrase, "") result = Parser().parse(test) sc.rtm_send_message(channel.name,"Rolling a '%s' and got a result of %s"%(test,result.sum)) #TODO: Support message level saving such that a user could track history of roll except Exception as e: sc.rtm_send_message(channel.name,"ROLL FAILED: %s"%e.message) time.sleep(1) else: print "Connection Failed, invalid token?"
def slack_thread(): print "in spawned slack thread" sc = SlackClient(SLACK_TOKEN) # Join all channels chans = json.loads(sc.api_call("channels.list")) chans = chans['channels'] for chan in chans: sc.api_call("channels.join", name=chan['name']) if sc.rtm_connect(): while True: msgs = sc.rtm_read() print "Got msgs == " + str(msgs) for msg in msgs: if msg.get('ok') is not None: print "Server acknowledged our message: " + str(msg) elif msg.get('type') is not None: if msg['type'] == 'hello': print "Server said hello: " + str(msg) elif msg['type'] == 'channel_created': print "Channel created: " + str(msg) print sc.api_call("channels.join", name=msg['channel']['name']) elif msg['type'] == 'message': print "Got a message: " + str(msg) sc.rtm_send_message(msg['channel'], str(msg)) else: print "Got RTM message with unknown type field: " + str(msg) else: print "Unknown message format in RTM: " + str(msg) gevent.sleep(1) else: print "Connection Failed, invalid token?"
def main(self): token = os.environ.get("SLACK_TOKEN") slack_client = SlackClient(token) if slack_client.rtm_connect(): while True: new_evts = slack_client.rtm_read() for evt in new_evts: #print evt if 'type' in evt: if str(evt["type"]) == "message" and "text" in evt: # this is where the logic for the human input text is placed. # we also get more information from the JSON keyword = True channel = evt['channel'] response = evt['text'] print response elif 'reply_to' in evt: #this is where the logic for the chat bot is placed. slack_client.rtm_send_message('This is where the messages will go', 'Hello World') else: print "Failed."
def handle_event(event: dict, channel: str, channel_id: str, message: str, sc: SlackClient, logger: logging.Logger) -> None: pretty_event = pformat(event) logger.debug(f"Event received:\n{pretty_event}") subtype = event.get('subtype') user = event.get('user') if subtype in ('group_join', 'channel_join') and user: # We will use the event's channel ID to send a response and refer to # users by their display_name in accordance with new guidelines. # https://api.slack.com/changelog/2017-09-the-one-about-usernames event_channel_id = event.get('channel') user_profile = event.get('user_profile') username = user_profile.get('display_name') user_mention = f"<@{user}>" message = message.replace('{user}', user_mention) if event_channel_id == channel_id: try: sc.rtm_send_message(event_channel_id, message) logger.info(f"Welcomed {username} to #{channel}") except AttributeError: logger.error(f"Couldn't send message to #{channel}")
def main(): token = tokens.token client = SlackClient(token) if client.rtm_connect(): channel = raw_input("Channel name: ") while True: message = raw_input("Message: ") client.rtm_send_message(channel, message) else: print "Connection Failed."
class PeckBot(object): def __init__(self, token, timeout): print('[INFO] Initializing bot...') self.token = token self.client = SlackClient(token) self.timeout = timeout self.userid = 'U04U7K4HC' self.responses = [ ('^!reddit ([a-zA-Z0-9]+)', RedditBehavior()), ('^!chat (.*)$', CleverBotBehavior()), ('^!doc$', DocBehavior()), ('^!quote ?(.*)$', QuoteBehavior()), ('^!trivia ?(.*)$', TriviaBehavior()), ('(.+)', NonsensSpewingBehavior()), ('.+', NonsensTrainingBehavior()) ] print('[INFO] Init done.') def connect(self): return self.client.rtm_connect() def send_msg(self, msg, channel): self.client.rtm_send_message(channel, msg) self.pause() def pause(self): time.sleep(self.timeout) def run(self): print('[INFO] PeckBot is running') while True: events = self.client.rtm_read() for event in events: if 'type' in event and event['type'] == 'message': if 'user' in event and event['user'] != self.userid: self.respond(event) self.pause() def respond(self, event): for resp in self.responses: regex, behavior = resp matches = re.findall(regex, event['text']) try: channel_name = json.loads(self.client.api_call('channels.info', channel=event['channel']))['channel']['name'] except KeyError: channel_name = event['channel'] for match in matches: print('[INFO] Triggered {0} on #{1}'.format(behavior.name, channel_name)) try: behavior.execute(self, match, event) except Exception as e: print('[ERROR] {0} failed: {1}'.format(behavior.name, e)) if len(matches) > 0: break
def handle(self, *args, **options): team = Team.objects.first() client = SlackClient(team.bot_access_token) if client.rtm_connect(): while True: events = client.rtm_read() print("%s----%s" % (team, events)) for event in events: if 'type' in event and event['type'] == 'message' and event['text'] == 'hi': client.rtm_send_message(event['channel'], "hello world") elif 'type' in event and event['type'] == 'message' and event['text'] == 'who': client.rtm_send_message(event['channel'], "I'am Groot") time.sleep(1)
def send_message(): channel = request.form['channel'] message = request.form['message'] access_token = request.form['access_token'] #Ideally, the only parameters taken would be origin user + message. This can be worked on in a further iteration. sc = SlackClient(access_token) sc.rtm_connect() sc.rtm_send_message(channel=channel, message=message) return "Success"
class Connection: dict = {} sc = None summ = None names = {} def read(self,token): self.sc = SlackClient(token) if self.sc.rtm_connect(): start = time.time() while True: try: str = self.sc.rtm_read() if str and ('text' in str[0]) and ('reply_to' not in str[0]): # if str is not null key = str[0].get('text') user = str[0].get('user') info = self.sc.api_call('users.info', user= user) if user not in self.dict: user_name = info.get('user').get('name') self.names[user_name] = user self.dict[user] = [] self.dict[user].append(float(key)) self.dict[user].append(1) self.dict[user].append(float(key)) print(float(key)) else: self.dict[user][0] += float(key) self.dict[user][1] += 1 print(float(self.dict[user][0])/self.dict[user][1]) self.dict[user][2] = self.dict[user][0]/self.dict[user][1] count , avg = 0,0 for key, value in self.dict.items(): avg += float(self.dict[key][0]) count += self.dict[key][1] self.summ = avg/count time.sleep(1) end = time.time() if(end - start >= 60): start = time.time() for key, value in self.dict.items(): avg += float(self.dict[key][0]) count += self.dict[key][1] str = "{:.9f}".format(avg/count) self.sc.rtm_send_message("general", str) count , avg = 0,0 else: time.sleep(1) except Exception as e: print("Exception: ", e.message)
class StandupBot: def __init__(self, token): self.token = token self.slack_client = None self.standup = None self.last_ping = 0 self.keepalive_timer = 3 print("Standup Bot initialized.") def connect(self): self.slack_client = SlackClient(self.token) self.slack_client.rtm_connect() def keepalive(self): now = int(time.time()) if now > self.last_ping + self.keepalive_timer: self.slack_client.server.ping() self.last_ping = now def start(self): self.connect() while True: for response in self.slack_client.rtm_read(): self.response_handler(response) self.keepalive() time.sleep(.5) def message_handler(self, channel, message): if "!standup" in message: # check to see if self.Standup is already initialized, and if so, if the standup is already started. if self.standup is None: self.slack_client.rtm_send_message(channel=channel, message="Hello <!channel>, it's time for Standup!") self.standup = Standup(channel, self.slack_client) elif self.standup is not None & self.standup.status is "INITIALIZED": self.slack_client.rtm_send_message([channel, "I will restart the meeting."]) self.standup = Standup(channel, self.slack_client) elif "!start" in message: if self.standup is not None: self.standup.start_standup() def response_handler(self, response): print(response) if "type" in response and "subtype" not in response: if "message" in response["type"]: self.message_handler(channel=response["channel"], message=response["text"])
class SlackBot(object): def __init__(self, bot_id, debug=False): self.sc = SlackClient(bot_id) self.user = "" self.connect = self.sc.rtm_connect() self.debug = debug self.threads = [] t = threading.Thread(target=self.watch_message) self.threads.append(t) t.start() self.handlers = [] def add_handler(self, msg, reply, run=None, con=True): handler = SlackHandler(msg, run, con) self.handlers.append(handler) def watch_message(self): if self.connect: self.sc.server.login_data["self"]["id"] while True: message = self.sc.rtm_read() if message and message[0]["type"] == "message" and message[0]["user"] != self.user: #There is a message from a user text = message[0]["text"] if self.debug: print("Message - " + text) self.parse_message(text, message[0]["channel"]) time.sleep(1) def parse_message(self, message, channel): for handler in self.handlers: if handler.con: if handler.message in message: if handler.run != None: if self.debug: print("Excuting - " + str(handler.run)) try: handler.run() except: print("Exception during handler function") self.sc.rtm_send_message(channel, message) elif handler.message == message: handler.run()
class Bot: def __init__(self, token): self.token = token print("Bot instantiated. My token is: "+self.token+".") def connect(self): print("Connecting with token: "+self.token+"...") self.client = SlackClient(self.token) self.client.rtm_connect() is_ok = self.client.api_call("api.test") is_ok = is_ok["ok"] if is_ok == True: print("Connection established!") else: print("Error code : 1. Connection failure. Check access token?") sys.exit() def print_chat(self, msg, channel): self.client.rtm_send_message(channel, msg) def read_msg(self): msg = self.client.rtm_read() if len(msg) > 0: msg = msg[0] if "type" in msg: if msg["type"] == "message": return msg return [] else: return [] def hello(self): self.client.api_call("chat.postMessage", token=self.token, channel="#general", text="Hello World", as_user=True) def id2name(self, id): users = self.client.api_call("users.list", token=self.token) users = users["members"] for user in users: if user["id"] == id: username = user["name"] return "@"+username
def main(config): init_log(config) hooks = init_plugins("plugins") client = SlackClient(config["token"]) if client.rtm_connect(): users = client.server.users while True: events = client.rtm_read() for event in events: logging.debug("got {0}".format(event.get("type", event))) response = handle_event(client, event, hooks, config) if response: client.rtm_send_message(event["channel"], response) time.sleep(1) else: logging.warn("Connection Failed, invalid token <{0}>?".format(config["token"]))
def slackbot_msg(message, channel=SLACK_CHANNEL): ''' Usage: slackbot_msg(msg, channel) Before: msg is a string containing message we want to send to slack, channel is the name of the channel we want to post to, if it is not provided the default channel from config will be used After: message has been sent to slack Note: this may fail silently (prints warning) if connecting to slack fails. ''' if ACT_LIKE_ROBOT: message = message.upper() sc = SlackClient(SLACKBOT_TOKEN) if sc.rtm_connect(): sc.rtm_send_message(channel, message) else: print 'Warning: slackbot_msg() failed, invalid token?'
def be_wise(config, quotes, stopwords): slack_client = SlackClient(config['token']) slack_client.rtm_connect() user_id = get_user_id(slack_client, config['name']) mention_string = '@%s' % user_id while True: messages = slack_client.rtm_read() messages = filter(lambda m: m['type'] == 'message', filter(lambda m: 'type' in m, messages)) if len(messages) > 0: for message in messages: if mention_string in message['text']: sentence = message['text'][len(user_id)+3:] quote = find_quote(sentence, quotes, stopwords) name = get_user_name(slack_client, message['user']) response = '<@%s>: %s says: "%s"' % (name, quote.author, quote.sentence) slack_client.rtm_send_message(message['channel'], response) time.sleep(1)
def run(Salute): slack_client_instance=SlackClient(api_token) if slack_client_instance.rtm_connect(): slack_client_instance.rtm_send_message(channel_name, "Am here for your daily stand ups say 'go' !") while True: for slack_message in slack_client_instance.rtm_read(): message=slack_message.get("text") user=slack_message.get("user") if not message or not user: continue slack_client_instance.rtm_send_message(channel_name,"<@{}> ".format(user)) slack_client_instance.rtm_send_message(channel_name, message) print(message) if message=="go": slack_client_instance.rtm_send_message(channel_name, "what did you do yesterday?") else: slack_client_instance.rtm_send_message(channel_name, "I did not quite get that! Say 'go' to continue") time.sleep(0.5)
def create_bot(): token = open("token.txt") sc = SlackClient(token) sc.rtm_connect() while True: new_evts = sc.rtm_read() for evt in new_evts: print(evt) if "type" in evt: if evt["type"] == "message" and "text" in evt: message = evt["text"] channel = evt["channel"] print(message) if "점심메뉴" in message or "십밥" in message or "10층" in message or "10밥" in message: sc.rtm_send_message(channel=channel, message=get_menu()) elif "명령어" in message: sc.rtm_send_message(channel=channel, message="10밥봇 명령어 : 점심메뉴, 십밥, 10층, 10밥") time.sleep(.1)
class Bot: def __init__(self, token): self.client = SlackClient(token) self.im_ids = [] self.last_ping = time.time() def start(self): self.client.rtm_connect() self.im_ids = self.get_im_ids() while True: for r in self.client.rtm_read(): if 'type' not in r: pass elif r['type'] == 'message': self.process_message(r) elif r['type'] == 'im_created': self.im_ids = self.get_im_ids() self.ping() time.sleep(0.2) def process_message(self, r): if 'subtype' in r or 'reply_to' in r: return if r['channel'] in self.im_ids or self.is_bot_mentioned(r['text']): self.client.rtm_send_message(r['channel'], r['text']) def is_bot_mentioned(self, msg): bot_id = self.client.server.login_data['self']['id'] bot_mentioned = '<@{}>'.format(bot_id) return bot_mentioned in msg def get_im_ids(self): return [x['id'] for x in self.client.api_call('im.list')['ims']] def ping(self): now = int(time.time()) if now > self.last_ping + 3: self.client.server.ping() self.last_ping = now
class Hackbot(object): """ An instance of Hackbot, the Hackbright XI Slack bot. Also known as Balloonicorn. """ def __init__(self, token): self.token = token self.client = None def connect(self): """Set up SlackClient and connect to Real Time Messaging API. The RTM sets up a continuous websocket connection, from which you can read and respond to events in real time without without making a full HTTPS request. """ self.client = SlackClient(self.token) self.client.rtm_connect() def read(self): """ Read all events from Real Time Messaging API. Checks if balloonicorn is mentioned. """ while True: for response in self.client.rtm_read(): print response if response.get('type') == 'message': message = response.get('text') if 'balloonicorn' in message: channel = response.get('channel') self.reply(message, channel) time.sleep(1) def reply(self, message, channel): """ When balloonicorn is mentioned, returns a random choice from a list of reponses. """ if reply = random.choice(['Hi there!', 'Yes?', ';)']) self.client.rtm_send_message(channel, reply)
class slackbot(object): # a class for fun slackbots def __init__(self, token): self.token = token self.slack_client = None def connect(self): # setup the SlackClient and connect to the RTM API self.slack_client = SlackClient(self.token) self.slack_client.rtm_connect() def get_events(self): # get all events from the RTM API # Is drunkoctopus or a keyword mentioned? while True: new_evts = self.slack_client.rtm_read() for evt in new_evts: print evt if evt.get('type') == 'message': message = evt.get('text') if 'catbot' in message: channel = evt.get('channel') self.reply(message, channel) time.sleep(1) def reply(self, message, channel): # when drunkoctopus is mentioned, return a message # look message words up in the drunkoctopus dictionary if "STAT" in message: reply = "DON'T RUSH CATS" self.slack_client.rtm_send_message(channel, reply) return else: reply = random.choice(imageList) self.slack_client.rtm_send_message(channel, reply) return
def main(): # Create the slackclient instance sc = SlackClient(BOT_TOKEN) # Connect to slack if sc.rtm_connect(): # Send first message sc.rtm_send_message(CHANNEL_NAME, "I'm ALIVE!!!") while True: # Read latest messages for slack_message in sc.rtm_read(): message = slack_message.get("text") user = slack_message.get("user") if not message or not user: continue sc.rtm_send_message(CHANNEL_NAME, "<@{}> wrote something...".format(user)) # Sleep for half a second time.sleep(0.5) else: print("Couldn't connect to slack")
def main (): controller = Controller() token = "" sc = SlackClient(token) if sc.rtm_connect(): while True: events = [] events = sc.rtm_read() if (events != []): print (events) for event in events: if (event.get('type', None) == 'message' and event.get('team', None) is not None): ans = controller.evaluateInput(event.get('text', 'None')) sc.rtm_send_message(event['channel'], ans) pass time.sleep(1) else: print ("Connection Failed, invalid token?")
def main(): client = SlackClient(token) logger.info(client.api_call('api.test')) if client.rtm_connect(): while True: new_events = client.rtm_read() for event in new_events: if 'type' in event and 'text' in event and 'channel' in event and 'user' in event and event['type'] == 'message': msg = event['text'] if msg.split()[0] == 'helpy': logger.info('channel: ' + event['channel'] + ', user:'******'user'] + ', msg:' + event['text']) query = ' '.join(msg.split()[1:]) try: head, desc, link = search(query) resp = "*{}*\n>{}{}".format(head, desc, '\n' + link if link is not None else '') client.rtm_send_message(event['channel'], resp) except Exception as e: logger.error('Runtime Error:') logger.error(e) time.sleep(1) else: logger.error("Could not connect!")
def main(): """ Creates a Slack client. If the client has connected the program enters into an infinite loop. Check for any new events with SlackClient.rtm_read(). Iterate through the new events If the event is a message, and the first word in the text is 'echo' Then the client sends the message back to the channel At the end of each loop, the client waits 1 second to prevent spamming the Slack """ client = SlackClient(token) if client.rtm_connect(): while True: new_events = client.rtm_read() for event in new_events: if event.get('type') == 'message': msg = event['text'] if len(msg) > 0 and msg.split()[0] == 'echo': response = ' '.join(msg.split()[1:]) client.rtm_send_message(event['channel'], response) time.sleep(1)
def main(): slack_client_instance=SlackClient(api_token) if slack_client_instance.rtm_connect(): slack_client_instance.rtm_send_message(channel_name, "Am here to find you a tech date !") while True: for slack_message in slack_client_instance.rtm_read(): message=slack_message.get("text") user=slack_message.get("user") if message=="go": message="please tell me your gender" slack_client_instance.rtm_send_message(channel_name, message) gender=slack_message.get("text`") if not message or not user: continue slack_client_instance.rtm_send_message(channel_name,"<@{}> ".format(user)) slack_client_instance.rtm_send_message(channel_name, message) time.sleep(0.5)
#!/usr/bin/env python # -*- coding: utf-8 -*- import random from slackclient import SlackClient import time #get your personal token from https://api.slack.com/web, bottom of the page. api_key = '' client = SlackClient(api_key) if client.rtm_connect(): while True: last_read = client.rtm_read() if last_read: try: parsed = last_read[0]['text'] #reply to channel message was found in. message_channel = last_read[0]['channel'] if parsed and 'food:' in parsed: choice = random.choice(['hamburger', 'pizza']) client.rtm_send_message(message_channel, 'Today you\'ll eat %s.' % choice) except: pass time.sleep(1)
def rtm(token, queue, workspace, workspace_token): sc = SlackClient(workspace_token) print('rtm start for ', workspace) room_parking_channel = None @MSGRAPH.tokengetter def get_token(): """Called by flask_oauthlib.client to retrieve current access token.""" return (token, '') # create member dict members = list() slack_api_members = sc.api_call('users.list')['members'] for x in slack_api_members: name = x['profile']['display_name'] if x['profile'][ 'display_name'] else x['profile']['real_name'] query_res = Member.get_by_user_workspace(x['id'], workspace) if query_res: member = query_res else: member = Member(name, x['profile']['real_name'], x['id'], workspace) member.add() members.append(member) for x in members: if x.display_name == 'roomparking': room_parking_channel = x.user_id print(room_parking_channel) elif not x.channel_id: res = sc.api_call('conversations.open', users=x.user_id) if not res.get('error', None): x.channel_id = res['channel']['id'] x.update() channel_members = dict() for x in members: if x.channel_id: channel_members[x.channel_id] = x with APP.test_request_context(): if sc.rtm_connect(): while True: try: res = sc.rtm_read() # processing, etc except (WebSocketConnectionClosedException, TimeoutError) as e: print('Connecitons was closed. Restarting.') print(e.args) sc.rtm_connect() continue if not queue.empty(): server_token = queue.get() print('token', server_token) member = channel_members.get(server_token['channel'], False) if server_token['status'] == 'error' or ( not server_token.get('access_token', False)) or ( not server_token.get('refresh_token', False)): sc.rtm_send_message( server_token['channel'], 'Sorry there was a problem please try again.') if member and workspace == server_token['workspace']: member.token = server_token['access_token'] member.refresh_token = server_token['refresh_token'] member.expires = server_token['expires'] print('expires', member.expires, ' ', member.display_name) member.update() sc.rtm_send_message( member.channel_id, 'Successful authentication! \n {0}'.format( GREETING_TEXT)) print('authorized') else: print('not my token') queue.put(server_token) time.sleep(2) if len(res) > 0 and type(res[0].get('channel', None)) is not str: print('res', res) continue # if len(res) > 0: # print(res) if len(res) > 0 and res[0].get( 'channel', None) in channel_members.keys() and res[0].get( 'type', None) == 'message' and res[0].get( 'user', None) != room_parking_channel: member = channel_members[res[0].get('channel', None)] # sc.rtm_send_message(member.channel_id, '{0}, {1}, {2}, {3}'.format(member.expires, utc.localize(member.expires),(datetime.now(utc)+timedelta(hours=1)), eastern.localize(member.expires)<=(datetime.now(utc)+timedelta(hours=1)))) if not res[0].get('text', False) or res[0].get( 'subtype') and res[0]['subtype'] == 'bot_message': continue if res[0]['text'].lower() == 'delete token': member.token = None member.refresh_token = None member.expires = None member.update() if member.token and member.expires and utc.localize( member.expires) <= datetime.now(utc): print('checking for new token') if not check_token(member): sc.rtm_send_message( member.channel_id, 'Couldn\'t update token. Please login again.') else: print('updated token! for ', member.display_name) # sc.rtm_send_message(member.channel_id, 'updated token succesfully.') if not member.token: sc.rtm_send_message( member.channel_id, 'Hello, {name}! This is the Room Booking app for Bloomberg Center at CornellTech.\n' 'It can help you quickly book any room for the next hour. This app will create new meeting on your calendar and invite the selected room. \n' 'To continue please authorize with your Cornell Office 365 account: \n Click here: {ip}?channel={channel}&workspace={workspace} \n' 'Use your Cornell Email ([email protected]).'. format(name=member.first_name, ip=SERVER_IP, channel=member.channel_id, workspace=workspace)) else: token = member.token print('booking for ', member.display_name) member_state = None if member.state: member_state = json.loads(member.state) if member_state and member_state['state'] == 'cancel': try: words = res[0]['text'] if words == 'exit': member.state = None member.update() sc.rtm_send_message( member.channel_id, GREETING_TEXT) continue elif int(words) in range( 1, len(member_state['data']) + 1): event = member_state['data'][int(words) - 1] # sc.rtm_send_message(member.channel_id, event['id']) res = MSGRAPH.delete( 'me/events/' + event['id'], data=None, format='json', headers=request_headers()) if res.status == 204: sc.rtm_send_message( member.channel_id, 'Successfully deleted meeting.') member_state['data'].pop( int(words) - 1) response_res = list() if len(member_state['data']) > 0: for pos, x in enumerate( member_state['data']): response_res.append( '{4}. Meeting at {0}. Starting at {1} until {2} (timezone: {3})' .format( x['location'], x["start"], x["end"], x['timeZone'], pos + 1)) sc.rtm_send_message( member.channel_id, 'Here are the remaining meetings found for your account: \n {0} \n. Please respond with position of the meeting. Ex: ```1``` If only one meeting is presented, please still type: 1.\nTo exit cancellation submenu type ```exit```' .format( '\n'.join(response_res))) else: sc.rtm_send_message( member.channel_id, 'Returning back to the main menu.' ) member_state = None sc.rtm_send_message( member.channel_id, GREETING_TEXT) else: sc.rtm_send_message( member.channel_id, 'Error deleting meeting:') sc.rtm_send_message( member.channel_id, res.data) else: raise ValueError( 'Please put number from 1 to {0}.'. format(len(member_state['data']))) member.state = json.dumps( member_state) if member_state else None member.update() except Exception as e: print(e) sc.rtm_send_message(member.channel_id, e.args[0]) sc.rtm_send_message( member.channel_id, 'Wrong command. Try: ```exit``` or ```1```' ) else: try: ### autocomplete time time_start = datetime.now(eastern) if time_start.minute >= 20 and time_start.minute < 50: time_start = time_start.replace( microsecond=0, second=0, minute=30, tzinfo=None) elif time_start.minute >= 50: time_start = time_start.replace( microsecond=0, second=0, minute=0, hour=time_start.hour + 1, tzinfo=None) else: time_start = time_start.replace( microsecond=0, second=0, minute=0, tzinfo=None) time_end = time_start + timedelta(hours=1) ### over words = res[0]['text'].split() if words[0].lower() == 'help': sc.rtm_send_message( member.channel_id, GREETING_TEXT) elif words[0].lower() == 'where': if len(words) > 1 and words[1] in room_no: sc.rtm_send_message( member.channel_id, 'https://roomparking.cornelltech.io/rooms/{0}.jpg' .format(words[1])) else: sc.rtm_send_message( member.channel_id, 'Wrong input. Try ```where 375```') elif words[0].lower() == 'cancel': msft_resp = MSGRAPH.get( "me/events", headers=request_headers()).data # print(msft_resp) meetings_by_bot = list() if len(msft_resp.get('value', list())) > 0: for x in msft_resp['value']: end_date_time = eastern.localize( dateutil.parser.parse( x['end']['dateTime'])) if x['bodyPreview'] == "This event is created by RoomParking Slackbot, " \ "contact Eugene ([email protected]) for help." and end_date_time > datetime.now(eastern): meetings_by_bot.append( get_meeting_info(x)) sc.rtm_send_message( member.channel_id, get_meeting_info(x)) # print(x) if len(meetings_by_bot) > 0: dumped_state = json.dumps({ 'state': 'cancel', 'data': meetings_by_bot }) if len(dumped_state) > 3000: raise ValueError( 'Sorry there are too many meetings created that we can\'t handle at once please delete them manually.' ) member.state = dumped_state member.update() response_res = list() for pos, x in enumerate( meetings_by_bot): response_res.append( '{4}. Meeting at {0}. Starting at {1} until {2} (timezone: {3})' .format( x['location'], x["start"], x["end"], x['timeZone'], pos + 1)) sc.rtm_send_message( member.channel_id, 'Here are the meetings found for your account: \n {0} \nPlease respond with the position of the meeting. Ex: ```1``` If only one meeting present, please still type: 1. To exit the cancelling submenu type exit.' .format('\n'.join(response_res))) print(meetings_by_bot) sc.rtm_send_message( member.channel_id, meetings_by_bot) else: sc.rtm_send_message( member.channel_id, 'No meetings created by our bot has been found for your account. Book some now! ' ) elif words[0].lower() == 'list': if len(words[1]) > 1: floor = int(words[1][0]) else: floor = int(words[1]) if floor not in [0, 1, 2, 3, 4]: raise ValueError( 'Floor is wrong. Use: 0, 1, 2, 3, 4' ) sc.rtm_send_message( member.channel_id, 'Looking for available rooms...') rooms = get_available_by_floor( floor, MSGRAPH, time_start, time_end) if rooms['result'] == 'success': if rooms['data']: sc.rtm_send_message( member.channel_id, 'Available rooms on floor #{0}: \n {1}. \n (VC - Video Conferencing, D - Display)' .format( floor, ','.join(rooms['data'])) ) # \n\nCheck Michael Wilber\'s nice visualization of available rooms: https://cornell-tech-rooms.herokuapp.com else: sc.rtm_send_message( member.channel_id, 'There are no available rooms on floor #{0}' .format(floor)) else: if rooms['data']['error'][ 'message'] == 'Access token has expired.': member.token = None member.refresh_token = None member.update() sc.rtm_send_message( member.channel_id, 'Token is expired, please login again.' ) else: sc.rtm_send_message( member.channel_id, rooms['data']) continue elif words[0].lower() == 'book': if len(words) == 1: sc.rtm_send_message( member.channel_id, 'Please specify room number, like: "book 375".' ) continue if len(words) == 3: time_new = words[2] if 'pm' == time_new[-2:]: time_hour = int(time_new[:-2]) + 12 elif 'am' == time_new[-2:]: time_hour = int(time_new[:-2]) else: raise ValueError( 'If you want to specify time for booking. Follow this example: ```book 375 11am``` or ```book 375 2pm``` The room will be booked for one hour starting the time you posted.' ) # sc.rtm_send_message(member.channel_id, time_start.isoformat()) # sc.rtm_send_message(member.channel_id, time_end.isoformat()) time_start = time_start.replace( microsecond=0, second=0, minute=0, hour=time_hour, tzinfo=None) time_end = time_start + timedelta( hours=1) # sc.rtm_send_message(member.channel_id, time_start.isoformat()) # sc.rtm_send_message(member.channel_id, time_end.isoformat()) room = words[1] print(room) room_full = get_room_by_no(room) if not room_full: sc.rtm_send_message( member.channel_id, 'Room not found. Try "list {floor_id}" to get rooms.' ) continue if room == '367': sc.rtm_send_message( member.channel_id, 'Somehow room 367 cannot be booked. It is not in the Outlook Calendar. I will raise a ticket to IT about it. \n Eugene' ) continue available = is_available_now( room_full, time_start, time_end) if available['result'] == 'success': if not available['data']: sc.rtm_send_message( member.channel_id, 'Room is already occupied!') sc.rtm_send_message( member.channel_id, available) continue else: book_json = create_booking_json( user=member.first_name, room=room_full, time_start=time_start. isoformat(), time_end=time_end.isoformat()) msft_resp = MSGRAPH.post( "me/calendar/events", data=book_json, format='json', headers=request_headers()).data if msft_resp.get('error'): raise SystemError(msft_resp) print(msft_resp) sc.rtm_send_message( member.channel_id, 'The room {4} is booked from {0}:{1:02d} to {2}:{3:02d}.' .format( time_start.hour, time_start.minute, time_end.hour, time_end.minute, room)) else: if available[ 'data'] == 'Access token has expired.': member.token = None member.expires = None member.refresh_token = None member.update() sc.rtm_send_message( member.channel_id, 'Token is expired, please login again.' ) else: sc.rtm_send_message( member.channel_id, available['data']) else: raise ValueError( 'No commands were matched.') # find_room_json(words[1], str()) except Exception as e: print(e) sc.rtm_send_message(member.channel_id, e.args[0]) sc.rtm_send_message( member.channel_id, 'Try: ```help``` or ```book 397``` or ```list 4``` or ```book 375 2pm```' ) else: print("Connection Failed")
class Client: METHOD_GET_USER_INFO = 'users.info' METHOD_AUTH_TEST = 'auth.test' METHOD_DELETE_MSG = 'chat.delete' METHOD_GET_CHANNEL_INFO = { Channel.TYPE_CHANNEL: 'channels.info', Channel.TYPE_GROUP: 'groups.info' } METHOD_GET_HISTORY = { Channel.TYPE_CHANNEL: 'channels.history', Channel.TYPE_GROUP: 'groups.history', Channel.TYPE_DIRECT: 'im.history', } users = {} channels = {} def __init__(self, api_key): self._client = SlackClient(api_key) self._logger = logging.getLogger(__name__) self._me = None def connect(self): self._client.rtm_connect() def send_message(self, channel, text): self._logger.debug('Sent message "%s" to channel "%s"' % (text, channel)) self._client.rtm_send_message(channel.id, text) def ping(self): self._client.server.ping() def get_user(self, id, force=False): if not id in self.users or force: response = self.call_method(Client.METHOD_GET_USER_INFO, user=id) if response: self.users[id] = User(response['user']) else: self._logger.warn('Could not fetch info for user "%s".' % id) return None return self.users[id] def get_me(self): if not self._me: response = self.call_method(Client.METHOD_AUTH_TEST) if response: self._me = self.get_user(response['user_id']) else: return None return self._me def get_channel(self, id): if id not in self.channels: type = Channel.get_channel_type(id) if type == Channel.TYPE_DIRECT: self.channels[id] = Channel({'id': id}) return self.channels[id] elif type == Channel.TYPE_GROUP: data_key = 'group' elif type == Channel.TYPE_CHANNEL: data_key = 'channel' response = self.call_method(self.METHOD_GET_CHANNEL_INFO[type], channel=id) if response: self.channels[id] = Channel(response[data_key]) else: self._logger.warn('Could not fetch info for channel "%s".' % id) return None return self.channels[id] def get_channel_history(self, channel): response = self.call_method(self.METHOD_GET_HISTORY[channel.type], channel=channel.id) if not response: return None return response['messages'] def delete_message(self, channel, timestamp): self.call_method(self.METHOD_DELETE_MSG, channel=channel.id, ts=timestamp) def call_method(self, method, **kwargs): response = json.loads( self._client.api_call(method, **kwargs).decode('utf-8')) if not 'ok' in response or not response['ok']: if 'error' in response: self._logger.warn('API call "%s" failed: %s.' % (method, response['error'])) else: self._logger.warn('API call "%s" failed.' % method) return None return response def process_special_event(self, event): if 'user' in event.data and isinstance(event.data['user'], dict): new_user = User(event.user) event.data['user'] = new_user self.users[new_user.id] = new_user if 'channel' in event.data and isinstance(event.data['channel'], dict): new_channel = Channel(event.channel) event.data['channel'] = new_channel self.channels[new_channel.id] = new_channel def read_events(self): events = [] try: event_datas = self._client.rtm_read() except BlockingIOError: self._logger.debug('Socket is blocked (by another thread?)...') return [] for event_data in event_datas: self._logger.debug('Read event: ' + str(event_data)) if not 'type' in event_data: continue event = Event.create(self, event_data) self.process_special_event(event) # store messages in the channel buffer if isinstance(event, Message) and event.is_plain(): event.channel.store_message(event) self._logger.debug('Event parsed:\n' + str(event)) events.append(event) return events
message = response['text'] user = get_dict_item(users, response['user'], sc.server.users).name channel = get_dict_item(channels, response['channel'], sc.server.channels).name domain = get_dict_item(channels, response['channel'], sc.server.channels).server.domain except: continue print "%s (%s/%s) -- %s" % (user, domain, channel, message) loud_response = louds.add(message, user, domain, channel) if loud_response: sc.rtm_send_message(response['channel'], loud_response) print " -- %s" % loud_response command_response = louds.do_commands(message,user,domain,channel) if command_response: sc.rtm_send_message(response['channel'], command_response) print " -- %s" % command_response time.sleep(1) else: print "Can't connect to Slack?!?"
class RepInstance( object ): def __init__( self, actor, oid, apiToken, botToken ): self.actor = actor self.oid = oid self.apiToken = apiToken self.botToken = botToken self.slack = Slacker( self.apiToken ) self.bot = SlackClient( self.botToken ) self.botId = None self.invId = str( uuid.uuid4() ) self.taskId = 0 self.slackLinkRE = re.compile( r'<.+://.+\|(.+)>' ) resp = self.actor.huntmanager.request( 'reg_inv', { 'uid' : self.actor.name, 'name' : self.invId } ) if not resp.isSuccess: raise Exception( 'failed to register investigation id for tasking: %s' % resp ) self.history = { 'last_cmd' : [] } self.makeChannel( '#detects' ) if not self.bot.rtm_connect(): raise Exception( 'failed to connect bot to Slack rtm API' ) self.actor.newThread( self.botThread ) def botThread( self, stopEvent ): try: # Get our ID api_call = self.bot.api_call( "users.list" ) if api_call.get( 'ok' ): for user in api_call.get( 'members' ): if user.get( 'name', '' ) == self.bot.server.username: self.botId = user.get( 'id' ) break self.actor.log( "found our id %s for %s" % ( self.botId, self.bot.server.username ) ) self.bot.rtm_send_message( '#general', 'Reporting in.' ) while not stopEvent.wait( 1.0 ): for slackMessage in self.tryToRead(): message = unicode( slackMessage.get( 'text' ) ) fromUser = slackMessage.get( 'user' ) channel = slackMessage.get( 'channel' ) if not message or not fromUser or ( '<@%s>' % self.botId ) not in message: continue # Fixing silly quotes form unicode to ascii message = message.replace( u'\u201c', '"' ) message = message.replace( u'\u201d', '"' ) try: ctx = CommandContext( channel, fromUser, [ self.stripSlackFormatting( x ) for x in shlex.split( message.replace( '<@%s>' % self.botId, '' ) ) ], copy.deepcopy( self.history ) ) except: self.bot.rtm_send_message( channel, "error parsing command `%s`: %s" % ( message, traceback.format_exc(), ) ) self.actor.newThread( self.executeCommand, ctx ) except: self.actor.log( "Excp: %s while parsing %s" % ( traceback.format_exc(), message ) ) self.bot.rtm_send_message( "#general", "oops I've fallen and I can't get up: %s" % ( traceback.format_exc(), ) ) del( self.actor.reps[ oid ] ) self.actor.log( "bot terminating" ) def tryToRead( self ): while True: try: return self.bot.rtm_read() except: self.bot = SlackClient( self.botToken ) self.bot.rtm_connect() def executeCommand( self, stopEvent, ctx ): try: if 'help' == ctx.cmd[ 0 ]: self.sendHelp( ctx ) elif '?' == ctx.cmd[ 0 ] and 2 <= len( ctx.cmd ): self.command_objects( ctx ) elif '*' == ctx.cmd[ 0 ]: self.command_status( ctx ) elif '.' == ctx.cmd[ 0 ] and 2 == len( ctx.cmd ): self.command_host_info( ctx ) elif '!' == ctx.cmd[ 0 ] and 2 < len( ctx.cmd ): self.command_task( ctx ) elif 'close' == ctx.cmd[ 0 ] and ( 1 == len( ctx.cmd ) or 2 == len( ctx.cmd ) ): self.command_close( ctx ) elif '>' == ctx.cmd[ 0 ] and 2 == len( ctx.cmd ): self.command_parent_atom( ctx ) elif '<' == ctx.cmd[ 0 ] and 2 == len( ctx.cmd ): self.command_children_atom( ctx ) elif '~' == ctx.cmd[ 0 ] and ( 2 == len( ctx.cmd ) or 4 <= len( ctx.cmd ) ): self.command_traffic( ctx ) else: self.bot.rtm_send_message( ctx.channel, "what are you talking about, need *help*?" ) except: self.bot.rtm_send_message( ctx.channel, "oops I've fallen and I can't get up: %s" % ( traceback.format_exc(), ) ) self.actor.log( "Excp: %s" % traceback.format_exc() ) self.history[ 'last_cmd' ] = ctx.cmd def isSensorAllowed( self, ctx, sid ): aid = AgentId( sid ) if aid.org_id is None: resp = self.actor.model.request( 'get_sensor_info', { 'id_or_host' : aid } ) if resp.isSuccess: aid = AgentId( resp.data[ 'id' ] ) if aid.org_id == self.oid: return True self.bot.rtm_send_message( ctx.channel, "sensor not allowed" ) return False def sendHelp( self, ctx ): self.bot.rtm_send_message( ctx.channel, self.prettyJson( { 'help' : 'this help', '?' : [ '? <object_name>: lists the objects of any types with that name', '? <object_name> <object_type> . [of_type]: lists the locations where the object was seen', '? <object_name> <object_type> > [of_type]: lists all the parents of the object', '? <object_name> <object_type> < [of_type}: lists all the children of the object' ], '!' : [ '! sensor_id command [arguments...]: execute the command on the sensor, investigation sensor if sensor id not specified' ], '>' : [ '> atom_id: get the parent event chain starting at this atom_id.' ], '<' : [ '< atom_id: get all the direct children of this atom_id.' ], '.' : [ '. [hostname | sensor_id]: get information on a host by name or sensor id' ], 'close' : [ 'close inv_id: closes the specific inv_id with that conclusion.', 'close: closes the inv_id from the current channel with that conclusion.' ], '~' : [ '~ atom_id: display the event content with that atom_id.', '~ sensor_id from_time to_time [of_type ...]: display event summaries for all events on sensor_id from from_time to to_time, optionally only of types of_type.' ] } ) ) def command_close( self, ctx ): if 1 == len( ctx.cmd ): #TODO conclude the investigation, tricky a bit because we need the Hunter. self.actor.log( "Archiving channel %s" % ctx.channel ) self.archiveChannel( ctx.channel ) elif 2 == len( ctx.cmd ): #TODO conclude the investigation, tricky a bit because we need the Hunter. self.actor.log( "Archiving channel %s" % ctx.cmd[ 1 ] ) self.archiveChannel( ctx.cmd[ 1 ] ) def command_objects( self, ctx ): if 2 == len( ctx.cmd ): # Query for object types that match the name data = self.getModelData( 'get_obj_list', { 'orgs' : self.oid, 'name' : ctx.cmd[ 1 ] } ) if data is not None: self.bot.rtm_send_message( ctx.channel, "here are the objects matching:\n%s\n(valid object types: %s)" % ( self.prettyJson( [ x for x in data[ 'objects' ] if 'RELATION' != x[ 2 ] ] ), str( ObjectTypes.forward.keys() ) ) ) elif 4 <= len( ctx.cmd ): # Query for a characteristic of the object if '.' == ctx.cmd[ 3 ]: # Query the locations of the object data = self.getModelData( 'get_obj_view', { 'orgs' : self.oid, 'obj_name' : ctx.cmd[ 1 ], 'obj_type' : ctx.cmd[ 2 ].upper() } ) aid = AgentId( '%s.0.0.0.0' % self.oid ) if data is not None: output = [] output.append( '*Globally*: %s hosts' % data[ 'locs' ].get( data[ 'id' ], '-' ) ) for loc in data[ 'olocs' ]: output.append( "*%s*" % ( self.getHostname( loc[ 0 ] ) ) ) output.append( ' Last Seen: %s' % self.msTsToTime( loc[ 1 ] ) ) output.append( ' SID: %s)\n' % loc[ 0 ] ) self.bot.rtm_send_message( ctx.channel, "locations of object *%s* (%s):\n%s" % ( ctx.cmd[ 1 ], ctx.cmd[ 2 ].upper(), "\n".join( output ) ) ) elif '>' == ctx.cmd[ 3 ]: # Query the parents of the object typeFilter = None if 5 == len( ctx.cmd ): typeFilter = ctx.cmd[ 4 ].upper() data = self.getModelData( 'get_obj_view', { 'orgs' : self.oid, 'obj_name' : ctx.cmd[ 1 ], 'obj_type' : ctx.cmd[ 2 ].upper() } ) if data is not None: output = [] for parent in data[ 'parents' ]: if typeFilter is not None and typeFilter != parent[ 2 ]: continue output.append( '*%s* (%s)' % ( parent[ 1 ], parent[ 2 ] ) ) output.append( ' Hosts w/ object: %s' % data[ 'locs' ].get( parent[ 0 ], '-' ) ) output.append( ' Hosts w/ relation: %s\n' % data[ 'rlocs' ].get( parent[ 0 ], '-' ) ) self.bot.rtm_send_message( ctx.channel, "parents of object *%s* (%s):\n%s" % ( ctx.cmd[ 1 ], ctx.cmd[ 2 ].upper(), "\n".join( output ) ) ) elif '<' == ctx.cmd[ 3 ]: # Query the children of the object if 5 == len( ctx.cmd ): typeFilter = ctx.cmd[ 4 ].upper() data = self.getModelData( 'get_obj_view', { 'orgs' : self.oid, 'obj_name' : ctx.cmd[ 1 ], 'obj_type' : ctx.cmd[ 2 ].upper() } ) if data is not None: output = [] for child in data[ 'children' ]: if typeFilter is not None and typeFilter != child[ 2 ]: continue output.append( '*%s* (%s)' % ( child[ 1 ], child[ 2 ] ) ) output.append( ' Hosts w/ object: %s' % data[ 'locs' ].get( child[ 0 ], '-' ) ) output.append( ' Hosts w/ relation: %s\n' % data[ 'rlocs' ].get( child[ 0 ], '-' ) ) self.bot.rtm_send_message( ctx.channel, "children of object *%s* (%s):\n%s" % ( ctx.cmd[ 1 ], ctx.cmd[ 2 ].upper(), "\n".join( output ) ) ) else: self.sendHelp( ctx ) def command_status( self, ctx ): orgSensors = self.getOrgSensors() sensorDir = self.getSensorDir() winSensors = 0 osxSensors = 0 linSensors = 0 winOnline = 0 osxOnline = 0 linOnline = 0 onlineSensors = [] for sid, sensorInfo in orgSensors.iteritems(): aid = AgentId( sensorInfo[ 'aid' ] ) isOnline = False if sid in sensorDir: isOnline = True _, _, curBytes, connectedAt = sensorDir[ sid ] onlineSensors.append( ( curBytes, connectedAt, sid ) ) if aid.isWindows(): winSensors += 1 if isOnline: winOnline += 1 if aid.isMacOSX(): osxSensors += 1 if isOnline: osxOnline += 1 if aid.isLinux(): linSensors += 1 if isOnline: linOnline += 1 del( sensorDir ) output = [] output.append( 'Sensor Status:' ) output.append( ' *Windows:* %d (%d online)' % ( winSensors, winOnline ) ) output.append( ' *MacOS:* %d (%d online)' % ( osxSensors, osxOnline ) ) output.append( ' *Linux:* %d (%d online)' % ( linSensors, linOnline ) ) output.append( '' ) topTraffic = sorted( onlineSensors, key = lambda x: x[ 0 ], reverse = True )[ : 5 ] output.append( 'Top online sensors by data received:' ) output.append( self.prettyJson( [ { "hostname" : self.getHostname( x[ 2 ] ), "sid" : x[ 2 ], "since" : self.sTsToTime( x[ 1 ] ), "bytes" : x[ 0 ] } for x in topTraffic ] ) ) self.bot.rtm_send_message( ctx.channel, "\n".join( output ) ) def command_task( self, ctx ): dest = self.getHostInfo( ctx.cmd[ 1 ] )[ 'id' ] if not self.isSensorAllowed( ctx, dest ): return for token in ctx.cmd: if token in ( '-!', '-x', '-@' ): self.bot.rtm_send_message( ctx.channel, "special CLI flags -x, -! and -@ are not allowed." ) return taskFuture = self.task( ctx, dest, ctx.cmd[ 2 : ] ) if taskFuture is not None: try: if taskFuture.wait( 120 ): start = time.time() while time.time() < start + 30: try: resp = taskFuture.responses.pop() data = self.prettyJson( resp ) atom = base64.b64decode( _x_( resp, '?/hbs.THIS_ATOM' ) ) self.slack.chat.post_message( ctx.channel, attachments = [ { "text" : data, "pretext" : "Result from *%s* on *%s*" % ( str( ctx.cmd[ 2 : ] ), AgentId( dest ).sensor_id ), "fallback" : "received task response", "mrkdwn_in" : [ "text", "pretext" ], "fields" : [ { "link" : "%s/explore?atid=%s" % ( self.actor.uiDomain, uuid.UUID( bytes = atom ) ) } ] } ] ) except IndexError: time.sleep( 1 ) elif taskFuture.wasReceived: self.actor.log( taskFuture.responses ) self.slack.chat.post_message( ctx.channel, "... task was received but no reply received" ) else: self.slack.chat.post_message( ctx.channel, "... haven't received a reply" ) finally: taskFuture.done() def command_parent_atom( self, ctx ): interpreter = EventInterpreter() data = [] for evt in self.crawlUpParentTree( None, rootAtom = ctx.cmd[ 1 ] ): interpreter.setEvent( evt ) data.append( { "type" : interpreter.name(), "atom" : interpreter.getAtom(), "narrative" : interpreter.narrative() } ) render = self.sanitizeJson( { "fallback" : "Events going up from: %s." % ctx.cmd[ 1 ], "pretext" : "Events going up from: %s." % ctx.cmd[ 1 ], "text" : self.prettyJson( data ), "mrkdwn_in" : [ "text", "pretext" ] } ) self.slack.chat.post_message( ctx.channel, attachments = [ render ] ) def command_children_atom( self, ctx ): interpreter = EventInterpreter() children = self.getChildrenAtoms( ctx.cmd[ 1 ], depth = 1 ) if children is None: self.slack.chat.post_message( ctx.channel, "couldn't fetch children for %s" % ctx.cmd[ 1 ] ) else: data = [] for evt in children: interpreter.setEvent( evt ) data.append( { "type" : interpreter.name(), "atom" : interpreter.getAtom(), "narrative" : interpreter.narrative() } ) render = self.sanitizeJson( { "fallback" : "Direct children events of: %s." % ctx.cmd[ 1 ], "pretext" : "Direct children events of: %s." % ctx.cmd[ 1 ], "text" : self.prettyJson( data ), "mrkdwn_in" : [ "text", "pretext" ] } ) self.slack.chat.post_message( ctx.channel, attachments = [ render ] ) def command_host_info( self, ctx ): hostOrId = ctx.cmd[ 1 ] hostInfo = self.getHostInfo( hostOrId ) if not self.isSensorAllowed( ctx, hostInfo[ 'id' ] ): return self.bot.rtm_send_message( ctx.channel, "host info for *%s*: %s" % ( ctx.cmd[ 1 ], self.prettyJson( hostInfo ) ) ) def command_traffic( self, ctx ): if 2 == len( ctx.cmd ): self.slack.chat.post_message( ctx.channel, attachments = [ { "fallback" : "event", "mrkdwn_in" : [ "text", "pretext" ], "pretext" : "Event %s" % ctx.cmd[ 1 ], "text" : self.prettyJson( self.getSingleAtom( ctx.cmd[ 1 ] ) ) } ] ) elif 4 <= len( ctx.cmd ): self.actor.log( "CMD: %s" % str(ctx.cmd) ) _, aid, after, before = ctx.cmd[ : 4 ] try: aid = AgentId( aid ) except: aid = AgentId( self.getHostInfo( aid )[ 'id' ] ) ofTypes = ctx.cmd[ 4 : ] if 0 == len( ofTypes ): ofTypes = None else: ofTypes = [ x if '.' in x else ( 'notification.%s' % x.upper() ) for x in ofTypes ] try: after = int( after ) except: after = ( dateutil.parser.parse( after ) - datetime.datetime( 1970, 1, 1 ) ).total_seconds() try: before = int( before ) except: before = ( dateutil.parser.parse( before ) - datetime.datetime( 1970, 1, 1 ) ).total_seconds() if not self.isSensorAllowed( ctx, aid ): return interpreter = EventInterpreter() timeline = self.getModelData( 'get_timeline', { 'id' : aid, 'after' : after, 'before' : before, 'types' : ofTypes, 'is_include_content' : True } ) if timeline is None: return events = [] for data in timeline[ 'events' ]: interpreter.setEvent( data[ 3 ] ) events.append( { "type" : interpreter.name(), "atom" : interpreter.getAtom(), "narrative" : interpreter.narrative() } ) render = self.sanitizeJson( { "fallback" : "Traffic for %s between %s and %s." % ( aid.sensor_id, after, before ), "pretext" : "Traffic for %s between %s and %s." % ( aid.sensor_id, after, before ), "text" : self.prettyJson( events ), "mrkdwn_in" : [ "text", "pretext" ] } ) self.slack.chat.post_message( ctx.channel, attachments = [ render ] ) def getModelData( self, request, requestData = {} ): resp = self.actor.model.request( request, requestData, timeout = 10.0 ) if resp.isSuccess: return resp.data else: self.actor.log( "error getting data from model: %s" % str( resp ) ) return None def getSensorDir( self ): directory = {} data = self.actor.sensordir.request( 'get_dir', {} ) if data.isSuccess: directory = data.data[ 'dir' ] return directory def getOrgSensors( self ): sensors = {} aid = AgentId( '%s.0.0.0.0' % self.oid ) data = self.getModelData( 'list_sensors', { 'aid' : aid } ) if data is not None: sensors = data return sensors def sanitizeJson( self, o ): if type( o ) is dict: for k, v in o.iteritems(): o[ k ] = self.sanitizeJson( v ) elif type( o ) is list or type( o ) is tuple: o = [ self.sanitizeJson( x ) for x in o ] elif type( o ) in ( uuid.UUID, AgentId ): o = str( o ) else: try: if ( type(o) is str or type(o) is unicode ) and "\x00" in o: raise Exception() json.dumps( o ) except: o = base64.b64encode( o ) return o def prettyJson( self, o, indent = 2 ): txt = json.dumps( self.sanitizeJson( o ), indent = indent ) overflow = '' if 7000 < len( txt ): txt = txt[ : 7000 ] overflow = '\n\n*output too large...*' return '```%s```%s' % ( txt, overflow ) def stripSlackFormatting( self, token ): res = self.slackLinkRE.match( token ) if res is not None: return res.groups()[ 0 ] return token def makeChannel( self, name ): try: self.slack.channels.create( '%s' % name ) except: return False return True def archiveChannel( self, name ): try: # Remove the prefix # name1 = name.lower() name2 = name[ 1 : ].lower() cid = None for channel in self.slack.channels.list().body[ 'channels' ]: if channel[ 'name' ].lower() in ( name1, name2 ) or channel[ 'id' ].lower() in ( name1, name2 ): cid = channel[ 'id' ] break if cid is not None: self.slack.channels.archive( cid ) except: self.bot.rtm_send_message( name, "error archiving channel (%s): %s" % ( cid, traceback.format_exc(), ) ) self.actor.log( "Excp: %s" % traceback.format_exc() ) return False return True def inviteToChannel( self, name ): try: name1 = name.lower() name2 = name[ 1 : ].lower() cid = None for channel in self.slack.channels.list().body[ 'channels' ]: if channel[ 'name' ].lower() in ( name1, name2 ) or channel[ 'id' ].lower() in ( name1, name2 ): cid = channel[ 'id' ] break if cid is not None: self.slack.channels.invite( cid, self.botId ) else: self.actor.log( "Channel not found: %s" % name ) except: self.actor.log( 'EXC: %s' % traceback.format_exc() ) return False return True def getHostname( self, aid ): try: return self.actor.model.request( 'get_sensor_info', { 'id_or_host' : str( aid ) } ).data[ 'hostname' ] except: return '-' def getHostInfo( self, aidOrHostnam ): try: return self.actor.model.request( 'get_sensor_info', { 'id_or_host' : str( aidOrHostnam ) } ).data except: return None def msTsToTime( self, ts ): if type( ts ) in ( str, unicode ): ts = ts.split( '.' )[ 0 ] return datetime.datetime.fromtimestamp( float( ts ) / 1000 ).strftime( '%Y-%m-%d %H:%M:%S.%f' ) def sTsToTime( self, ts ): return self.msTsToTime( ts * 1000 ).split( '.' )[ 0 ] def newDetect( self, sources, detect ): hostNames = [ self.getHostname( x ) for x in sources ] atom = _x_( detect[ 'detect' ], '?/hbs.THIS_ATOM' ) message = [ 'Detected *%s* on *%s*:' % ( detect[ 'cat' ], ', '.join( hostNames ) ) ] message.append( 'Summary: %s.' % detect[ 'summary' ] ) message.append( 'Link to sensor: %s' % ' '.join( [ ( '%s/sensor?sid=%s' % ( self.actor.uiDomain, x.sensor_id ) ) for x in sources ] ) ) if atom is not None: message.append( 'Link to event: %s/explore?atid=%s' % ( self.actor.uiDomain, uuid.UUID( bytes = atom ) ) ) detectAttachment = { "text" : self.prettyJson( detect[ 'detect' ] ), "fallback" : "Detection Data", "mrkdwn_in": [ "text", "pretext" ] } self.slack.chat.post_message( '#detects', '\n'.join( message ), attachments = [ detectAttachment ] ) def renderInvHeader( self, inv, sources ): render = { "fallback" : "New investigation (ID: %s) created on %s." % ( inv[ 'inv_id' ], inv[ 'generated' ] ), "pretext" : "New investigation.", "author_name" : inv[ 'hunter' ], "fields" : [], "mrkdwn_in": [ "text", "pretext" ] } for source in sources: render[ "fields" ].append( { "title" : self.getHostname( source ), "value" : source.sensor_id, "short" : True } ) return self.sanitizeJson( render ) def renderNewTasking( self, inv, task ): render = { "fallback" : "New tasking sent: %s." % str( task[ 'data' ] ), "pretext" : "New tasking sent: `%s`." % task[ 'why' ], "text" : self.prettyJson( task[ 'data' ], indent = None ), "fields" : [ { "title" : "Sent", "value" : ( "yes" if task[ 'sent' ] else "no" ), "short" : True } ], "mrkdwn_in": [ "text", "pretext" ] } return self.sanitizeJson( render ) def renderNewData( self, inv, data ): render = { "fallback" : "Reporting new data.", "pretext" : "Reporting new data: `%s`." % data[ 'why' ], "mrkdwn_in": [ "text", "pretext" ] } if 0 != len( data[ 'data' ] ): render[ "text" ] = self.prettyJson( data[ 'data' ] ) return self.sanitizeJson( render ) def renderInvConclusion( self, inv ): render = { "fallback" : "Investigation concluded on %s." % inv[ 'closed' ], "pretext" : "Investigation concluded,", "author_name" : inv[ 'hunter' ], "mrkdwn_in": [ "text", "pretext" ], "fields" : [ { "title" : "Reasoning", "value" : inv[ 'why' ], "short" : True }, { "title" : "Nature", "value" : InvestigationNature.lookup[ inv[ 'nature' ] ], "short" : True }, { "title" : "Conclusion", "value" : InvestigationConclusion.lookup[ inv[ 'conclusion' ] ], "short" : True }, { "title" : "Closed On", "value" : inv[ 'closed' ], "short" : True } ] } return self.sanitizeJson( render ) def newInvestigation( self, sources, investigation ): hostNames = [ self.getHostname( x ) for x in sources ] channelName = '#inv_%s' % ( investigation[ 'inv_id' ][ : 8 ] ) self.makeChannel( channelName ) self.inviteToChannel( channelName ) self.slack.chat.post_message( channelName, attachments = [ self.renderInvHeader( investigation, sources ) ] ) for evt in sorted( investigation[ 'data' ] + investigation[ 'tasks' ], key = lambda x: x[ 'generated' ] ): if evt.get( 'sent', None ) is not None: self.slack.chat.post_message( channelName, attachments = [ self.renderNewTasking( investigation, evt )] ) else: self.slack.chat.post_message( channelName, attachments = [ self.renderNewData( investigation, evt )] ) self.slack.chat.post_message( channelName, attachments = [ self.renderInvConclusion( investigation ) ] ) if investigation[ 'nature' ] in ( InvestigationNature.FALSE_POSITIVE, InvestigationNature.DUPLICATE ): self.archiveChannel( channelName ) def task( self, ctx, dest, cmdsAndArgs ): ret = None if type( cmdsAndArgs[ 0 ] ) not in ( tuple, list ): cmdsAndArgs = ( cmdsAndArgs, ) if not self.isSensorAllowed( ctx, dest ): return data = { 'dest' : dest, 'tasks' : cmdsAndArgs } # Currently Hunters only operate live data[ 'expiry' ] = 0 trxId = '%s//%s' % ( self.invId, self.taskId ) self.taskId += 1 data[ 'inv_id' ] = trxId # We start listening for an answer before sending the tasking # so that we are sure to beat the race in case an answer comes # back really quickly. ret = _TaskResp( trxId, self.actor ) def _syncRecv( msg ): routing, event, mtd = msg.data ret._add( event ) return ( True, ) self.actor.handle( trxId, _syncRecv ) resp = self.actor.tasking.request( 'task', data, key = dest, timeout = 30, nRetries = 0 ) if resp.isSuccess: msg = "sent for tasking: %s" % ( str(cmdsAndArgs), ) self.actor.log( msg ) self.slack.chat.post_message( ctx.channel, msg ) else: if 'usage' == resp.error: msg = "```%s```" % resp.data else: msg = "failed to send tasking: ```%s```" % resp self.actor.log( msg ) self.slack.chat.post_message( ctx.channel, msg ) # Well we listened for nothing, cleanup. ret.done() ret = None return ret def getSingleAtom( self, id ): resp = self.actor.model.request( 'get_atoms_from_root', { 'id' : id, 'depth' : 0 } ) if resp.isSuccess and 0 < len( resp.data ): return resp.data[ 0 ] else: return None def getChildrenAtoms( self, id, depth = 5 ): resp = self.actor.model.request( 'get_atoms_from_root', { 'id' : id, 'depth' : depth } ) if resp.isSuccess: return resp.data else: return None # This is a generator def crawlUpParentTree( self, rootEvent, rootAtom = None ): currentEvent = rootEvent while True: if currentEvent is None and rootAtom is not None: parentAtom = rootAtom else: parentAtom = _x_( currentEvent, '?/hbs.PARENT_ATOM' ) if parentAtom is None: return parentEvent = self.getSingleAtom( parentAtom ) if parentEvent is None: return currentEvent = parentEvent yield parentEvent
try: if last_read[0].get('file') is None or last_read[0].get('file').get('url_private') is None: parsed = last_read[0]['text'] #reply to channel message was found in. message_channel = last_read[0]['channel'] if parsed and 'projects' in parsed.lower(): msg = get_msg_of_project_lists() elif parsed and len(re.compile('\d+').findall(parsed))>0: msg = get_msg_by_project(int(re.compile('\d+').findall(parsed)[0])) elif parsed and 'today' in parsed.lower(): msg = get_msg_by_date(date.today()) elif parsed and 'tomorrow' in parsed.lower(): msg = get_msg_by_date(date.today() + timedelta(days=1)) else: msg ='Hello naughty tester, I don\'t understand what you want\r\n Please type "projects" to see the project list\r\nType "today" or "tomorrow" to see the deployment of these days' client.rtm_send_message(message_channel, msg) elif last_read[0].get('file') is not None and last_read[0].get('file').get('url_private') is not None: url = str(last_read[0]['file']['url_private']) file_type = str(last_read[0]['file']['filetype']) response = requests.get(url, headers={'Authorization': 'Bearer %s' % api_key}, stream = True) temp_name = 'abc_temp.%s' % file_type message_channel = last_read[0]['channel'] with open(temp_name, 'wb') as out_file: response.raw.decode_content = True shutil.copyfileobj(response.raw, out_file) projects = parse_workbook(temp_name) os.remove(holden_xlsx) os.rename(temp_name, holden_xlsx) client.rtm_send_message(message_channel, 'Thank you for uploading new schedule!') del response except IOError as e:
def handle(self, *args, **options): team = Team.objects.first() client = SlackClient("xoxb-335086709553-AVM6StX7HqYoW1xj0IrjXooN") self.mainLobby = Lobby() self.mainGame = None self.userDict = dict() self.gameActive = False self.teamID = "C9VNBVCA1" if client.rtm_connect(): while True: events = client.rtm_read() print("%s----%s" % (team, events)) for event in events: if 'subtype' in event and event['subtype'] == 'bot_message': continue elif 'type' in event and event['type'] == 'message': userID = event['user'] channelID = event['channel'] msgText = event['text'] username = client.server.users[userID].real_name regex = r'^!set (\w+) (\w+)$' if re.match(regex, msgText): matches = re.match(regex, event['text']) codename, dword = matches[1], matches[2] if userID in self.userDict: if self.userDict[userID].active: client.api_call( "chat.postEphemeral", channel=channelID, text= "Unable to modify character while in game.", user=userID) continue else: self.setName(userID, codename) self.setDW(userID, dword) else: self.userDict[userID] = Assassin( userID, username, codename, dword) client.api_call("chat.postEphemeral", channel=channelID, text=str(self.userDict[userID]), user=userID) continue regex = r'^!setname (\w+)$' if re.match(regex, msgText): name = re.match(regex, msgText)[1] if userID in self.userDict: if self.userDict[userID].active: client.api_call( "chat.postEphemeral", channel=channelID, text= "Unable to modify codename while in game.", user=userID) continue else: self.setName(userID, name) else: self.userDict[userID] = Assassin(userID, username, codeName=name) client.api_call("chat.postEphemeral", channel=channelID, text=str(self.userDict[userID]), user=userID) continue regex = r'^!setdword (\w+)$' if re.match(regex, msgText): dword = re.match(regex, msgText)[1] if userID in self.userDict: if self.userDict[userID].active: client.api_call( "chat.postEphemeral", channel=channelID, text= "Unable to modify deathword while in game.", user=userID) continue else: self.setDW(userID, dword) else: self.userDict[userID] = Assassin(userID, username, dw=dword) client.api_call("chat.postEphemeral", channel=channelID, text=str(self.userDict[userID]), user=userID) continue regex = r'^!self$' if re.match(regex, msgText): if userID in self.userDict: client.api_call("chat.postEphemeral", channel=channelID, text=str( self.userDict[userID]), user=userID) else: client.api_call( "chat.postEphemeral", channel=channelID, text= "Please create a character using commands !set, !setname or !setdword", user=userID) continue regex = r'^!joinlobby$' if re.match(regex, msgText): if self.gameActive: client.api_call( "chat.postEphemeral", channel=channelID, text= "Game is already in progress, please wait for the next game.", user=userID) elif userID in self.userDict: if self.userDict[ userID] in self.mainLobby.players: client.api_call( "chat.postEphemeral", channel=channelID, text="You are already in the lobby.", user=userID) else: self.joinLobby(userID) client.api_call( "chat.postEphemeral", channel=channelID, text="You have joined the lobby.", user=userID) client.rtm_send_message( self.teamID, self.userDict[userID].codeName + " has joined the Lobby.") client.rtm_send_message( self.teamID, str(self.mainLobby)) else: client.api_call( "chat.postEphemeral", channel=channelID, text= "Please create a character first by using commands:\n!set, !setname or !setdword", user=userID) continue regex = r'^!leavelobby$' if re.match(regex, msgText): if self.gameActive: client.api_call( "chat.postEphemeral", channel=channelID, text="Unable to leave lobby while in game.", user=userID) elif userID not in self.userDict: client.api_call( "chat.postEphemeral", channel=channelID, text= "Please create a character first by using commands:\n!set, !setname or !setdword.", user=userID) elif self.userDict[ userID] in self.mainLobby.players: self.leaveLobby(userID) client.api_call( "chat.postEphemeral", channel=channelID, text="You have left the lobby.", user=userID) client.rtm_send_message( self.teamID, self.userDict[userID].codeName + " has left the Lobby.") client.rtm_send_message( self.teamID, str(self.mainLobby)) else: client.api_call( "chat.postEphemeral", channel=channelID, text="You are not in the lobby.", user=userID) continue regex = r'^!scores$' if re.match(regex, msgText): client.api_call("chat.postEphemeral", channel=channelID, text=str(self.mainLobby), user=userID) continue regex = r'^!startgame$' if re.match(regex, msgText): if self.gameActive: client.api_call( "chat.postEphemeral", channel=channelID, text="Game has already started.", user=userID) elif len(self.mainLobby.players) < 1: client.api_call( "chat.postEphemeral", channel=channelID, text="Lobby must have at least 1 player.", user=userID) else: self.startGame() for p in self.mainLobby.players: client.api_call("chat.postEphemeral", channel=self.teamID, text="Your target is: " + p.target.realName, user=p.userID) client.api_call("chat.postEphemeral", channel=channelID, text=str( self.userDict[userID]), user=userID) client.rtm_send_message( self.teamID, "Game has begun.\n\nCurrent Scores:") client.rtm_send_message( self.teamID, str(self.mainLobby)) continue regex = r'!kill (\w+)\s?(.*)?$' if re.match(regex, msgText): if self.gameActive: if userID not in self.userDict: client.api_call( "chat.postEphemeral", channel=channelID, text= "Please create a character first by using commands:\n!set, !setname or !setdword.", user=userID) elif self.userDict[userID].active: matches = re.match(regex, msgText) dw = matches[1] deathMsg = "\n" + matches[2] killer = self.userDict[userID] victim = self.killPlayer(dw, killer) if victim is not None: client.api_call( "chat.postEphemeral", channel=self.teamID, text="You have been eliminated by " + killer.codeName + " (" + killer.realName + ").", user=victim.userID) client.api_call( "chat.postEphemeral", channel=channelID, text="Target eliminated.\nYou have " + str(killer.kills) + " confirmed kills.", user=userID) client.rtm_send_message( self.teamID, victim.codeName + " (" + victim.realName + ")" + " has been assassinated by " + killer.codeName + "." + deathMsg) client.rtm_send_message( self.teamID, str(self.mainLobby)) if len(self.mainGame.loop) < 2: client.rtm_send_message( self.teamID, "Game over.\n\nFinal Scores:") client.rtm_send_message( self.teamID, str(self.mainLobby)) client.api_call( "chat.postEphemeral", channel=channelID, text= "Congratulations! You have won the game.", user=userID) self.endGame() else: client.api_call( "chat.postEphemeral", channel=channelID, text="Your new target is: " + killer.target.realName, user=userID) else: client.api_call( "chat.postEphemeral", channel=channelID, text="Incorrect death word.", user=userID) else: client.api_call( "chat.postEphemeral", channel=channelID, text= "You cannot kill while eliminated.", user=userID) else: client.api_call("chat.postEphemeral", channel=channelID, text="Game has not yet begun.", user=userID) continue regex = r'^!help$' if re.match(regex, msgText): client.api_call("chat.postEphemeral", channel=channelID, text=self.helpText(), user=userID) continue time.sleep(1)
for sourcename in tutors_dict: print("added user from db: {} => {}".format(sourcename, tutors_dict[sourcename])) # now open it again to append more logs username_file = open(LOOKUP_FILE, 'a') reaction_file = open(REACTION_FILE, 'a') # connect to Slack sc = SlackClient(SLACK_TOKEN) # connect to RTM API which feeds us stuff that happens if not sc.rtm_connect(with_team_state=False, auto_reconnect=True): raise Exception("couldn't connect to RTM api") sc.rtm_send_message("welcome-test", "test") def is_checked_hour(hour): if UTCHOURS_ACTIVE_START > UTCHOURS_ACTIVE_END: # start later than end return hour >= UTCHOURS_ACTIVE_START or hour < UTCHOURS_ACTIVE_END # normal contiguous range return hour >= UTCHOURS_ACTIVE_START and hour < UTCHOURS_ACTIVE_END def format_real_name(real_name): if real_name in tutors_dict: slackid = tutors_dict[real_name] return '<@{}>'.format(slackid) return '{}'.format(real_name)
class SpotifySlackBot(): def __init__(self, api_key, broadcast_channel): self.broadcast_channel = broadcast_channel self.sc = SlackClient(api_key) # Get the user list response = self.sc.api_call('users.list') self.users = json.loads(response)['members'] def command_current_song(self, event): data = self.run_spotify_script('current-song') data = data.strip().split('\n') data = {"id": data[0], "name": data[1], "artist": data[2]} message = "Hey, the current song is *%s* by *%s*. You can open it on Spotify: %s" % ( data['name'], data['artist'], data['id']) self.sc.rtm_send_message(event['channel'], message) def command_playback_play(self, event): self.run_spotify_script('playback-play') self.sc.rtm_send_message( self.broadcast_channel, "*Resumed playback*, as requested by %s." % (self.get_username(event['user']))) self.sc.rtm_send_message(event['channel'], "Sure, let the music play!") def command_playback_pause(self, event): self.run_spotify_script('playback-pause') self.sc.rtm_send_message( self.broadcast_channel, "*Paused playback*, as requested by %s." % (self.get_username(event['user']))) self.sc.rtm_send_message(event['channel'], "Alright, let's have some silence for now.") def command_playback_skip(self, event): self.run_spotify_script('playback-skip') self.sc.rtm_send_message( self.broadcast_channel, "*Skipping this song*, as requested by %s." % (self.get_username(event['user']))) self.sc.rtm_send_message(event['channel'], "Sure, let's listen to something else...") def command_help(self, event): self.sc.rtm_send_message( event['channel'], "Hey, how are you? I'm here to help you using our office playlist.\n" "I can give you some information about what is playing right now. Just send the command:\n" "- `song`: I'll tell you which song is playing and who is the artist.\n" "\n" "I can also control the playlist, with the following commands:\n" "- `play`: I'll resume playback of the playlist, if it is paused.\n" "- `pause`: I'll pause the playback of the playlist, if it is playing.\n" "- `skip`: I'll skip the current song and play another one.\n" "\n" "*Please note:* When you give commands to control the playlist, *I'll advertise on #spotify-playlist that you asked me to do it*, just so everyone knows what is going on. Please use these only if you really need to :)" ) def command_unknown(self, event): self.sc.rtm_send_message( event['channel'], "Hey there! I kinda didn't get what you mean, sorry. If you need, just say `help` and I can tell you how I can be of use. ;)" ) def run_spotify_script(self, *args): return check_output(['./spotify.applescript'] + list(args)) def get_username(self, id): for user in self.users: if user['id'] == id: return '@%s' % user['name'] return 'someone' def run(self): commands = [('song', self.command_current_song), ('play', self.command_playback_play), ('pause', self.command_playback_pause), ('skip|next', self.command_playback_skip), ('hey|help', self.command_help), ('.+', self.command_unknown)] if self.sc.rtm_connect(): while True: events = self.sc.rtm_read() for event in events: print event if event.get('type') == 'message' and event.get( 'channel')[0] == 'D': for (expression, function) in commands: if re.match(expression, event['text']): function(event) break time.sleep(1)
class RtmBot(object): """Run plugins and check slack for status periodically""" def __init__(self, token, channel="C0LL5MDKN", interval=0.3, ping_interval=5): self.channel = channel or "C0LL5MDKN" self.interval = interval self.ping_interval = min(max(ping_interval, 2), 3600) self.first_ping = 0 self.last_ping = 0 self.token = token self.bot_plugins = [] self.slack_client = None self.last_output = None def connect(self): """Convenience method that creates Server instance""" self.slack_client = SlackClient(self.token) self.slack_client.rtm_connect() def start(self): self.connect() self.load_plugins() while True: for reply in self.slack_client.rtm_read(): dbg('reply: {}'.format(reply)) self.input(reply) self.crons() self.output() self.autoping() time.sleep(self.interval) if DEBUG and (10 < (time.time() - self.first_ping) < (10 + self.interval * 2)) and not self.last_output: ans = self.slack_client.rtm_send_message( self.channel, "I'm alive!") dbg('Answer to send_message: {}'.format(ans)) def autoping(self): """Automatically ping the server every 3 seconds""" now = int(time.time()) if now > self.last_ping + self.ping_interval: self.first_ping = self.first_ping or now self.slack_client.server.ping() dbg('Next ping in {}s'.format(self.ping_interval)) self.last_ping = now def input(self, data): if "type" in data: function_name = "process_" + data["type"] dbg("got {}".format(function_name)) for plugin in self.bot_plugins: plugin.register_jobs() plugin.do(function_name, data) def output(self): for plugin in self.bot_plugins: limiter = False for output in plugin.do_output(): dbg('Found {} output: {}'.format(plugin, output)) channel = self.slack_client.server.channels.find(output[0]) if channel is not None and output[1] is None: if limiter is True: time.sleep(.1) limiter = False message = output[1].encode('ascii', 'ignore') channel.send_message("{}".format(message)) self.last_output = time.time() limiter = True def crons(self): for plugin in self.bot_plugins: plugin.do_jobs() def load_plugins(self): for plugin in glob.glob(directory + '/plugins/*'): sys.path.insert(0, plugin) sys.path.insert(0, directory + '/plugins/') for plugin in glob.glob(directory + '/plugins/*.py') + glob.glob( directory + '/plugins/*/*.py'): logging.info(plugin) name = plugin.split('/')[-1][:-3] self.bot_plugins.append(Plugin(name)) print('Loaded: {}'.format(self.bot_plugins))
class Iris: """The Iris Slack bot engine.""" def __init__(self, slack_token, command_handlers): self.sc = SlackClient(slack_token) self.command_handlers = command_handlers self._signal_handler = ExitOnSignal() def run(self): """Run the Iris bot using the configured commands.""" if self.sc.rtm_connect(): print("> Successfully connected to Slack! Starting the Iris bot...") while True: # Check the signal handler to make sure we are breaking if necessary. if self._signal_handler.kill_now: print("> Terminating the Iris bot...") break # Read events from Slack, then parse that list of events into IrisCommand objects. events = self.sc.rtm_read() commands = self.convert_commands(self.filter_commands(events)) # Handle each IrisCommand received from Slack. for command in commands: self.handle_command(command) # Sleep so that we're polite to Slack. There does not seem to be a blocking # approach available at this time so this will have to do. time.sleep(0.1) else: print("Failed to connect to Slack. Please verify you have a valid token.") @staticmethod def _is_command(event): """True if the event is a command, false otherwise. Commands are Slack messages that start with '!', the command identifier, and contain all required fields.""" if 'type' in event and 'text' in event and 'user' in event and 'channel' in event: return event['type'] == 'message' and str(event['text']).startswith("!") else: return False @staticmethod def _command_name(cmd): """Extract the name of a command.""" # We say that the name is any character up until the first space. # When we use this command, we already know that the string starts with an '!', the command identifier. # We ignore the command identifier with [1:], and then take a single split by space. The single split # will produce an array of size two with the first element being to the left of the space, and the second # element being to the right of the space. We'll use this same approach to extract the content as well. return str(cmd['text'])[1:].split(" ", 1)[0] @staticmethod def _command_content(cmd): """Extract the content of a command.""" splits = str(cmd['text']).split(" ", 1) if len(splits) > 1: return splits[1] else: return "" def _to_command(self, cmd): """Builds an IrisCommand from the given Slack event.""" return IrisCommand(self._command_name(cmd), cmd['user'], cmd['channel'], self._command_content(cmd)) def filter_commands(self, events): """Given some list of events, filter such that only the commands remain.""" return list(filter(lambda evt: self._is_command(evt), events)) def convert_commands(self, commands): """Given some list of commands, convert them into IrisCommand objects.""" return list(map(lambda cmd: self._to_command(cmd), commands)) def handle_command(self, command): """Given some command, parse it and act upon it if the command is registered.""" if command.name in self.command_handlers: handler = self.command_handlers[command.name] handler.handle_command(self.sc, command) return True else: print("No handler exists for command \'" + command.name + "\'.") self.sc.rtm_send_message(command.channel, "No such command \'" + command.name + "\' exists, please type !help for a list.") return False
class AA5ROBot: """ A Slack bot for the AARO Slack site. """ def __init__(self): # Get the Bot token from the environment. Raises RunTimeError if the # value isn't set because the bot can't run without a token configured. slack_bot_token = os.environ.get('SLACK_BOT_TOKEN') if slack_bot_token == '': raise RuntimeError( 'SLACK_BOT_TOKEN must be set in the environment.') # Create the main SlackClient instance for the bot self.slack_client = SlackClient(slack_bot_token) # start initial connection to Slack RTM if self.slack_client.rtm_connect(with_team_state=False): logger.info("AA5ROBot connected to Slack.") self.aa5robot_id = self.slack_client.api_call( "auth.test")["user_id"] else: logger.warning("Connection to Slack RTM failed.") self.shutdown(1) # Load the bot's commands self.commands = command.get_commands() print('AA5RObot initialized.') def start(self): reconnects = 0 # Process events from Slack RTM until ctrl-c logger.info('Processing events from Slack...') while self.slack_client.server.connected is True: try: data, channel = self.parse_bot_commands( self.slack_client.rtm_read()) if data: self.handle_command(data, channel) time.sleep(RTM_READ_DELAY) except KeyboardInterrupt: self.shutdown() # If execution gets here, the connection to the server was interrupted. # Attempt up to MAX_RECONNECT_ATTEMPTS tries to reconnect to Slack. while reconnects < MAX_RECONNECT_ATTEMPTS: print( 'AA5RObot lost connection to Slack. Attempting reconnect, try {}' .format(reconnects + 1)) if self.slack_client.rtm_connect(with_team_state=False): print("AA5ROBot reconnected to Slack.") self.aa5robot_id = slack_client.api_call( "auth.test")["user_id"] self.start() else: reconnects += 1 time.sleep(RECONNECT_WAIT_TIME) # Bot was unable to reconnect, so end the process. print('Unable to reconnect to Slack. Exiting.') self.shutdown(1) def shutdown(self, exit_code=0): """ Execute cleanup tasks before exiting the process. """ # call shutdown method on all command instances for instance in self.commands: instance[1].shutdown() # end the process print("AA5ROBot exiting.") sys.exit(exit_code) def parse_bot_commands(self, 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 a command is not found, then this function returns None, None. """ for event in slack_events: try: if event["type"] == "message" and not "subtype" in event: user_id, message = self.parse_direct_mention(event["text"]) if user_id == self.aa5robot_id: return message, event["channel"] except KeyError: return None, None return None, None def parse_direct_mention(self, 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("^<@(|[WU].+?)>(.*)", 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(self, data, channel): """ Executes a bot command. """ logger.debug('channel: {}, data: {}'.format(channel, data)) # get command string try: command_str = data.split()[0].lower() except IndexError: self.send_message( channel, "Not sure what you mean. Tell me 'help' for more info.") return if command_str == '': self.send_message( channel, "Not sure what you mean. Tell me 'help' for more info.") return if command_str == 'help' or command_str == '?': self.handle_help(channel) return command_strings = [i[0] for i in self.commands] if command_str in command_strings: logger.info("Executing command '{}'.".format(command_str)) method, response = self.commands[command_strings.index( command_str)][1].do_command(data) if method == command.MessageTypes.RTM_MESSAGE: self.send_message(channel, response) if method == command.MessageTypes.API_CALL: self.chat_post_message(channel, response) else: self.send_message( channel, "Not sure what you mean. Tell me 'help' for more info.") return def handle_help(self, channel): """ Sends the bot's help message to Slack. """ self.send_message(channel, "Help not implemented yet!") def send_message(self, channel, response): """ Send a text-only response via the RTM API. """ self.slack_client.rtm_send_message(channel, response) def chat_post_message(self, channel, response): """ Send a chat.postMessage API call. """ self.slack_client.api_call("chat.postMessage", channel=channel, as_user=True, attachments=json.dumps(response))
from slackclient import SlackClient import time from parse import filter_message, parse_message, preprocess from execute import execute_command from config import SLACK_BOT_TOKEN, BOT_ID, READ_WEBSOCKET_DELAY slack_client = SlackClient(SLACK_BOT_TOKEN) if slack_client.rtm_connect(): print("Bot connected and running!", flush=True) last_task = None while True: filtered = filter(filter_message, slack_client.rtm_read()) for message in filtered: if message['text'] == '닫혀라 참깨': assert False try: print('message :', message) parsed_message = parse_message(message) parsed_message = preprocess(parsed_message, last_task) print('parsed message :', parsed_message) response, last_task = execute_command(parsed_message) print('response :', response) except Exception as e: print(e) response = "Sorry, I didn't quite get that. Type 'help' for instruction." slack_client.rtm_send_message(message['channel'], response) time.sleep(READ_WEBSOCKET_DELAY) else: print("Connection failed. Invalid Slack token or bot ID?")
class Robotson(): def __init__(self, token): self.token = token self.slack = SlackClient(token=self.token) self.cleverbot = Cleverbot() self.botname = settings.BOT_NAME self.facebook = Facebook() self.twitter = Twitter() self.network = SocialNetwork() def run(self, interval): if self.slack.rtm_connect(): while True: full_message = self.slack.rtm_read() if full_message: content = full_message[0] if content.get("type") == 'message': sender = self.username_as_str(content.get("user")) channel = content.get("channel") message = content.get("text") try: match = re.search(r'<@[A-Z0-9]+>', message) bot_mention = match.group() if match else "" if bot_mention: # TODO: Remove hardcoding if settings.BOT_UID in bot_mention: self.talk(channel, sender, message) elif settings.SHARE_TRIGGER in message.lower(): self.share(message) except: pass time.sleep(interval) else: raise SlackNotConnected def share(self, message): try: match_share_trigger = re.search( r'%s[\:]?' % settings.SHARE_TRIGGER, message) message = message.replace(match_share_trigger.group(), "") match_lt_mt = re.search(r'[<]+(.*)[>]+', message) message = message.replace(match_lt_mt.group(0), match_lt_mt.group(1)) message = message.strip() url = re.findall( r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', message) if len(url) > 0: if not self.network.already_posted(url[0]): self.facebook.post(message) # self.twitter.post(message) self.network.save_message(message) except Exception: pass def talk(self, channel, user, message): try: answer = '@%s: %s' % (user, self.cleverbot.ask(message)) self.slack.rtm_send_message(channel=channel, message=answer) except Exception: pass def username_as_str(self, userid): try: response = json.loads( self.slack.api_call('users.info', user=userid)) return response.get("user").get("name") except: return ""
def main(): sc = SlackClient(SLACK_BOT_TOKEN) error_msg = json.dumps([{ "color": "#e74c3c", "attachment_type": "default", "text": "", "image_url": "http://i2.kym-cdn.com/photos/images/original/000/329/784/bd6.jpg" }]) # Connect to slack if sc.rtm_connect(): while True: # Listen for any latest events for slack_event in sc.rtm_read(): message = slack_event.get("text") user = slack_event.get("user") channel = slack_event.get("channel") if (message and user): if (SLACK_BOT_NAME in message): movieName = message[13:] if (len(movieName.strip()) == 0): sc.api_call("chat.postMessage", channel=channel, text="", attachments=error_msg, as_user=True) else: try: url = "http://www.omdbapi.com/?t=" + message[ 13:] response = requests.get(url) if response.status_code == 200: data = response.json() print "Calling " + url intro_msg = json.dumps([{ "fallback": "There seems to be some issue with displaying the data", "title": message[13:], "color": "#50e043", "attachment_type": "default", "text": data["Plot"], "fields": [{ "title": "Title", "value": data["Title"], "short": True }, { "title": "Actors", "value": data["Actors"], "short": True }, { "title": "Released", "value": data["Released"], "short": True }, { "title": "Rated", "value": data["Rated"], "short": True }, { "title": "IMDB Ratings", "value": data["Ratings"][0]["Value"], "short": True }], "image_url": data["Poster"] }]) sc.api_call( "chat.postMessage", channel=channel, text="Here is some information about " + message[13:], attachments=intro_msg, as_user=True) except: sc.rtm_send_message( channel, "Hey " + "<@" + user + "> !" + " I couldn't find this movie") else: sc.rtm_send_message(channel, "")
class DispatcherBot(RedisHash): _slack = None def __init__(self, name='dispatcher'): super().__init__(namespace='slack', prefix='bot', key=name) self.attrib_lists.update( dict(string=['api_key', 'name'], bool=[], int=[], list=[], set=['watching_events', 'watching_users', 'messages'], path=[])) self.__namespaceinit__() if not self or not self.name: self.__bindattrs__() self.name = name if self._slack is None: self._slack = SlackClient(ET_SLACK_IDENTIFIER) if not self.watching_events: self.watching_events.extend(['presence_change', 'message']) def start(self): if self._slack.rtm_connect(): while True: events = self._slack.rtm_read() if events: self.handle_events(events) gevent.sleep(2) else: logger.error('Connection Failed!') def handle_events(self, events): events = [e for e in events if e['type'] in self.watching_events] for event in events: method = '_{}_handler'.format(event['type']) handler = getattr(self, method) try: handler(event) except Exception as err: logger.exception(err) def _presence_change_handler(self, event): if 'active' != event['presence']: return if not self.watching_users or event['user'] not in self.watching_users: return elif not self.messages: return for msg_id in self.messages: msg = DispatcherBotMessage(msg_id) if msg.delivered or not msg.to_users or event[ 'user'] not in msg.to_users: continue channel = self._slack.api_call('im.open', user=event['user']) if self._slack.rtm_send_message(channel, msg.content): msg.to_users.remove(event['user']) self.watching_users.remove(event['user']) if not msg.to_users: msg.delivered = True
class Slack_bot(SlackClient): """slack_bot class.""" def __init__(self, token, twit_channel, home_channel, bot_id=None): self.sc = SlackClient(token) self.channel = twit_channel self.home = home_channel self.start_time = datetime.datetime.now() self.bot_id = bot_id if not self.bot_id and self.sc.rtm_connect(with_team_state=False): response = self.sc.api_call('auth.test') self.name = response.get('user') self.bot_id = response.get('user_id') self.at_bot = '<@' + self.bot_id + '>' def __enter__(self): """returns slack obj and connects to rtm if not.""" mess = "PBJTIME is ONLINE!!!! (with a baseball bat)" if self.sc.server.connected: logger.info('SlackBot connected to rtm stream') else: logger.info('SlackBot connected to rtm stream') self.sc.rtm_connect(with_team_state=False) self.post_command_message(mess, self.home) return self def __exit__(self, type, value, traceback): """lets program know that it is exiting slackbot.""" logger.info('Exiting slack_bot') def read_stream(self): """reads stream from slack_client connections.""" return self.sc.rtm_read() def parse_stream(self, content): """takes in content from stream and looks for pbjtime mentions.""" for item in content: if 'text' in item and item['text'].startswith(self.at_bot): text = item['text'].split(self.at_bot) chan = item['channel'] return (text[1].strip(), chan) return (None, None) def handle_command(self, text, tb): """handles commands that are given and returns message to post.""" global subscr global stats args = text.lower().split() if args: cmd = args[0].lower() logger.info('{} cmd was issued.'.format(cmd)) else: cmd = '' args = args[1:] if cmd == 'raise': logger.info('raise test exception') raise TestException elif cmd == 'help': return 'these commands are possible:\n\ {}'.format(pp.pformat(bot_commands)) elif cmd == 'time': logger.info('bot initialized in slack.') return "IT'S PEANUT BUTTER JELLY TIME!! \n(help for more options)" elif cmd == 'ping': uptime = datetime.datetime.now() - self.start_time logger.info('current uptime: {}'.format(uptime)) return 'Peanut Butter Jelly upTime: {}'.format(uptime) elif cmd == 'exit': tb.close_stream() subscr = [] tb.subscriptions = [] stats = {} logger.info('pbjtime leaving slack.') return "peanut butter jelly time :'( (goodbye)" elif cmd == 'start': subscr = list(set(subscr + args)) if not subscr: logger.info('no subscr. ignoring and not starting stream.') return 'Please add subscriptions so I can find tweets.' tb.init_stream(subscr) logger.info('started stream with subscriptions: {}'.format(subscr)) for subs in subscr: if subs not in stats: stats[subs] = 0 if args: return 'Added subscriptions: {}'.format(args) return 'Started with subcriptions: {}'.format(subscr) elif cmd == 'add': subscr = list(set(subscr + args)) if not subscr or not args: logger.info('no new subscriptions. ignoring') return 'Please add new subscriptions so I can find tweets.' tb.init_stream(subscr) for subs in subscr: if subs not in stats: stats[subs] = 0 logger.info('added new subcriptions; restarting stream.') return 'Added subscriptions: {}'.format(args) elif cmd == 'remove': removed = [] for arg in args: if arg in subscr: subscr.remove(arg) removed.append(arg) if arg in stats: del stats[arg] if removed: logger.info('removed subcriptions: {}'.format(arg)) tb.init_stream(subscr) logger.info('restarted twitter stream.') return 'removed subcriptions: {} and restarted.'.format(arg) else: logger.info('no subscriptions matching input. ignoring') return 'No subscriptions removed. use list to see current.' elif cmd == 'removeall': subscr = [] tb.close_stream() tb.subscriptions = [] stats = {} logger.info('All subscriptions removed') return 'all subscriptions removed!' elif cmd == 'list': logger.info('channel list: {}'.format(subscr)) return 'current subscriptons: \n {}'.format(subscr) elif cmd == 'stop': logger.info('Stopping twitter stream') tb.close_stream() logger.info('stream closed on slack side.') return 'Twitter stream has been stopped.' elif cmd == 'channels': self.channel_list() elif cmd == 'stats': logger.info('stats: {}'.format(pp.pformat(stats))) return 'subscription stats: {}'.format(pp.pformat(stats)) elif cmd not in bot_commands: logger.info('unknown command issued') return 'Peanut Butter Jelly Time??? use help for more options.' else: logger.warning('made it through if else block: {}'.format(cmd)) return None def post_command_message(self, mess, channel): """posts message after command is completed.""" logger.info('Sent response to channel: {}'.format(channel)) self.sc.rtm_send_message(channel, mess) def post_twit_mess(self, mess): """Posts message from twitter bot to initial channel.""" global stats global subscr for scr in stats: if scr in mess.lower(): stats[scr] += 1 self.sc.api_call("chat.postMessage", channel=self.channel, text=mess) def channel_list(self): logger.info('requesting channel list') logger.info(pp.pformat(self.sc.api_call("channels.list")))
class SlackConnection(Borg): def __init__(self): super().__init__() self.log = logging.getLogger(__name__) self.initialized = False def initialize(self): # pragma: no cover if not self.initialized: self.get_slack_token() self.connect() self.initialized = True def get_slack_token(self): # pragma: no cover config_dict = configuration.get() self.token = config_dict['main']['slackbot_token'] def connect(self): # pragma: no cover self.sc = SlackClient(self.token) if not self.sc.rtm_connect(): self.log.critical("Error conecting to Slack - token issue?") self.log.critical("--- full stack trace ---") self.log.critical(traceback.format_exc()) sys.exit(1) @asyncio.coroutine def get_stream_messages(self): self.initialize() return_messages = [] try: messages = self.sc.rtm_read() for msg in messages: message_object = self.get_message_type(msg) return_messages.append(message_object) except TimeoutError as t: self.log.error("Error reading from slack socket: %s" % t) self.log.error("--- full stack trace ---") self.log.error(traceback.format_exc()) self.log.info("Now attempting to reconnect") self.connect() except BrokenPipeError as b: self.log.critical("Error reading from slack socket: %s" % b) self.log.critical("--- full stack trace ---") self.log.critical(traceback.format_exc()) sys.exit(1) return return_messages def get_message_type(self, msg): self.initialize() obj_list = [ "charlesbot.slack.slack_pong.SlackPong", "charlesbot.slack.slack_channel_joined.SlackChannelJoined", "charlesbot.slack.slack_channel_left.SlackChannelLeft", "charlesbot.slack.slack_group_joined.SlackGroupJoined", "charlesbot.slack.slack_group_left.SlackGroupLeft", "charlesbot.slack.slack_message.SlackMessage", ] for obj in obj_list: module_name, class_name = obj.rsplit(".", 1) obj_class = getattr(importlib.import_module(module_name), class_name) # NOQA return_obj = obj_class() if getattr(return_obj, 'is_compatible')(msg): return_obj.load(msg) return return_obj return None @asyncio.coroutine def send_channel_message(self, channel_id, message): # pragma: no cover self.initialize() self.sc.rtm_send_message(channel_id, message) @asyncio.coroutine def send_ping_message(self): # pragma: no cover self.initialize() self.sc.server.ping() @asyncio.coroutine def api_call(self, api_endpoint, **kwargs): self.initialize() val = self.sc.api_call(api_endpoint, **kwargs) json_str = json.loads(val.decode('utf-8')) if not json_str['ok']: self.log.error("Error fetching %s - response: %s", api_endpoint, str(json_str['ok'])) self.log.error(json_str) return json.dumps("{}") return json.dumps(json_str)
def _fetch_slack_blessing(self, slack_token: Text, channel_id: Text, model_uri: Text) -> _SlackResponse: """Send message via Slack channel and wait for response. Args: slack_token: The user-defined function to obtain token to send and receive messages. channel_id: The id of the Slack channel to send and receive messages. model_uri: The URI of the model waiting for human review. Returns: A _SlackResponse instance. Raises: ConnectionError: When connection to slack server cannot be established. """ sc = SlackClient(slack_token) msg = _NOTIFY_MODEL_REVIEW_TEMPLATE.format(model_uri) ts = 0 if not sc.rtm_connect(): msg = 'Cannot connect to slack server with given token' tf.logging.error(msg) raise ConnectionError(msg) # pylint: disable=undefined-variable sc.rtm_send_message(channel=channel_id, message=msg) while sc.server.connected: payload_list = sc.rtm_read() if not payload_list: continue for payload in payload_list: if payload.get('ok') and payload.get( 'reply_to') == 0 and not ts: ts = payload['ts'] continue elif payload.get('type') == 'message' and payload.get( 'channel') == channel_id and payload.get( 'text') and payload.get('thread_ts') == ts: if payload.get('text').lower() in _APPROVE_TEXT: tf.logging.info( 'User %s approves the model located at %s', payload.get('user'), model_uri) return _SlackResponse(True, payload.get('user'), payload.get('text'), channel_id, str(ts)) elif payload.get('text').lower() in _DECLINE_TEXT: tf.logging.info( 'User %s declines the model located at %s', payload.get('user'), model_uri) return _SlackResponse(False, payload.get('user'), payload.get('text'), channel_id, str(ts)) else: unrecognized_text = payload.get('text') tf.logging.info('Unrecognized response: %s', unrecognized_text) sc.rtm_send_message( channel=channel_id, message=_NOTIFY_CORRECT_REPLY_TEMPLATE.format( unrecognized_text), thread=ts)
class SlackBot: def __init__(self): self.config = configparser.ConfigParser() self.config.read("stagebot.ini") self.parser = ArgumentParser() self.parser.add_argument("command", choices=["echo", "deploy"]) self.parser.add_argument("--branch", default="master") self.slack = SlackClient(self.config.get("slack", "bot_token")) self._connect() def _connect(self): if not self.slack.rtm_connect(): raise Exception("rtm connect failed") logging.info("Connected.") def run(self): while True: for msg in self.slack.rtm_read(): logging.debug("%s", msg) if msg.get("type") == "message" and "text" in msg: if msg["user"] == self.config.get("slack", "bot_uid"): continue args = msg["text"].split() if args[0].lower() not in [ "stagebot", "@stagebot" ] and self.config.get("slack", "bot_uid") not in args[0]: continue try: self.handle(args[1:]) except Exception as err: self.post_snippet("build failure", str(err)) time.sleep(1) def send(self, message): logging.info(message) self.slack.rtm_send_message("bot-testing", message) def post_snippet(self, title, snippet): self.slack.api_call("files.upload", channels="bot-testing", title=title, content=snippet or "<no output>", filetype="txt") def handle(self, args): try: args = self.parser.parse_args(args) except ParserMessage as msg: self.send("%s" % msg) return except ParserError as err: self.send(":interrobang: %s" % err) return if not re.match(r"^[A-Za-z0-9_-]+\Z", args.branch): self.send(":interrobang: Invalid branch name") return if args.command == "echo": self.send("echo") elif args.command == "deploy": self.deploy(args) def deploy(self, args): start_time = time.time() # 0. Pre sh(self.config.get("deploy", "pre")) # 1. Download server download = "%s/lila-server-%s.tar.gz" % (self.config.get( "s3", "bucket"), args.branch) self.send("Downloading %s ..." % download) urllib.urlretrieve(download, "lila-server.tar.gz") # 2. Download assets download = "%s/lila-assets-%s.tar.gz" % (self.config.get( "s3", "bucket"), args.branch) self.send("Downloading %s ..." % download) urllib.urlretrieve(download, "lila-assets.tar.gz") with tarfile.open("lila-server.tar.gz") as tar: # 3. Peek server with tar.extractfile("commit.txt") as commit_file: sha, message = commit_file.readline().decode( "utf-8").strip().split(None, 1) self.send( "Deploying server: https://github.com/%s/commit/%s (`%s`) ..." % (self.config.get("github", "slug"), sha, message)) # 4. Extract server app_files = [ t for t in tar.getmembers() if make_relative("target/universal/stage/", t) ] tar.extractall(self.config.get("deploy", "app"), members=app_files) with tarfile.open("lila-assets.tar.gz") as tar: # 5. Peek assets with tar.extractfile("commit.txt") as commit_file: sha, message = commit_file.readline().decode( "utf-8").strip().split(None, 1) self.send( "Deploying assets: https://github.com/%s/commit/%s (`%s`) ..." % (self.config.get("github", "slug"), sha, message)) # 6. Extract assets. asset_files = [ t for t in tar.getmembers() if make_relative("public/", t) ] tar.extractall(self.config.get("deploy", "assets"), members=asset_files) # 7. Post sh(self.config.get("deploy", "post")) end_time = time.time() self.send(":white_check_mark: Done in %.1fs" % (end_time - start_time))
class Gaben: def __init__(self, api_key, rep_directory): self.api_key = api_key self.slack = SlackClient(api_key) self.store = Store() self.builder = Builder(rep_directory) def run(self): if self.slack.rtm_connect(auto_reconnect=True): print("Gabe is ready!") while True: data_list = self.slack.rtm_read() for data in data_list: if "type" in data and "subtype" not in data and data[ "type"] == "message": self.incoming_im(data) time.sleep(1) else: print("Slack connection failed...") def get_user_info(self, data): return self.slack.api_call("users.info", user=data["user"]) def incoming_im(self, data): text = data["text"].strip().replace("“", "\"").replace("”", "\"") user_info = self.get_user_info(data) if user_info["user"]["name"] == self.slack.server.username: return print("%s: %s" % (user_info["user"]["name"], text)) if text[:3].lower() == "add": self.incoming_add(data, text) elif text[:6].lower() == "remove": self.incoming_remove(data, text) elif text.strip().lower() == "projects": self.incoming_projects(data) elif text[:5].lower() == "build": self.incoming_build(data, text) elif text[:5].lower() == "alter": self.incoming_alter(data, text) elif text[:4].lower() == "jobs": self.incoming_jobs(data) else: if data["channel"] not in config.DONT_PRINT_USAGE_FOR: self.send_usage(data) def send_usage(self, data): self.send_msg( data, """Usage: add - add a new project remove - remove a project and clean it's data alter - change parameters of the project projects - get list of all projects build - build a project jobs - show current tasks and projects statuses""") def send_msg(self, data, text): self.slack.rtm_send_message(data["channel"], text) def incoming_alter(self, data, text): cmd = shlex.split(text)[1:] parser = ArgumentParser(prog="alter", description='Alter an existing project') parser.add_argument("name", help="Name or url of the project") parser.add_argument( "--keystore", help="Path of the keystore file relative to the project root", default="") parser.add_argument("--keystore_pwd", help="Keystore password", default="") parser.add_argument("--key", help="Keystore key", default="") parser.add_argument("--key_pwd", help="Keystore key password", default="") try: args = parser.parse_args(cmd) project = self.store.search(args.name) if len(args.keystore) > 0: project.keystore_filename = args.keystore if len(args.keystore_pwd) > 0: project.keystore_pwd = args.keystore_pwd if len(args.key) > 0: project.key = args.key if len(args.key_pwd) > 0: project.key_pwd = args.key_pwd self.store.save() self.send_msg(data, "Project altered") except Exception as ex: self.send_msg(data, str(ex)) def incoming_add(self, data, text): cmd = shlex.split(text)[1:] parser = ArgumentParser(prog="add", description='Add a new project') parser.add_argument("url", help="Git url of the repository") parser.add_argument( "--keystore", help="Path to the keystore file relative to the project root", default="") parser.add_argument("--keystore_pwd", help="Keystore password", default="") parser.add_argument("--key", help="Keystore key", default="") parser.add_argument("--key_pwd", help="Keystore key password", default="") parser.add_argument("--name", help="Name of the project (optional)", default="") try: args = parser.parse_args(cmd) args.url = re.sub(r"<mailto:(.+)\|(.+)>", lambda m: m.group(1), args.url) if self.store.is_url_exists(args.url): raise Exception("Project with url %s already exists" % args.url) project = Project(args.url, args.keystore, args.keystore_pwd, args.key, args.key_pwd, args.name) self.store.add_project(project) self.send_msg( data, """Project added with parameters: *Url:* %s *Keystore file path:* %s *Keystore password:* %s *Key:* %s *Key password:* %s *Name:* %s """ % (project.url, project.keystore_filename, project.keystore_pwd, project.key, project.key_pwd, project.name)) except Exception as ex: self.send_msg(data, str(ex)) def incoming_remove(self, data, text): cmd = shlex.split(text)[1:] parser = ArgumentParser(prog="remove", description='Remove project') parser.add_argument("name", help="Name or url of the project") try: args = parser.parse_args(cmd) project = self.store.search(args.name) self.builder.clean_project(project) self.store.remove_project(project) self.send_msg(data, "Project *%s* removed" % str(project)) except Exception as ex: self.send_msg(data, str(ex)) return def incoming_projects(self, data): projects = self.store.get_data() result = "" for project in projects: result += "*%s:* %s keystore=%s key=%s\r\n" % ( project.name, project.url, project.keystore_filename, project.key) if len(result) == 0: self.send_msg(data, "No projects added") else: self.send_msg(data, result) def incoming_build(self, data, text): platforms = [ "Win", "Win64", "OSXUniversal", "Linux", "Linux64", "LinuxUniversal", "iOS", "Android" ] scripting_backengs = ["il2cpp", "mono"] cmd = shlex.split(text)[1:] parser = ArgumentParser(prog="build", description='Build the project') parser.add_argument("name", help="Name or url of the project") parser.add_argument("branch", help="Branch of the repositary") parser.add_argument("platform", help="Platform: " + ",".join(platforms)) parser.add_argument("--noupload", action="store_true", help="Don't upload build to Slack") parser.add_argument( "--log", action="store_true", help="Always keep log, even if build was successful") parser.add_argument("--clean", action="store_true", help="Make a clean build (remove unity cache)") parser.add_argument("--backend", help="Override scripting backend: " + ",".join(scripting_backengs), default="") parser.add_argument("--build", type=int, help="Override build number", default=-1) parser.add_argument("--version", help="Override build version", default="") parser.add_argument( "--development", action="store_true", help="Make a developement build (default is Release)") parser.add_argument("--profiler", action="store_true", help="Autoconnect profiler") parser.add_argument("--donotsign", action="store_true", help="(Android only) Do not sign build") parser.add_argument( "--split", action="store_true", help="(Android only) Split APK & OBB (default is single APK)") parser.add_argument( "--split_arch", action="store_true", help="(Android only) Split APK by target architecture") parser.add_argument("--build_with_method", default="", help="Set custom building method") try: args = parser.parse_args(cmd) project = self.store.search(args.name) if args.platform not in platforms: raise Exception("Unknown platform %s. Possible options: %s" % (args.platform, ",".join(platforms))) if args.backend not in scripting_backengs and len( args.backend) > 0: raise Exception( "Unknown scripting backend %s. Possible options: %s" % (args.backend, ",".join(scripting_backengs))) if args.backend == "mono" and args.platform == "iOS": raise Exception("%s backend doesn't work on platform %s" % (args.backend, args.platform)) self.builder.start(project, args.branch, args.platform, args.noupload, args.backend, not args.donotsign, \ args.split, args.split_arch, args.log, args.clean, args.build, args.version, args.development, args.profiler, args.build_with_method, data, self.builder_callback) self.send_msg(data, config.get_random_quote()) except Exception as ex: self.send_msg(data, str(ex)) return def incoming_jobs(self, data): jobs = self.builder.get_jobs() if len(jobs) == 0: self.send_msg( data, "No jobs at the moment (uploading your build is not a job)") return result = "*Current jobs:*\r\n" for job in jobs: result += "*%s* -> %s\r\n" % ( job.project.name, str(job.pipeline.get_current_job()) if job.pipeline is not None else "Finishing") self.send_msg(data, result) def builder_callback(self, data, project, status, file_path, noupload): size = os.path.getsize(file_path) MAX_MB = config.MAX_UPLOAD_SIZE_MB if noupload: self.send_msg( data, "Build completed! No upload flag is set, so grab your build locally in %s" % file_path) return if size > 1024 * 1024 * MAX_MB: self.send_msg( data, "Build completed, but it's exceeds %dMb size! :neutral_face:\nYou can grab build locally in %s" % (MAX_MB, file_path)) return try: with open(file_path, "rb") as f: self.slack.api_call( 'files.upload', channels=data["channel"], as_user=True, filename=os.path.basename(file_path), file=f, ) except Exception as ex: print("Failed to upload file to slack: %s" % str(ex)) self.send_msg( data, "Failed to upload build to Slack, grab the build locally in %s" % file_path) return if status: self.send_msg(data, "Build of %s completed! :+1:" % project.name) else: self.send_msg( data, ":octagonal_sign: Build of %s failed! " % project.name)
class MySlackBot(object): def __init__(self): config_path = os.getenv('MYBOT_SLACK_CONFIG_PATH') if config_path is None: config_path = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'config.yaml') print("Loading config from " + config_path) with io.open(config_path, 'r', encoding='utf8') as f: config = yaml.safe_load(f) self._logger = logging.getLogger('mybot.slack') log_level = config.get('log level', logging.WARN) self._logger.setLevel(log_level) ch = logging.StreamHandler() ch.setLevel(log_level) formatter = logging.Formatter( '%(asctime)s [%(levelname)s] - %(name)s\n%(message)s') ch.setFormatter(formatter) self._logger.addHandler(ch) slack_token = config["slack API token"] self._client = SlackClient(slack_token) del slack_token # Get current user's ID so that they don't automatically reply to their own messages. # TODO Determine is automatically: might need to use OAuth. self._current_user_id = config.get('user id') self._reply_rules = [] ReplyRule = namedtuple('ReplyRule', ['pattern', 'replies']) for rule in config.get('reply rules', []): self._reply_rules.append( ReplyRule(re.compile(rule['pattern']), rule['replies'])) self._check_delay = config.get('check delay', 3) def _get_reply(self, received_msg): result = None for rule in self._reply_rules: m = rule.pattern.match(received_msg) if m: result = random.choice(rule.replies) break return result def handle_messages(self): if self._client.rtm_connect(): self._logger.info("Waiting for messages.") while True: try: rtm_results = self._client.rtm_read() except Exception as e: self._logger.exception(e) raise for event in rtm_results: try: if self._logger.isEnabledFor(logging.DEBUG): self._logger.debug("Event: \"%s\"", json.dumps(event, indent=2)) if event.get('type') == 'message' and event.get( 'user') != self._current_user_id: channel = event.get('channel', '') if channel.startswith('D'): received_msg = event.get('text') if received_msg: reply = self._get_reply(received_msg) if reply: self._logger.info( "Replying: \"%s\" in %s", reply, channel) self._client.rtm_send_message( channel, reply) except Exception as e: self._logger.exception(e) time.sleep(self._check_delay) else: raise Exception("Connection failed. Maybe your token is invalid?")
'\u2019', '\'') # hacky way of fixing encoding with apostrophe # print(len(json.loads(history)['messages'])) # save_string_as_json_file(filename=office, content=history) while True: last_read = client.rtm_read() if last_read: try: parsed = last_read[0]['text'] #reply to channel message was found in. message_channel = last_read[0]['channel'] if message_channel.startswith( 'D' ) and "update" in parsed: #TODO: Restrict access with last_read[0]['user']: # print last_read[0] client.rtm_send_message( message_channel, "No problem! Please give me a minute to analyze the latest messages. :clock1:" ) r = requests.get( "http://ec2-52-87-240-146.compute-1.amazonaws.com:23001/trigger" ) # r = requests.get("http://google.com") client.rtm_send_message( message_channel, "Got the results back! Check them out at http://bit.ly/28cy4vX" ) except: pass time.sleep(1)
def main(): ''' UDP通信サーバーのセッティング 受信データの解析 解析結果をslack botで送信を行う ''' token = "トークン" # メモしておいたトークンを設定 sc = SlackClient(token) print("bot boot") channels_name = "bot_name" test = 0 n = 40 time_window = 100 window_list_xyz = [] time_data = [] amount = 250 Decrease_point = [0,0] ave_xyz = 0 udp_data_xyz = 0 median = 0 index = 1 ''' UDP通信サーバーのセッティング ''' try : s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) except s(ocket.error, msg) : print ('Failed to create socket. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]) sys.exit() try: s.bind(('', 3333)) except (socket.error , msg): print ('Bind failed. Error: ' + str(msg[0]) + ': ' + msg[1]) sys.exit() print ('Server listening') if sc.rtm_connect(): while True: udp_recv = s.recvfrom(1024) udp_data = udp_recv[0].strip() udp_data = re.findall(r'[0-9]+', str(udp_data)) udp_data_xyz = int(udp_data[0]) window_list_xyz.append(udp_data_xyz) time_data.append(udp_data_xyz) slack_data = sc.rtm_read() test = test + 1 if len(window_list_xyz) > n: window_list_xyz.pop(0) if len(window_list_xyz) == n: '''' 畳み込み積分を行う '''' ave_xyz = np.convolve(np.array(window_list_xyz, dtype='int64'), np.ones(n)/float(n), 'valid') if len(time_data) > time_window: time_data.pop(0) if len(time_data) == time_window: ''' 最頻値を取得 ''' median = statistics.median(time_data) time_data.pop(0) if len(window_list_xyz) == n: if median-ave_xyz > 50 and index - Decrease_point[0] > 50: print("push") print(index - Decrease_point[0]) print(median-ave_xyz) Decrease_point[0] = index Decrease_point[1] = Decrease_point[1] + 1 if len(slack_data) > 0: for item in slack_data: message_check = create_message(item) if message_check is True: amount_answer = math.floor(((amount-Decrease_point[1]*5)/amount)*100) print(amount_answer) messagetext = "シャンプーの残りの量は"+str(amount_answer)+"%です" sc.rtm_send_message(item['channel'], messagetext) sc.api_call('files.upload', channels=item['channel'], as_user=True, filename='./image_data/'+str(amount_answer)+'.png', file=open('./image_data/'+str(amount_answer)+'.png', 'rb')) index = index + 1 s.close() else: print("Connection Failed, invalid token?")
sc = SlackClient(token) if sc.rtm_connect(): message = { "as_user": True, "text": "TEST1:", "attachments": json.dumps([{ "title": "App hangs on reboot", "title_link": "http://domain.com/ticket/123456", "text": "If I restart my computer without quitting your app, it stops the reboot sequence.\nhttp://domain.com/ticket/123456" }]), } sc.api_call("chat.postMessage", channel="#yuwei", **message) while True: in_events = sc.rtm_read() for event in in_events: if 'type' in event: if event['type'] == 'message': channel, message = event['channel'], event['text'] print(channel, message) sc.rtm_send_message(channel=channel, message=message) else: print("Connection Failed, invalid token?")
matches.append(v['name']) cb=v['callback'] if m[0].lower() == v['name'].lower(): exact=cb if exact: log_event( display_name,msg['text']) text=exact(sc,userinfo,contexts[chan],*m) elif len(matches)==1: log_event( display_name,msg['text']) text=cb(sc,userinfo,contexts[chan],*m) elif len(matches)==0: text="Unknown command. Type `help` for help" else: text="Ambiguous command: Did you mean " text += oxfordlist(matches) text += "?\n(`help` for more)" except BaseException as e: text = ":alert: Epic fail: ```"+str(e)+"```" log_event( "<Error>",str(e)) sc.rtm_send_message(msg['channel'],text) prune_contexts(contexts) sys.stdout.flush() else: print "Connection Failed" time.sleep(2) print "RETRY"
for each in i: # process select loop events if socketlist[each] == 'tty': # tosend = sys.stdin.readline().rstrip('\r\n') msg = teletype.recv(256).rstrip('\r\n') tosend = str(msg.decode('ascii', 'ignore')) tosend = tosend.replace( '^G', '<bell>') # bell is "not well formed xml" hahaha. tosend = tosend.replace( ' ', ' ') # tabs make whole message fail silently # drop blank lines so we don't make a bogus rtm_send_message() call if not tosend: continue if not tosend.startswith('/'): if current_channel: sc.rtm_send_message(channel=current_channel, message=tosend) else: sl_print("not in a channel") else: # process a / command cmd = tosend.split() cmd[0] = cmd[0].lower() if cmd[0] == '/q' or cmd[0] == '/quit': sl_print("quitting slack") online = False # try to send a direct message? this is janky. if (cmd[0] == '/m' or cmd[0] == '/msg') and len(cmd) > 2: recip = cmd[1].lower() body = ' '.join(cmd[2:]) if recip in uids: try:
http_get_rqst_pattern = re.compile ('^get\s+<(https?://([-\w\.]+)+(:\d+)?(/([\w/_\.]*(\?\S+)?)?)?)>$') stop_pattern = re.compile ('^quititsaysame$') sc = SlackClient (slack_token) if sc.rtm_connect (): while run_flag: msgs = sc.rtm_read () if len(msgs) == 0: sleep (1) else: for msg in msgs: if 'channel' in msg and msg['channel'] == direct_chan_id: if 'text' in msg: stop_match = stop_pattern.match (msg['text']) http_get_rqst_match = http_get_rqst_pattern.match (msg['text']) if stop_match is not None: run_flag = False elif http_get_rqst_match is not None: uri = http_get_rqst_match.group (1) rqst = requests.get (uri) sc.rtm_send_message (direct_chan_id, "{0} reported status code {1}".format (uri, rqst.status_code)) else: sc.rtm_send_message (direct_chan_id, 'Unknown command: '+ repr(msg['text'])) else: raise Exception ("Unable to connect to slack.com")
"!register": register, "!withdraw": withdraw, "!price": price, "!market": market, "!calc": calc, "!help": help } while (True): try: data = sc.rtm_read() if (data): print(data) if ("subtype" in data[0] and "channel_join" in data[0]["subtype"]): user = data[0]["channel"] sc.rtm_send_message(user, "Welcome") if ("text" in data[0] and "C2ACQLM7B" not in data[0]["channel"]): message = clean(data[0]["text"]) channel = data[0]["channel"] user = data[0]["user"] print(message[0]) if "!" in message[0]: sc.rtm_send_message(channel, commands[message[0]](message, user)) elif ("C2ACQLM7B" in data[0]["channel"] and "!" in clean(data[0]["text"])[0]): sc.rtm_send_message(data[0]["channel"], "Please use bot in DM or in #bots-area") except: pass
class SlackAdapter(Adapter): def __init__(self, robot): super().__init__(robot) token = env.get("PYBOT_SLACK_TOKEN") if not token: raise RuntimeError("Missing environment variable PYBOT_SLACK_TOKEN") self.bot_id = None self.client = SlackClient(token) def send(self, message, text): self._send_message(message.room, text) def reply(self, message, text): thread = None if not self._is_direct_message(message.room): text = f"<@{message.user.id}>: {text}" thread = message.thread_id self._send_message(message.room, text, thread) def run(self): if not self.client.rtm_connect(): # TODO: use logger once implemented print("error: unable to connect to RTM service") return self._initialize() self._loop_forever() def _loop_forever(self): while True: events = self.client.rtm_read() if events: self._dispatch(events) sleep(0.1) def _initialize(self): name = self.client.server.username user = self._find_user(name) self.bot_id = user.id self.robot.name = user.name self.robot.emit("connected") def _dispatch(self, events): for event in events: type = event.get("type") if not type: continue # Ignore any events sent by the bot user = self._user_from_event(event) if user and user.id == self.bot_id: continue message = None if type == "message": # TODO: implement other interesting subtypes subtype = event.get("subtype") or "message" if subtype == "message": message = self._adapt_message(user, event) if message: self.receive(message) def _adapt_message(self, user, event): channel_id = event["channel"] text = event["text"] ts = event["ts"] thread_ts = event.get("thread_ts", ts) if self._is_direct_message(channel_id): # Pretend they mentioned the robot's name text = f"{self.robot.name} {text}" # TODO: chat threads return Message(user, channel_id, text, ts, thread_ts) def _user_from_event(self, event): user = event.get("user") if isinstance(user, dict): # In certain events, the user value of the event # will be the entire user instead of an ID. user = user.get("id") return self._find_user(user) def _send_message(self, channel_id, text, thread=None): self.client.rtm_send_message(channel_id, text, thread) def _find_user(self, name_or_id): return self.client.server.users.find(name_or_id) @staticmethod def _is_direct_message(channel_id): return (channel_id or "").startswith("D")
class SlackBackend(ErrBot): def __init__(self, config): super().__init__(config) identity = config.BOT_IDENTITY self.token = identity.get('token', None) if not self.token: log.fatal( 'You need to set your token (found under "Bot Integration" on Slack) in ' 'the BOT_IDENTITY setting in your configuration. Without this token I ' 'cannot connect to Slack.') sys.exit(1) self.sc = None # Will be initialized in serve_once self.md = imtext() def api_call(self, method, data=None, raise_errors=True): """ Make an API call to the Slack API and return response data. This is a thin wrapper around `SlackClient.server.api_call`. :param method: The API method to invoke (see https://api.slack.com/methods/). :param raise_errors: Whether to raise :class:`~SlackAPIResponseError` if the API returns an error :param data: A dictionary with data to pass along in the API request. :returns: The JSON-decoded API response :raises: :class:`~SlackAPIResponseError` if raise_errors is True and the API responds with `{"ok": false}` """ if data is None: data = {} response = json.loads( self.sc.server.api_call(method, **data).decode('utf-8')) if raise_errors and not response['ok']: raise SlackAPIResponseError("Slack API call to %s failed: %s" % (method, response['error']), error=response['error']) return response def serve_once(self): self.sc = SlackClient(self.token) log.info("Verifying authentication token") self.auth = self.api_call("auth.test", raise_errors=False) if not self.auth['ok']: raise SlackAPIResponseError( error="Couldn't authenticate with Slack. Server said: %s" % self.auth['error']) log.debug("Token accepted") self.bot_identifier = SlackIdentifier(self.sc, self.auth["user_id"]) log.info("Connecting to Slack real-time-messaging API") if self.sc.rtm_connect(): log.info("Connected") self.reset_reconnection_count() try: while True: for message in self.sc.rtm_read(): if 'type' not in message: log.debug("Ignoring non-event message: %s" % message) continue event_type = message['type'] event_handler = getattr( self, '_%s_event_handler' % event_type, None) if event_handler is None: log.debug( "No event handler available for %s, ignoring this event" % event_type) continue try: log.debug("Processing slack event: %s" % message) event_handler(message) except Exception: log.exception( "%s event handler raised an exception" % event_type) time.sleep(1) except KeyboardInterrupt: log.info("Interrupt received, shutting down..") return True except: log.exception("Error reading from RTM stream:") finally: log.debug("Triggering disconnect callback") self.disconnect_callback() else: raise Exception('Connection failed, invalid token ?') def _hello_event_handler(self, event): """Event handler for the 'hello' event""" self.connect_callback() self.callback_presence( Presence(identifier=self.bot_identifier, status=ONLINE)) def _presence_change_event_handler(self, event): """Event handler for the 'presence_change' event""" idd = SlackIdentifier(self.sc, event['user']) presence = event['presence'] # According to https://api.slack.com/docs/presence, presence can # only be one of 'active' and 'away' if presence == 'active': status = ONLINE elif presence == 'away': status = AWAY else: log.error( "It appears the Slack API changed, I received an unknown presence type %s" % presence) status = ONLINE self.callback_presence(Presence(identifier=idd, status=status)) def _team_join_event_handler(self, event): self.sc.parse_user_data((event['user'], )) def _message_event_handler(self, event): """Event handler for the 'message' event""" channel = event['channel'] if channel.startswith('C'): log.debug("Handling message from a public channel") message_type = 'groupchat' elif channel.startswith('G'): log.debug("Handling message from a private group") message_type = 'groupchat' elif channel.startswith('D'): log.debug("Handling message from a user") message_type = 'chat' else: log.warning("Unknown message type! Unable to handle") return subtype = event.get('subtype', None) if subtype == "message_deleted": log.debug("Message of type message_deleted, ignoring this event") return if subtype == "message_changed" and 'attachments' in event['message']: # If you paste a link into Slack, it does a call-out to grab details # from it so it can display this in the chatroom. These show up as # message_changed events with an 'attachments' key in the embedded # message. We should completely ignore these events otherwise we # could end up processing bot commands twice (user issues a command # containing a link, it gets processed, then Slack triggers the # message_changed event and we end up processing it again as a new # message. This is not what we want). log.debug( "Ignoring message_changed event with attachments, likely caused " "by Slack auto-expanding a link") return if 'message' in event: text = event['message']['text'] user = event['message']['user'] else: text = event['text'] user = event['user'] text = re.sub("<[^>]*>", self.remove_angle_brackets_from_uris, text) msg = Message(text, type_=message_type) if message_type == 'chat': msg.frm = SlackIdentifier(self.sc, user, event['channel']) msg.to = SlackIdentifier( self.sc, self.username_to_userid(self.sc.server.username), event['channel']) else: msg.frm = SlackMUCOccupant(self.sc, user, event['channel']) msg.to = SlackMUCOccupant( self.sc, self.username_to_userid(self.sc.server.username), event['channel']) self.callback_message(msg) def userid_to_username(self, id_): """Convert a Slack user ID to their user name""" user = [user for user in self.sc.server.users if user.id == id_] if not user: raise UserDoesNotExistError("Cannot find user with ID %s" % id_) return user[0].name def username_to_userid(self, name): """Convert a Slack user name to their user ID""" user = [user for user in self.sc.server.users if user.name == name] if not user: raise UserDoesNotExistError("Cannot find user %s" % name) return user[0].id def channelid_to_channelname(self, id_): """Convert a Slack channel ID to its channel name""" channel = [ channel for channel in self.sc.server.channels if channel.id == id_ ] if not channel: raise RoomDoesNotExistError("No channel with ID %s exists" % id_) return channel[0].name def channelname_to_channelid(self, name): """Convert a Slack channel name to its channel ID""" if name.startswith('#'): name = name[1:] channel = [ channel for channel in self.sc.server.channels if channel.name == name ] if not channel: raise RoomDoesNotExistError("No channel named %s exists" % name) return channel[0].id def channels(self, exclude_archived=True, joined_only=False): """ Get all channels and groups and return information about them. :param exclude_archived: Exclude archived channels/groups :param joined_only: Filter out channels the bot hasn't joined :returns: A list of channel (https://api.slack.com/types/channel) and group (https://api.slack.com/types/group) types. See also: * https://api.slack.com/methods/channels.list * https://api.slack.com/methods/groups.list """ response = self.api_call('channels.list', data={'exclude_archived': exclude_archived}) channels = [ channel for channel in response['channels'] if channel['is_member'] or not joined_only ] response = self.api_call('groups.list', data={'exclude_archived': exclude_archived}) # No need to filter for 'is_member' in this next call (it doesn't # (even exist) because leaving a group means you have to get invited # back again by somebody else. groups = [group for group in response['groups']] return channels + groups @lru_cache(50) def get_im_channel(self, id_): """Open a direct message channel to a user""" response = self.api_call('im.open', data={'user': id_}) return response['channel']['id'] def send_message(self, mess): super().send_message(mess) to_humanreadable = "<unknown>" try: if mess.type == 'groupchat': to_humanreadable = mess.to.username to_channel_id = mess.to.channelid else: to_humanreadable = mess.to.username to_channel_id = mess.to.channelid if to_channel_id.startswith('C'): log.debug( "This is a divert to private message, sending it directly to the user." ) to_channel_id = self.get_im_channel( self.username_to_userid(to_humanreadable)) log.debug('Sending %s message to %s (%s)' % (mess.type, to_humanreadable, to_channel_id)) body = self.md.convert(mess.body) log.debug('Message size: %d' % len(body)) fixed_format = body.startswith( '```\n') # hack to fix the formatting for part in split_string_after( body, min(self.bot_config.MESSAGE_SIZE_LIMIT, SLACK_MESSAGE_LIMIT)): if fixed_format: if not part.startswith('```\n'): part = '```\n' + part if not part.endswith('```') and not part.endswith('```\n'): part += '\n```\n' self.sc.rtm_send_message(to_channel_id, part) except Exception: log.exception( "An exception occurred while trying to send the following message " "to %s: %s" % (to_humanreadable, mess.body)) def build_identifier(self, txtrep): """ #channelname/username or @username """ log.debug("building an identifier from %s" % txtrep) txtrep = txtrep.strip() channelname = None if txtrep[0] == '@': username = txtrep[1:] elif txtrep[0] == '#': plainrep = txtrep[1:] if '/' not in txtrep: raise Exception( "Unparseable slack identifier, " + "should be #channelname/username or @username : '******'" % txtrep) channelname, username = plainrep.split('/') else: raise Exception( "Unparseable slack identifier, " + "should be #channelname/username or @username : '******'" % txtrep) userid = self.username_to_userid(username) if channelname: channelid = self.channelname_to_channelid(channelname) return SlackMUCOccupant(self.sc, userid, channelid) return SlackIdentifier(self.sc, userid, self.get_im_channel(userid)) def build_reply(self, mess, text=None, private=False): msg_type = mess.type response = self.build_message(text) response.frm = self.bot_identifier response.to = mess.frm response.type = 'chat' if private else msg_type return response def shutdown(self): super().shutdown() @deprecated def join_room(self, room, username=None, password=None): return self.query_room(room) @property def mode(self): return 'slack' def query_room(self, room): """ Room can either be a name or a channelid """ if room.startswith('C') or room.startswith('G'): return SlackRoom(channelid=room, bot=self) m = SLACK_CLIENT_CHANNEL_HYPERLINK.match(room) if m is not None: return SlackRoom(channelid=m.groupdict()['id'], bot=self) return SlackRoom(name=room, bot=self) def rooms(self): """ Return a list of rooms the bot is currently in. :returns: A list of :class:`~SlackRoom` instances. """ channels = self.channels(joined_only=True, exclude_archived=True) return [ SlackRoom(channelid=channel['id'], bot=self) for channel in channels ] def prefix_groupchat_reply(self, message, identifier): message.body = '@{0}: {1}'.format(identifier.nick, message.body) def remove_angle_brackets_from_uris(self, match_object): if "://" in match_object.group(): return match_object.group().strip("<>") return match_object.group()
class SlackBackend(ErrBot): def __init__(self, config): super().__init__(config) identity = config.BOT_IDENTITY self.token = identity.get('token', None) if not self.token: log.fatal( 'You need to set your token (found under "Bot Integration" on Slack) in ' 'the BOT_IDENTITY setting in your configuration. Without this token I ' 'cannot connect to Slack.' ) sys.exit(1) self.sc = None # Will be initialized in serve_once def api_call(self, method, data=None, raise_errors=True): """ Make an API call to the Slack API and return response data. This is a thin wrapper around `SlackClient.server.api_call`. :param method: The API method to invoke (see https://api.slack.com/methods/). :param raise_errors: Whether to raise :class:`~SlackAPIResponseError` if the API returns an error :param data: A dictionary with data to pass along in the API request. :returns: The JSON-decoded API response :raises: :class:`~SlackAPIResponseError` if raise_errors is True and the API responds with `{"ok": false}` """ if data is None: data = {} response = json.loads(self.sc.server.api_call(method, **data).decode('utf-8')) if raise_errors and not response['ok']: raise SlackAPIResponseError("Slack API call to %s failed: %s" % (method, response['error'])) return response def serve_once(self): self.sc = SlackClient(self.token) log.info("Verifying authentication token") self.auth = self.api_call("auth.test", raise_errors=False) if not self.auth['ok']: raise SlackAPIResponseError("Couldn't authenticate with Slack. Server said: %s" % self.auth['error']) log.debug("Token accepted") self.bot_identifier = SlackIdentifier(self.sc, self.auth["user_id"]) log.info("Connecting to Slack real-time-messaging API") if self.sc.rtm_connect(): log.info("Connected") self.reset_reconnection_count() try: while True: for message in self.sc.rtm_read(): if 'type' not in message: log.debug("Ignoring non-event message: %s" % message) continue event_type = message['type'] event_handler = getattr(self, '_%s_event_handler' % event_type, None) if event_handler is None: log.debug("No event handler available for %s, ignoring this event" % event_type) continue try: log.debug("Processing slack event: %s" % message) event_handler(message) except Exception: log.exception("%s event handler raised an exception" % event_type) time.sleep(1) except KeyboardInterrupt: log.info("Interrupt received, shutting down..") return True except: log.exception("Error reading from RTM stream:") finally: log.debug("Triggering disconnect callback") self.disconnect_callback() else: raise Exception('Connection failed, invalid token ?') def _hello_event_handler(self, event): """Event handler for the 'hello' event""" self.connect_callback() self.callback_presence(Presence(identifier=self.bot_identifier, status=ONLINE)) def _presence_change_event_handler(self, event): """Event handler for the 'presence_change' event""" idd = SlackIdentifier(self.sc, event['user']) presence = event['presence'] # According to https://api.slack.com/docs/presence, presence can # only be one of 'active' and 'away' if presence == 'active': status = ONLINE elif presence == 'away': status = AWAY else: log.error( "It appears the Slack API changed, I received an unknown presence type %s" % presence ) status = ONLINE self.callback_presence(Presence(identifier=idd, status=status)) def _message_event_handler(self, event): """Event handler for the 'message' event""" channel = event['channel'] if channel.startswith('C'): log.debug("Handling message from a public channel") message_type = 'groupchat' elif channel.startswith('G'): log.debug("Handling message from a private group") message_type = 'groupchat' elif channel.startswith('D'): log.debug("Handling message from a user") message_type = 'chat' else: log.warning("Unknown message type! Unable to handle") return subtype = event.get('subtype', None) if subtype == "message_deleted": log.debug("Message of type message_deleted, ignoring this event") return if subtype == "message_changed" and 'attachments' in event['message']: # If you paste a link into Slack, it does a call-out to grab details # from it so it can display this in the chatroom. These show up as # message_changed events with an 'attachments' key in the embedded # message. We should completely ignore these events otherwise we # could end up processing bot commands twice (user issues a command # containing a link, it gets processed, then Slack triggers the # message_changed event and we end up processing it again as a new # message. This is not what we want). log.debug( "Ignoring message_changed event with attachments, likely caused " "by Slack auto-expanding a link" ) return if 'message' in event: text = event['message']['text'] user = event['message']['user'] else: text = event['text'] user = event['user'] msg = Message(text, type_=message_type) if message_type == 'chat': msg.frm = SlackIdentifier(self.sc, user, event['channel']) msg.to = SlackIdentifier(self.sc, self.username_to_userid(self.sc.server.username), event['channel']) else: msg.frm = SlackMUCOccupant(self.sc, user, event['channel']) msg.to = SlackMUCOccupant(self.sc, self.username_to_userid(self.sc.server.username), event['channel']) msg.nick = msg.frm.userid self.callback_message(msg) def userid_to_username(self, id): """Convert a Slack user ID to their user name""" user = [user for user in self.sc.server.users if user.id == id] if not user: raise UserDoesNotExistError("Cannot find user with ID %s" % id) return user[0].name def username_to_userid(self, name): """Convert a Slack user name to their user ID""" user = [user for user in self.sc.server.users if user.name == name] if not user: raise UserDoesNotExistError("Cannot find user %s" % name) return user[0].id def channelid_to_channelname(self, id): """Convert a Slack channel ID to its channel name""" channel = [channel for channel in self.sc.server.channels if channel.id == id] if not channel: raise RoomDoesNotExistError("No channel with ID %s exists" % id) return channel[0].name def channelname_to_channelid(self, name): """Convert a Slack channel name to its channel ID""" if name.startswith('#'): name = name[1:] channel = [channel for channel in self.sc.server.channels if channel.name == name] if not channel: raise RoomDoesNotExistError("No channel named %s exists" % name) return channel[0].id def channels(self, exclude_archived=True, joined_only=False): """ Get all channels and groups and return information about them. :param exclude_archived: Exclude archived channels/groups :param joined_only: Filter out channels the bot hasn't joined :returns: A list of channel (https://api.slack.com/types/channel) and group (https://api.slack.com/types/group) types. See also: * https://api.slack.com/methods/channels.list * https://api.slack.com/methods/groups.list """ response = self.api_call('channels.list', data={'exclude_archived': exclude_archived}) channels = [channel for channel in response['channels'] if channel['is_member'] or not joined_only] response = self.api_call('groups.list', data={'exclude_archived': exclude_archived}) # No need to filter for 'is_member' in this next call (it doesn't # (even exist) because leaving a group means you have to get invited # back again by somebody else. groups = [group for group in response['groups']] return channels + groups @lru_cache(50) def get_im_channel(self, id): """Open a direct message channel to a user""" response = self.api_call('im.open', data={'user': id}) return response['channel']['id'] def send_message(self, mess): super().send_message(mess) to_humanreadable = "<unknown>" try: if mess.type == 'groupchat': to_humanreadable = mess.to.username to_channel_id = mess.to.channelid else: to_humanreadable = mess.to.username to_channel_id = mess.to.channelid log.debug('Sending %s message to %s (%s)' % (mess.type, to_humanreadable, to_channel_id)) self.sc.rtm_send_message(to_channel_id, mess.body) except Exception: log.exception( "An exception occurred while trying to send the following message " "to %s: %s" % (to_humanreadable, mess.body) ) def build_message(self, text): return build_message(text, Message) def build_identifier(self, txtrep): """ #channelname/username or @username """ log.debug("building an identifier from %s" % txtrep) txtrep = txtrep.strip() channelname = None if txtrep[0] == '@': username = txtrep[1:] elif txtrep[0] == '#': plainrep = txtrep[1:] if '/' not in txtrep: raise Exception("Unparseable slack identifier, " + "should be #channelname/username or @username : '******'" % txtrep) channelname, username = plainrep.split('/') else: raise Exception("Unparseable slack identifier, " + "should be #channelname/username or @username : '******'" % txtrep) userid = self.username_to_userid(username) if channelname: channelid = self.channelname_to_channelid(channelname) return SlackMUCOccupant(self.sc, userid, channelid) return SlackIdentifier(self.sc, userid, self.get_im_channel(userid)) def build_reply(self, mess, text=None, private=False): msg_type = mess.type response = self.build_message(text) response.frm = self.bot_identifier response.to = mess.frm response.type = 'chat' if private else msg_type return response def is_admin(self, usr): return usr.split('@')[0] in self.bot_config.BOT_ADMINS def shutdown(self): super().shutdown() @deprecated def join_room(self, room, username=None, password=None): return self.query_room(room) @property def mode(self): return 'slack' def query_room(self, room): """ Room can either be a name or a channelid """ if room.startswith('C') or room.startswith('G'): return SlackRoom(channelid=room, bot=self) m = SLACK_CLIENT_CHANNEL_HYPERLINK.match(room) if m is not None: return SlackRoom(channelid=m.groupdict()['id'], bot=self) return SlackRoom(name=room, bot=self) def rooms(self): """ Return a list of rooms the bot is currently in. :returns: A list of :class:`~SlackRoom` instances. """ channels = self.channels(joined_only=True, exclude_archived=True) return [SlackRoom(channelid=channel['id'], bot=self) for channel in channels] def groupchat_reply_format(self): return '@{0}: {1}'
def parcel_help(): pass if sc.rtm_connect(): while sc.server.connected is True: msg_from_slack = sc.rtm_read() if msg_from_slack: print "got something from slack: {} ".format(msg_from_slack) if 'text' in msg_from_slack[0].keys( ) and msg_from_slack[0]['text'].encode( 'ascii', 'ignore').startswith('@mailboy'): print msg_from_slack[0]['text'][8::] if msg_from_slack[0]['text'][8::].strip() == 'testing': sc.rtm_send_message("CBCK26G31", "I'm fine!") elif msg_from_slack[0]['text'][8::].strip() == 'help': print "You need help!" help_msg = '''You can type any of the following to interact with me:\n@mailboy username,\n@mailboy testing,\n@mailboy quicklookid ''' sc.rtm_send_message("CBECMBL01", help_msg) else: #suppose everything is handled from here parcel_help() #----make slack bot more interesting! question_slack = msg_from_slack[0]['text'][8::].strip() try: question = 'python quepy/examples/dbpedia/main.py ' + question_slack res = os.popen(question).read()
class Bot(object): """Slack bot class. Handle all basic greeting to member rolling standup, including timeframe of each standup. """ """Attributes.""" token = None channels = [] reports = [] client = None login_data = None end_time = None def __init__(self, token, timeout, secret=""): """Initialize bot instance. token: slack bot authorization token """ self.headers = { "secret": secret, "Content-Type": "application/json", "Accept": "application/json" } self.timeout = timeout self.token = token def start(self): """Boot up slack bot.""" self.client = SlackClient(self.token) if self.client.rtm_connect(): self.login_data = self.client.get_login_data() logging.info("bot running") for channel in self.get_all_channels(): if channel['name'] in self.channels: self.reports.append(self.standup_start(channel)) return self.reports def set_channels(self, channels): """Pass list of channel to execute standup. :channels array of channels """ self.channels = channels return self def greet(self, channel): """Initial greeting. channel: target channel name """ self.client.rtm_send_message( channel, "Hello, We'll start the stand up \ soon.") def farewell(self, channel): """Sum up the standups. channel: target channel name """ self.client.rtm_send_message( channel, "Looks like that's it for today \ Thanks for your effort today") def is_bot(self, member): """Check if member is current bot. member: specified member id """ return self.login_data['id'] == member def extract_slack_message(self, message): """Extract slack message body. message: response from slack """ text, user, channel = message.get('text'), message.get( 'user'), message.get('channel') if not text or not user or not channel or user == self.login_data['id']: return None return {'user': user, 'text': text, 'channel': channel} def fetch_user_data(self, member): """Fetch user data from userid. member: userid on slack """ response = self.client.api_call("users.info", user=member) result = { 'email': response['user']['profile']['email'], 'username': response['user']['name'], 'real_name': response['user']['real_name'] } return result def exec_member(self, member, channel): """Loop through every questions, and pass to user. member: interacted member. """ ongoing = True count = -1 data = {} response = {} data['user'] = self.fetch_user_data(member) # bot start self.client.rtm_send_message( channel, """ Hello <@{}> type anything to begin,\ or `skip` if you want to skip for \ today. """.format(member)) member_time_out = datetime.now() + timedelta(seconds=int(self.timeout)) while ongoing: if datetime.now() > member_time_out: response['message'] = "timeout" self.client.rtm_send_message( channel, "<@{}> is not available \ Let's move to another member.".format(member)) break for slack_message in self.client.rtm_read(): # Start listening for message message = self.extract_slack_message(slack_message) if message is None: continue if message['channel'] != channel or message['user'] != member: continue if message['text'].lower() == 'skip': response['message'] = "skipped" self.client.rtm_send_message(message['channel'], 'okay') ongoing = False break elif count < 0 and message['text'].lower( ) not in constants.POSITIVE: continue if count >= 0: response[self.questions[count]] = message['text'] else: response['init'] = message['text'] count += 1 if count >= len(self.questions): ongoing = False break # reset timeout variables after each answer member_time_out = datetime.now() + timedelta( seconds=int(self.timeout)) self.client.rtm_send_message(message['channel'], self.questions[count]) data['response'] = response self.client.rtm_send_message(channel, "Thanks <@{}>.".format(member)) return data def standup_start(self, channel): """Start stand up on channel. channel: respective channel """ report = {} report['channel'] = channel['name'] report['members'] = [] self.greet(channel['id']) members = self.get_members(channel['id']) for member in members: if self.is_bot(member): continue member_report = self.exec_member(member, channel['id']) report['members'].append(member_report) self.farewell(channel['id']) return report def get_all_channels(self): """Get all channel associated with current bot.""" response = self.client.api_call("channels.list") return response['channels'] def get_members(self, channel): """Get members of channel. channel: channel name """ response = self.client.api_call("channels.info", channel=channel) return response['channel']['members'] def set_questions(self, questions): """Set question to be asked. questions: array of questions """ self.questions = questions return self def push_question(self, question): """Push question to queue. question: Question object to be pushed. """ self.questions.append(question) return self def send_report(self, hook): """Send report to hook. hook: endpoint to receive the report """ payload = json.dumps(self.reports) try: response = requests.post(hook, headers=self.headers, data=payload) return response except requests.exceptions.RequestException as e: logging.warning(e) return payload
class PartyQueueBot: def __init__(self, config): self.client = SlackClient( token=config.slack_token, client_id=config.slack_client_id, client_secret=config.slack_client_secret ) self.bot_user_id = self._get_user_id() self.bot_mention = '<@{id_}>'.format(id_=self.bot_user_id) self.mobile_client = MobileClientWrapper(config) self.queue = PartyQueueController(self.mobile_client) self.track_controller = TrackController(self.mobile_client) self.search_controller = SearchController(self.mobile_client) def _get_user_id(self): users = self.client.api_call('users.list') return [user for user in users['members'] if user['name'] == 'party_queue'][0]['id'] def start_real_time_messaging(self): """ Starts Real Time Messaging """ if self.client.rtm_connect(): print('PartyQueue up and listening! Ctrl+C to break.') try: while True: last_read = self.client.rtm_read() if not last_read: continue last_read = last_read[0] last_read.setdefault('type', '') last_read.setdefault('text', '') if last_read['type'] == 'message' and self.bot_mention in last_read['text']: self.handle_message(last_read) except KeyboardInterrupt: print('Cleaning up and logging out...') self.queue.close_party_queue() self.mobile_client.logout() def handle_message(self, last_read_message): """ Handles a slack message :param last_read_message: dict of last read message """ parsed_text = last_read_message['text'] origin = last_read_message['channel'] sender_user_id = last_read_message['user'] if 'queue' in parsed_text.lower(): self.get_queue_contents(origin) elif 'search' in parsed_text.lower(): self.search_songs(origin, self.get_query(parsed_text.lower(), 'search')) elif 'add' in parsed_text.lower(): self.add_song_by_name_and_title(origin, self.get_query(parsed_text.lower(), 'add'), sender_user_id) else: self.client.rtm_send_message(origin, 'I don\'t understand your stupid request.') @staticmethod def get_query(message, command): """ Pulls out actual query from message string :param message: the message string :param command: the PartyQueue command string used in the message :return: query string """ return message[message.index(command)+len(command)+1:] def get_queue_contents(self, origin): """ Posts PartyQueue Entries to chat :param origin: channel where request originated """ queue_tracks = self.queue.get_party_queue_tracks() if len(queue_tracks): text = '*Songs in the PartyQueue ({share}):*' \ '\n*-------------------------*\n'.format(share=self.queue.share_url()) for index, track in enumerate(queue_tracks, start=1): text += '{count}. {artist} | {title}\n'.format(count=index, artist=track.artist, title=track.title) else: text = 'No Songs Currently in the Queue ({share})'.format(share=self.queue.share_url()) self.client.rtm_send_message(origin, text) def search_songs(self, origin, query): """ Posts results of search made on given query to chat :param origin: channel where request originated :param query: search query """ text = '*Search Results for \'{query}\'*\n*-------------------------*\n'.format(**locals()) for index, track in enumerate(self.search_controller.get_search_results(query), start=1): self.track_controller.add_track_to_repo(track) track_text = '{count}. {artist} | {title}\n'.format(count=index, artist=track.artist, title=track.title) text += track_text self.client.rtm_send_message(origin, text) def add_song_by_name_and_title(self, origin, artist_song_string, slack_user_id): """ Adds a Song to the PartyQueue and Posts a notification :param origin: channel where request originated :param artist_song_string: Name of the song to add :param slack_user_id: ID of the slack user who requested the song """ split_list = artist_song_string.split('|') artist = split_list[0].strip() track_name = split_list[1].strip() track = self.track_controller.get_track_by_artist_and_name(artist, track_name) if track is None: text = '*Could not find song {title}, try searching for it first*'.format(title=track_name.title()) else: self.queue.add_to_play_list(track.store_id, slack_user_id) text = '*Added {title} to the Party Queue*'.format(title=track.title) self.client.rtm_send_message(origin, text)