Пример #1
0
def slack_notifier(slack_token, secret_conf_path, server, user, password, build_url):
    branches = run_command("git branch")
    branch_name_reg = re.search("\* (.*)", branches)
    branch_name = branch_name_reg.group(1)

    if branch_name == 'master':
        print_color("Starting Slack notifications about instances", LOG_COLORS.GREEN)
        attachments, integrations_counter = get_attachments(secret_conf_path, server, user, password, build_url)

        sc = SlackClient(slack_token)
        sc.api_call(
            "chat.postMessage",
            channel="devops-events",
            username="******",
            as_user="******",
            attachments=attachments,
            text="You have {0} instances configurations".format(integrations_counter)
        )

        sc.api_call(
            "chat.postMessage",
            channel="content-lab-tests",
            username="******",
            as_user="******",
            attachments=attachments,
            text="You have {0} instances configurations".format(integrations_counter)
        )
Пример #2
0
class Output(cowrie.core.output.Output):

    def __init__(self):
        self.slack_channel = CONFIG.get('output_slack', 'channel')
        self.slack_token = CONFIG.get('output_slack', 'token')
        cowrie.core.output.Output.__init__(self)

    def start(self):
        pass

    def stop(self):
        pass

    def write(self, logentry):
        for i in list(logentry.keys()):
            # Remove twisted 15 legacy keys
            if i.startswith('log_'):
                del logentry[i]

        self.sc = SlackClient(self.slack_token)
        self.sc.api_call(
            "chat.postMessage",
            channel=self.slack_channel,
            text="%s %s" % (time.strftime('%Y-%m-%d %H:%M:%S'), json.dumps(logentry, indent=4, sort_keys=True))
        )
Пример #3
0
def main():
    response = ''
    scope = ['https://www.googleapis.com/auth/analytics.readonly']
    key_file_location = '_analytics-key.json'

    service = get_service('analytics', 'v3', scope, key_file_location)
    profile = get_first_profile_id(service)

    metrics = 'rt:activeUsers'
    dimensions = 'rt:referralPath,rt:source'
    sort = '-rt:activeUsers'

    detailed = get_detailed_totals(get_results(service, profile, metrics=metrics, dimensions=dimensions, sort=sort))
    total_active = detailed[0]
    details = detailed[1]

    if int(total_active) >= 500 :
        try:
            # e.g. _slack-key.json
            # {"token": "<slack token>"}
            with open('_slack-key.json') as json_file:
                json_data = json.load(json_file)
            token = json_data['token']
            sc = SlackClient(token)
            chan = 'google-analytics'
            message = '\n*Google Analytics Real-Time*\n Active Users:\t*' + total_active + '*\n' + details
            # View this post for GAE requests error
            # https://github.com/kennethreitz/requests/compare/master...agfor:master
            print sc.api_call('chat.postMessage', as_user='******', channel=chan, text=message)
            print ('************ DONE ***************')
            response = 'Posted message to Slack #google-analytics'
        except HTTPError, error:
            response = ('Arg, there was an API error : %s : %s' %
                        (error.resp.status, error._get_reason()))
Пример #4
0
 def check(self):
     sc = SlackClient(self.config["bot"]["token"])
     history = sc.api_call("channels.history", channel=self.config["bot"]["channel"], oldest=self.lastcheck )
     botname = "%s" % self.config["bot"]["name"]
     #sometimes there are no messages!
     if "messages" in history:
         for message in history["messages"]:
             if botname in message["text"]:
                 timestamp = message["ts"]
                 command = message["text"].split(" ")
                 if command[1] == self.config["hostname"]:
                     if command[2] == "df":
                         self._action_df()    
                         self._set_lastcheck(timestamp)
                     elif command[2] == "mem":
                         self._action_mem()
                         self._set_lastcheck(timestamp)
                     elif command[2] == "top":
                         self._action_top()
                         self._set_lastcheck(timestamp)
                     else:
                         self._send_message("I don't know what this action is '%s'. Supported actions: df, mem, top" % command[2])
                         sc.api_call("chat.postMessage", as_user="******", channel=self.config["bot"]["channel"], text="I don't know what this action is '%s'. Supported actions: df, mem, top" % command[2])
                         self._set_lastcheck(timestamp)
                 elif command[1] == "rollcall":
                     self._send_message("%s on %s reporting in" % (self.config["bot"]["name"], self.config["hostname"]))    
Пример #5
0
def process_message(data):
        token = "xoxo"    # Your Slack Token
        sc = SlackClient(token)
        print sc.api_call("users.info",user=data['user'])
        print sc.api_call("channels.info",channel=data['channel'])

        Greetings = ['Hi', 'Hello', 'hi', 'hello', 'HI', 'HELLO']
        marco = ['Marco']
        polo = ['Polo']

        # Say Hello
        for greeting in Greetings:

                if greeting in data['text']:
                        sendstring = "Say Marco"
                        outputs.append([data['channel'], sendstring])
        # Say marco
        for m in marco:

                if m in data['text'] or m.lower() in data['text'] or m.upper() in data['text']:
                        sendstring = "Polo!\nSay it again"
                        outputs.append([data['channel'], sendstring])

        # Say polo
        for p in polo:

                if p in data['text'] or p.lower() in data['text'] or p.upper() in data['text']:
                        sendstring = "Marco!\nBut next time say Marco"
                        outputs.append([data['channel'], sendstring])
                break
def postNotification(token, channelID, service, calendar, timePeriod):

    events = []
    message = ""
    sc = SlackClient(token)

    if timePeriod == "today":
        events = get_todays_events(token, channelID, service, calendar)
    elif timePeriod == "this week":
        events = get_weeks_events(token, channelID, service, calendar)
    elif timePeriod == "this month":
        events = get_months_events(token, channelID,service, calendar)

    if not events:
        period = "*_No events scheduled for " + timePeriod + " :sleepy:  _*\n"
    for event in events:
        period = "*_Here are the events happening " + timePeriod + "  :smile: _*\n"
        period = period.encode('utf-8')
        start_date = dateutil.parser.parse(event['start'].get('dateTime'))
        start_date = start_date.strftime("%A, %B %d %Y @ %I:%M %p")
        end_date = dateutil.parser.parse(event['end'].get('dateTime'))
        end_date = end_date.strftime("%A, %B %d %Y @ %I:%M %p")
        message += "\n - " + "*" + event['summary'] + "*" + "\n"+ start_date + " to " + end_date + "\n" + "*Where:* " + event['location'] + "\n" + "*Description:* " + event['description'] + "\n" + event['htmlLink'] + "\n"
        message = message.encode('utf-8')
        
    sc.api_call("chat.postMessage",username="******",channel=channelID,text=period + message)
Пример #7
0
def router():

    _logger = get_logger(__name__)
    if request.form.get("token") == os.environ.get("SLACK_WEBHOOK_SECRET"):

        # Get info from incoming request
        channel_id = request.form.get("channel_id")
        user = request.form.get("user_name")
        message = request.form.get("text")
        _logger.info("Incoming message from {0} on {1}: {2}".format(channel_id, user, message))

        # Parse and route
        try:
            response = parse_message(message, user)
        except Exception as e:
            response = fail(e, user)
        slack_client = SlackClient(os.environ.get("SLACK_TOKEN"))
        slack_client.api_call(
            "chat.postMessage",
            channel=channel_id,
            username='******',
            icon_emoji=':sausage:',
            **response
        )

    return Response(), 200
Пример #8
0
def _register_deployment():
    branch = local('git rev-parse --abbrev-ref HEAD', capture=True)
    author = local('git log -1 --pretty=format:"%an"', capture=True)
    commit = local('git log -1 --pretty=format:"%B"', capture=True)
    git_url = f'https://github.com/CDE-UNIBE/qcat/tree/{branch}'

    sc = SlackClient(settings.SLACK_TOKEN)

    sc.api_call(
        'chat.postMessage',
        channel='server-info',
        username='******',
        text=f'Branch "{branch}" deployed: {git_url}',
        attachments=[
            {
                'pretext': f'Great success!',
                'title': commit,
                'title_link': git_url,
                'fields': [
                    {
                        'title': 'Branch',
                        'value': 'develop',
                        'short': False
                    },
                    {
                        'title': 'Author',
                        'value': author,
                        'short': False
                    }
                ],
                'image_url': 'https://qcat.wocat.net/static/assets/favicons/favicon-32x32.png'
            }
        ]
    )
Пример #9
0
def slack():
	logs.write("In slack function in new thread", 'working')
	sc = SlackClient(token)
	if sc.rtm_connect():
		logs.write("Connected to rtm socket", 'success')
    	while True:
    		time.sleep(0.1)
        	message=sc.rtm_read()
        	if message!=[]:
        		if message[0].keys()[0]=='text':
        			command=message[0].values()[0]
        			logs.write(command,'working')
        			try:
        				command=json.loads(command)
        			except ValueError:
        				command=[{'type':'command'},{'devices':'all'},{'action':"{0}".format(command)}]
        			commandtype=command[0]
        			devices=command[1]
        			action=command[2]
        			if devices.values()[0]=='all' or devices.values()[0]=="XPS":
	        			logs.write("Checking local W.I.L.L server", 'trying')
	        			answer=requests.get('http://127.0.0.1:5000/?context=command&command={0}'.format(action.values()[0])).text
	        			print sc.api_call( "chat.postMessage", channel="#w_i_l_l", text="{0}".format(answer), username='******')
	else:
		logs.write("Connection Failed, invalid token?", 'error')
Пример #10
0
def citigroup_slack_bot():
    bot_token = SECRETS_DICT['CITIGROUP_SLACKBOT_TOKEN']
    sc = SlackClient(bot_token)

    log_message_window = datetime.timedelta(hours=12)
    oldest_window = datetime.datetime.now() - log_message_window
    oldest_window = time.mktime(oldest_window.timetuple())

    cronbox_channel_id = 'C0KC1FWNA'
    cronbox_messages = sc.api_call('channels.history', channel=cronbox_channel_id, oldest=oldest_window)
    cronbox_messages_dict = json.loads(cronbox_messages)
    found_git_sync = False
    for message in cronbox_messages_dict['messages']:
        if 'synced crontab with git' in message['text']:
            found_git_sync = True

    warnings_channel_id = 'C0KCAG7AL'
    if not found_git_sync:
        sc.api_call('chat.postMessage', channel=warnings_channel_id,
                    text='@channel: did not find message with "synced crontab with git" '
                         'in channel #cronbox. '
                         'This suggests that cronbox is not syncing its crontab with git. ', link_names=1)
    else:
        sc.api_call('chat.postMessage', channel=warnings_channel_id,
                    text='k')
Пример #11
0
 def fail_message(self):
     sc = SlackClient(self.bot_token)
     sc.api_call(
         "chat.postMessage", channel=self.channel_id,
         text="Sorry <@{}|{}> not sure if I can do that".format(self.reply_user_id, self.reply_user_name),
         username=self.username, as_user="******", icon_emoji=':instapaper:')
     return 200
Пример #12
0
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?"
Пример #13
0
def slack():
	'''Slack rtm reader started in seprate thread'''
	logs.write("In slack function in new thread", 'working')
	sc = SlackClient(token)
	if sc.rtm_connect():
		logs.write("Connected to rtm socket", 'success')
    	while True:
    		time.sleep(0.1)
    		#Get message from rtm socket
        	message=sc.rtm_read()
        	#If the message isn't empty
        	if message!=[]:
        		#If the message is text as opposed to a notification. Eventually plan to have other kinds of messages in a backend communications channel.
        		if message[0].keys()[0]=='text':
        			command=message[0].values()[0]
        			logs.write(command,'working')
        			#The commands are json or plain text. If it isn't a json backend command, interpret it as a "normal" command
        			try:
        				command=json.loads(command)
        			except ValueError:
        				command=[{'type':'command'},{'devices':'all'},{'action':"{0}".format(command)}]
        			#Json slack commands or management can eventually be formatted like so: [{"type":"management/command",{"devices":"all/mobile/desktop/network/device name"},{"action":"message content"}]
        			#Not sure if I want to do that in the backend or command channel or what really, but I'm definitely working with it. 
        			commandtype=command[0]
        			devices=command[1]
        			action=command[2]
        			#Replace thisdevicename with whatever you want to name yours in the W.I.L.L slack network (obviously)
        			if devices.values()[0]=='all' or devices.values()[0]=="thisdevicename":
	        			logs.write("Checking local W.I.L.L server", 'trying')
	        			#Hit W.I.L.L with the command. This is also where you could add exceptions or easter eggs
	        			answer=requests.get('http://127.0.0.1:5000/?context=command&command={0}'.format(action.values()[0])).text
	        			print sc.api_call( "chat.postMessage", channel="#w_i_l_l", text="{0}".format(answer), username='******')
	else:
		logs.write("Connection Failed, invalid token?", 'error')
Пример #14
0
def ask_question(question):
    answer = question['answer']
    hints = list()
    hint = ["`Подсказка: "] + ['.']*len(answer) + ['`']
    hints.append("".join(hint))
    offset = 1
    rand_indexes = list(range(len(answer)))
    random.shuffle(rand_indexes)
    for i in rand_indexes:
        hint[offset+i] = answer[i]
        hints.append("".join(hint))
    sc = SlackClient(BOT_TOKEN)

    # TODO: add post_to_channel function
    sc.api_call(
        "chat.postMessage",
        as_user="******",
        channel=CHANNEL,
        text="#" + str(question['id']) + ": " + question['text']
    )
    yield from asyncio.sleep(5)
    for i, hint in enumerate(hints):
        sc.api_call(
            "chat.postMessage",
            as_user="******",
            channel=CHANNEL,
            text=hint
        )
        if i < len(hints) - 1:
            yield from asyncio.sleep(3.5)
Пример #15
0
def marcopolo_bot():
    # Insert API token from Slack
    # My token was disabled as soon as I uploaded it to Git, another token must be generated 
    token = 'xoxb-55268990450-WzfkM0A5ufihTTElZ8k6sC33'
    # Creating the slackclient object/instance 
    sc = SlackClient(token)
    # Connect to Slack
    if sc.rtm_connect():
        
        while True:
            # Read latest messages as long as connected to Slack
            rtm_responses = sc.rtm_read()
            # Check every instance of potential response and check for text response 
            for rtm_response in rtm_responses:
                if 'text' in rtm_response:
                    # If response is found as 'marco', call API function to respond with 'polo'
                    if rtm_response['text'] == 'marco':
                        sc.api_call(
                            "chat.postMessage", channel="marco-polo", text="polo",
                            username='******', icon_emoji=':robot_face:'
                        )
            
            time.sleep(1)

    else:
        quit()
Пример #16
0
class Slack:

    def __init__(self, config, token_file):
        self.disabled = True
        try:
            from slackclient import SlackClient
        except:
            return

        try:
            self.channel = config['channel']
            self.method = config['method']
            self.username = config['username']
            self.emoji = config['emoji']
        except (TypeError, KeyError) as e:
            return

        try:
            with open(token_file) as stoken:
                r = stoken.readlines()
            slack_token = ''.join(r).strip()
            self.client = SlackClient(slack_token)
        except IOError:
            return

        self.disabled = False

    def api_call(self, text):
        if not self.disabled:
            self.client.api_call(self.method, channel=self.channel,
                                 username=self.username, icon_emoji=self.emoji, text=text)
            print ("Your current configuration for slack notifications is deprecated! Please switch to latest configuration.")
Пример #17
0
class SlackAPI(object):
    def __init__(self, token, username="******"):
        self.client = SlackClient(token)
        self._all_channels = self._get_channels()
        self.username = username

    def _get_channels(self):
        res = self.client.api_call("channels.list")
        _channels = json.loads(res.decode())
        _parsed_channels = _channels.get("channels", None)
        if _parsed_channels is None:
            raise Exception("Could not get Slack channels. Are you sure your token is correct?")
        return _parsed_channels

    def get_channels(self, reload_channels=False):
        if not self._all_channels or reload_channels:
            self._all_channels = self._get_channels()
        return self._all_channels

    def channel_name_to_id(self, channel_name):
        for channel in self._all_channels:
            if channel["name"] == channel_name:
                return channel["id"]
        raise ChannelNotFoundError("Channel {} not in the list of available channels".format(channel_name))

    def bulk_message(self, message, post_to=[]):
        for channel in post_to:
            if not channel.startswith("@"):
                channel = self.channel_name_to_id(channel)
            logging.debug("Posting message to {}".format(channel))
            self.client.api_call("chat.postMessage", text=message, channel=channel, username=self.username)
        return True
Пример #18
0
def send_message(channel, message, username):
    slack_token = os.environ.get('SLACK_API_TOKEN')
    client = SlackClient(slack_token)
    client.api_call(
        'chat.postMessage',
        channel=channel, text=message, username=username
    )
Пример #19
0
class BasicSlackClient:
    """
    Basic slack client.git
    """
    def __init__(self, token: str, default_channel: str, default_username: str):
        """
        Constructor.
        :param token: authentication tocken from BasicSlackClient
        """
        self._default_channel = default_channel
        self._default_username = default_username
        self._slack_client = SlackClient(token)

    def post(self, message: str, channel: str=None, username: str=None):
        """
        Post the given message to the given channel as the given username.
        :param message: the message to post
        :param channel: the channel to post to
        :param username: the username to post as
        """
        if channel is None:
            channel = self._default_channel
        if username is None:
            username = self._default_username

        self._slack_client.api_call(_SLACK_CLIENT_POST_MESSAGE, channel=channel, text=message, username=username)
Пример #20
0
def sendSlackAlert(token, channel, username, *args):
	sc = SlackClient(token)
	sc.api_call(
		"chat.postMessage", 
		channel=str(channel), 
		text=args[0] + "\n",
		username=str(username))
Пример #21
0
class SlackROS():
    # Must have __init__(self) function for a class, similar to a C++ class constructor.
    def __init__(self):
        # Get the ~private namespace parameters from command line or launch file.
        self.token = rospy.get_param('~token', 'xoxp-123456789')
        self.channel = rospy.get_param('~channel', 'G1234567Q')
        self.username = rospy.get_param('~username', 'ros-bot')
	
        # Create a publisher for our custom message.
        pub = rospy.Publisher('from_slack_to_ros', String, queue_size=10)
	rospy.Subscriber("from_ros_to_slack", String, self.callback)

	# Create the slack client
	self.sc = SlackClient(self.token)

	if self.sc.rtm_connect():

            # Main while loop.
            while not rospy.is_shutdown():
                for reply in self.sc.rtm_read():
                    if "type" in reply and "user" in reply:
                        #print reply
                        if reply["type"] == "message" and reply["channel"] == self.channel:
                            pub.publish(reply["text"])
                
	        # Sleep for a while before publishing new messages. Division is so rate != period.
                rospy.sleep(2.0)

    def callback(self, data):
	self.sc.api_call(
    	    "chat.postMessage", channel=self.channel, text=data.data,
    	    username=self.username, icon_emoji=':robot_face:'
	)
Пример #22
0
class Utils:
    def __init__(self):
        self.sc = SlackClient(token)

    def send(self, chan, message):
        """Print to chat function using the slackclient api"""
        self.sc.api_call("chat.postMessage", channel = chan, text = "`" + message + "`", icon_emoji=':robot_face:')

    def whisper(self, message):
        return message

    def is_empty_input(param, self):
        """Check parameters to see if it is empty"""
        param = request.args.get("text")
        if param is None:
            self.help()
            return True
        return False

    def is_user_online(self, username):
        """Grats the user_ID (U123456789) via username"""
        data = self.sc.api_call("users.list", presence='1')
        try:
            for key in data['members']:
                if key['name'] == username:
                    return key['presence']
        except:
            pass
        return None
Пример #23
0
 def post_message(self):
     sc = SlackClient(self.token)
     print sc.api_call("api.test")
     sc.api_call(
         "chat.postMessage", channel="#general", text="Hello from Python! :tada:",
         username=self.username, as_user="******", icon_emoji=':robot_face:'
     )
Пример #24
0
class SlackInterface(object):
    TOPIC_EXTRACT_EXPR = "^DC([0-9]+).*$"

    def __init__(self, config):
        self.sc = SlackClient(config["slack_token"])
        self.bot_token = config["slackbot_token"]
        self.channel_name = config["channel_name"]
        self.channel_id = config["channel_id"]

    def get_challenge_number_from_topic(self):
        info = json.loads(self.sc.api_call("channels.info", channel=self.channel_id))
        if "channel" in info and "topic" in info["channel"] and "value" in info["channel"]["topic"]:
            topic = info["channel"]["topic"]["value"]

            print "got", topic
            match = re.match(SlackInterface.TOPIC_EXTRACT_EXPR, topic)
            if match is None:
                return 0
            else:
                return int(match.group(1))
        else:
            return 0

    def post_to_slack(self, poster_name, challenge_num, challenge):
        print self.sc.api_call(
            "channels.setTopic", channel=self.channel_id, topic="DC%d: %s" % (challenge_num, challenge)
        )
        post_url = "https://rands-leadership.slack.com/services/hooks/slackbot?token=%s&channel=%%23%s" % (
            self.bot_token,
            self.channel_name,
        )
        post_data = " @%s says: Daily Challenge #%d: %s" % (poster_name, challenge_num, challenge)
        r = requests.post(post_url, data=post_data)
        print r.content
Пример #25
0
def main():
    sc = SlackClient(SLACK_TOKEN)
    rt = RecognitionTracker()
    if sc.rtm_connect():
        while True:
            messages = sc.rtm_read()
            for message in messages:
                message_to_write = None

                # It only watches the channels it's in, but to be extra
                # careful here.
                channel = message.get("channel")
                if not channel or channel not in CHANNEL_INFO.keys():
                    continue

                # The first time you get here after 10AM on a new day, print
                # out some random results.
                current_date = (datetime.datetime.now() -
                                datetime.timedelta(hours=17)).date()
                if current_date != rt.current_date:
                    # Write the daily message to every channel
                    for channel_key in CHANNEL_INFO.iterkeys():
                        possible_message_to_write = rt.get_daily(channel_key)
                        if possible_message_to_write:
                            sc.api_call(
                                "chat.postMessage",
                                channel=channel_key,
                                username=CHANNEL_INFO[channel_key]['name'],
                                icon_emoji=CHANNEL_INFO[channel_key]['emoji'],
                                attachments=possible_message_to_write
                            )

                    rt.current_date = current_date

                command_type = get_command_type(message)
                if command_type == "thanks":
                    message_to_write = rt.give_thanks(message['text'],
                                                      message['user'],
                                                      channel)

                elif command_type == "summary":
                    message_to_write = rt.get_summary(channel)

                elif command_type == "help":
                    message_to_write = rt.get_help(channel)

                elif command_type == "today":
                    message_to_write = rt.get_daily(channel,
                                                    override=True)

                if message_to_write:
                    sc.api_call("chat.postMessage", channel=channel,
                                username=CHANNEL_INFO[channel]['name'],
                                icon_emoji=CHANNEL_INFO[channel]['emoji'],
                                attachments=message_to_write)

                time.sleep(1)
    else:
        print "Oh noes, the sadness commences!"
Пример #26
0
 def success_message(self, num_articles):
     sc = SlackClient(self.bot_token)
     sc.api_call(
         "chat.postMessage", channel=self.channel_id,
         text="Hello <@{}|{}> just grabbed {} new articles for you :newspaper:!".format(self.reply_user_id, self.reply_user_name, num_articles),
         username=self.username, as_user="******", icon_emoji=':instapaper:'
     )
     return 200
Пример #27
0
def slack_notify_message(message):
    bot_token = SECRETS_DICT['CITIGROUP_SLACKBOT_TOKEN']
    sc = SlackClient(bot_token)

    general_channel_id = 'C0GEA5C1X'
    sc.api_call('chat.postMessage', channel=general_channel_id,
                text='@channel: {}'.format(message), link_names=1,
                as_user=True)
Пример #28
0
class SlackExfiltrator():
    def __init__(self, slackSlaveID, slackToken, encKey):
        self.slackSlaveID = slackSlaveID
        self.slackToken = slackToken
        self.encKey = encKey

        self.encDriver = AESCipher(key=self.encKey)
        self.slackObj = None

    def _connect2Slack(self):
        self.slackObj = SlackClient(self.slackToken)

        if self.slackObj.api_call("api.test")['ok'] == True:
            sys.stdout.write("[+]\tConnected to Slack. API is valid!\n")
            return True

        else:
            sys.stderr.write("Unable to connect to slack. Maybe token is wrong?\n")
            sys.stderr.write("%s\n" % self.slackObj.api_call("api.test")['error'])
            sys.exit(1)

    def Listen(self):
        SC.api_call("chat.postMessage", as_user=True, channel=self.slackSlaveID, text="Bot is now online and will accept your calls.")
        if SC.rtm_connect():
            while True:
                answer = SC.rtm_read()
                try:
                    answer = answer[0]
                except IndexError:
                    continue

                try:
                    user = answer['user']
                    mtype = answer['type']
                except KeyError:
                    continue

                if answer['type'] == 'message' and answer['user'] == self.slackSlaveID:
                    sys.stdout.write("[.]\tGot a message from SlackSlaveID!\n")
                    try:
                        data = base64.b64decode(answer['text'])
                    except:
                        sys.stderr.write("[-]\tMessage from SlaveID is not Base64!\n")
                        continue

                    try:
                        decData = self.encDriver.decrypt(data)
                    except:
                        sys.stderr.write("[!]\tYou are not using the same key.\n")
                        continue

                    fname = str(random.randint(1111,9999)) + ".raw"
                    f = open(fname, 'wb')
                    f.write(decData)
                    f.close()
                    sys.stdout.write("[+]\tFile '%s' has been saved.\n" % fname)

                time.sleep(GLOBS.TIMEOUT)
Пример #29
0
def notify(message):
    config = _configuration()
    if config.notification_channel is NOT_SET:
        raise missingConfigurationException('notification-channel')
    if config.access_token is NOT_SET:
        raise missingConfigurationException('access-token')
    client = SlackClient(config.access_token)
    message = '%s %s' % (message, _SLACK_MESSAGE_SUFFIX)
    client.api_call('chat.postMessage', channel='#%s' % config.notification_channel, text=message, as_user=True, parse='full')
Пример #30
0
def send_telegram_message(message, destination):
    from slackclient import SlackClient
    token = "xoxp-60436121012-65421128289-66951783558-32760d4109"
    sc = SlackClient(token)
    sc.api_call("chat.postMessage",
                channel=destination,
                text=message,
                username="******"
                )
Пример #31
0
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")
Пример #32
0
    # for cities in data:
    # logger.logit('city=%s',cities)
    # for key, value in cities.items():
    # countryset.add(cities['country'])
    # logger.debug('List of countries= %s',countryset)
    # todo update countries in data with full name instead of abbreviations

# ---- End of Open Weather Map initialization

# Constants
AT_BOT = "<@" + BOT_ID + ">"
EXAMPLE_COMMAND = ''
CHATROOM = <insert slack room ID>
ROBITSHOP =  <insert slack room ID>

logger.debug(slack_client.api_call("channels.list"))


# Functions to parse Slack output and handle commands  ------------------------
def handle_command(rb_command, rb_channel):
    """
        Receives commands directed at the bot and determines if they
        are valid commands. If so, then acts on the commands. If not,
        returns back what it needs for clarification.
    """
    response = ''
    rb_command = rb_command.lower()

    if rb_command.startswith(EXAMPLE_COMMAND):

        if 'pizza party' in rb_command:
Пример #33
0
secrets_file = 'slack_secret.json'
f = open(secrets_file, 'r')
content = f.read()
f.close()

auth_info = json.loads(content)
auth_token = auth_info["access_token"]
bot_user_id = auth_info["user_id"]

sc = SlackClient(auth_token)
sc.rtm_connect()

if sc.rtm_connect():
    while True:
        time.sleep(1)
        response = sc.rtm_read()
        for item in response:
            if item.get("type") != 'message':
                continue
            if item.get("user") == None:
                continue
            message_text = item.get('text')
            if not message_matches(bot_user_id, message_text):
                continue
            response = sc.api_call("users.info", user=item["user"])
            username = response['user'].get('name')
            entity = extract_entity(message_text)
            message = create_message(username, entity)
            sc.api_call("chat.postMessage",
                        channel="#assignment2_bots",
                        text=message)
Пример #34
0
        result[key] = None
        field_id, transform = v

        data = fields.get(field_id)
        result[key] = transform(data["value"] if data else None)

    return result


def is_ok(result):
    return bool(result.get("ok"))


if __name__ == "__main__":

    result = slack.api_call("users.list")
    if not is_ok(result):
        fatal("failed to get list of users")

    profiles = []
    users = [u for u in result["members"] if is_valid_user(u)]

    for user in users:
        user_id = user["id"]
        user_name = user["name"]

        result = slack.api_call("users.profile.get", user=user_id)
        if not is_ok(result):
            error(f"failed to get user {user_name} ({user_id})")
            continue
Пример #35
0
class SlackWrapper:
    DEFAULT_SUPPORTED_FILE_TYPES = ["jpg", "jpeg", "png"]

    def __init__(
        self,
        token=None,
        on_file_shared_fn=None,
        supported_file_types=DEFAULT_SUPPORTED_FILE_TYPES,
    ):
        """
        SlackWrapper handles communication with the Slack RTM and Web APIs

        Params:
        `slack_token` : String,
        `supported_file_types` a list of supported file types
        `on_file_shared_fn` : Fn(string, string) -> None - handle files
        """

        self.__token = token
        self.__client = SlackClient(token)
        self.__should_quit = False
        self.__edward_id = None
        self.__supported_file_types = supported_file_types
        self.__on_file_shared_fn = on_file_shared_fn

    def stop(self):
        self.__should_quit = True

    def start(self):
        """
        Connect to Slacks real time messaging client and kick of the main loop
        """

        # first things first; let's connect to Slack RTM
        if self.__client.rtm_connect(auto_reconnect=True, with_team_state=False):

            # once that succeeds, store our own user ID for filtering
            self.__edward_id = self.__client.api_call("auth.test")["user_id"]

            # kick off main loop; blocking
            self.run_main_loop()

    def run_main_loop(self):
        """
        The main loop is responsible for reading messages off of the queue
        and kicking off converting jobs should a message be applicable.
        """

        EdwardLogger.info("Ready for action!")

        # start looping as long as we're connected
        while self.__client.server.connected:
            # should we shutdown?
            if self.__should_quit:
                break

            batch = self.__client.rtm_read()
            job_params = self.extract_job_params(batch)

            if job_params is not None:
                # all is OK, spawn handler
                download_url, response_channel_id = job_params

                # perform the callback containing the job parameters
                EdwardLogger.info("File attached and valid")
                self.__on_file_shared_fn(download_url, response_channel_id)

            # no matter if we scheduled a job or not; wait a bit
            time.sleep(1)

    def extract_job_params(self, messages):
        """
        extract_job_params takes the original slack message and returns either
        `None` or a tuple containing the `download_url` and `return_channel_id`:

        * download_url is a string containing the download location
        * return_channel_id is the Slack channel id on which to reply to
        """

        # if there's no messages to be polled, we receive an empty list.
        # we should just skip and try again
        if len(messages) == 0:
            return None

        # the messages are returned in an array; grab the first one
        # and start validating the payload
        message = messages[0]

        # if message does not contain required fields, ignore it
        if not self.__is_message_valid(message):
            return None

        # if message author is edward itself, ignore to avoid endless looping
        if message["user"] == self.__edward_id:
            return None

        # if it isn't a file_shared message, just ignore and continue
        if not self.__is_file_attached(message):
            return None

        # if there is a file but it is not supported by Edward
        file = message["files"][0]
        pretty_type = file["pretty_type"].lower()
        if pretty_type not in self.__supported_file_types:
            EdwardLogger.info("Attached file not of valid type, skipping")
            return None

        # if we've reached this point, we encountered a valid message.
        # extract the important bits and return a tuple containing job params
        return (file["url_private_download"], message["channel"])

    def download_image(self, image_download_url):
        """
        download_file accepts a file_download_url, provides authorization
        and kicks off the request to Slack Web API
        """
        return requests.get(image_download_url, headers=self.__get_http_headers())

    def upload_image(self, channel_id, bytes):
        """
        upload_image uploads the sequence of bytes to the provided slack channel.
        It returns either None if all went well, or the error if something blew up
        """

        response = self.__client.api_call(
            "files.upload", channels=channel_id, file=bytes
        )

        if response["ok"]:
            return None
        else:
            return response["error"]

    def __get_http_headers(self):
        return {"Authorization": "Bearer {}".format(self.__token)}

    def __is_message_valid(self, message):
        return (
            "type" in message
            and message["type"] == "message"
            and "user" in message
        )

    def __is_file_attached(self, message):
        return (
            message["type"] == "message"
            and "files" in message
            and len(message["files"]) > 0
        )
Пример #36
0
        Executes bot command if the command is known
    """
    # Default response is help text for the user
    default_response = "Not sure what you mean. Try *{}*.".format(
        EXAMPLE_COMMAND)

    # Finds and executes the given command, filling in response
    response = None
    # This is where you start to implement more commands!
    if command.startswith(EXAMPLE_COMMAND):
        response = "Sure...write some more code then I can do that!"

    # Sends the response back to the channel
    slack_client.api_call("chat.postMessage",
                          channel=channel,
                          text=response or default_response)


if __name__ == "__main__":
    if slack_client.rtm_connect(with_team_state=False):
        print("Starter Bot connected and running!")
        # Read bot's user ID by calling Web API method 'auth.test'
        starterbot_id = slack_client.api_call("auth.test")["user_id"]
        while True:
            command, channel = parse_bot_commands(slack_client.rtm_read())
            if command:
                handle_command(command, channel)
            time.sleep(RTM_READ_DELAY)
    else:
        print("Connection failed. Exception traceback printed above.")
Пример #37
0
    def handle(self, *args, **options):
        try:
            bounty_client = BountyClient()
            sc = SlackClient(settings.SLACK_TOKEN)

            while True:
                # poll by the second
                if not settings.LOCAL:
                    time.sleep(1)

                response = sqs_client.receive_message(
                    QueueUrl=settings.QUEUE_URL,
                    AttributeNames=['MessageDeduplicationId'],
                    MessageAttributeNames=['All'],
                )

                messages = response.get('Messages')

                if not messages:
                    continue

                message = messages[0]
                receipt_handle = message['ReceiptHandle']
                message_attributes = message['MessageAttributes']

                event = message_attributes['Event']['StringValue']
                bounty_id = int(message_attributes['BountyId']['StringValue'])
                fulfillment_id = int(
                    message_attributes['FulfillmentId']['StringValue'])
                message_deduplication_id = message_attributes[
                    'MessageDeduplicationId']['StringValue']
                transaction_from = message_attributes['TransactionFrom'][
                    'StringValue']
                event_timestamp = message_attributes['TimeStamp'][
                    'StringValue']
                contract_method_inputs = json.loads(
                    message_attributes['ContractMethodInputs']['StringValue'])

                # If someone uploads a data hash that is faulty, then we want to blacklist all events around that
                # bounty id. We manage this manually
                if redis_client.get('blacklist:' + str(bounty_id)):
                    redis_client.set(message_deduplication_id, True)
                    sqs_client.delete_message(
                        QueueUrl=settings.QUEUE_URL,
                        ReceiptHandle=receipt_handle,
                    )
                    continue

                logger.info('attempting {}: for bounty id {}'.format(
                    event, str(bounty_id)))
                if event == 'BountyIssued':
                    bounty_client.issue_bounty(bounty_id,
                                               contract_method_inputs,
                                               event_timestamp)

                if event == 'BountyActivated':
                    bounty_client.activate_bounty(bounty_id,
                                                  contract_method_inputs)

                if event == 'BountyFulfilled':
                    bounty_client.fulfill_bounty(bounty_id, fulfillment_id,
                                                 contract_method_inputs,
                                                 event_timestamp,
                                                 transaction_from)

                if event == 'FulfillmentUpdated':
                    bounty_client.update_fulfillment(bounty_id, fulfillment_id,
                                                     contract_method_inputs)

                if event == 'FulfillmentAccepted':
                    bounty_client.accept_fulfillment(bounty_id, fulfillment_id)

                if event == 'BountyKilled':
                    bounty_client.kill_bounty(bounty_id)

                if event == 'ContributionAdded':
                    bounty_client.add_contribution(bounty_id,
                                                   contract_method_inputs)

                if event == 'DeadlineExtended':
                    bounty_client.extend_deadline(bounty_id,
                                                  contract_method_inputs)

                if event == 'BountyChanged':
                    bounty_client.change_bounty(bounty_id,
                                                contract_method_inputs)

                if event == 'IssuerTransferred':
                    bounty_client.transfer_issuer(bounty_id,
                                                  contract_method_inputs)

                if event == 'PayoutIncreased':
                    bounty_client.increase_payout(bounty_id,
                                                  contract_method_inputs)

                logger.info(event)

                # We should create a separate client to manage these
                # notifications to slack
                sc.api_call('chat.postMessage',
                            channel=settings.NOTIFICATIONS_SLACK_CHANNEL,
                            text='Event {} passed for bounty {}'.format(
                                event, str(bounty_id)))
                # This means the contract subscriber will never send this event
                # through to sqs again
                redis_client.set(message_deduplication_id, True)
                sqs_client.delete_message(
                    QueueUrl=settings.QUEUE_URL,
                    ReceiptHandle=receipt_handle,
                )
        except Exception as e:
            # goes to rollbar
            logger.exception(e)
            raise e
Пример #38
0
        )
        #leader_board sort by time and pick top10(sql)
        rows = cur.fetchall()
        cur.close()
        conn.close()
        q1 = rows
    except Exception, e:
        print(e)
    response = "Your result is " + str(res[0].split("\n")[0]) + "\n TOP10: \n"
    i = 1
    for elem in q1:
        response = response + str(i) + " " + elem[0].strftime(
            "%Y-%m-%d %H:%M:%S") + " " + str(elem[1]) + "\n"
        i = i + 1
    slack_client.api_call("chat.postMessage",
                          channel=channel,
                          text=response or default_response)
    pass


def parse_direct_mention(message_text):
    """
        Finds a direct mention (a mention that is at the beginning) in message text
        and returns the user ID which was mentioned. If there is no direct mention, returns None
    """
    #print("Received " + message_text)
    submission(message_text)
    matches = re.search(MENTION_REGEX, message_text)
    # the first group contains the username, the second group contains the remaining message
    return (matches.group(1), matches.group(2).strip()) if matches else (None,
                                                                         None)
Пример #39
0
def main():
    TOKEN = "TOKEN GOES HERE"
    GAME = "GAME.z5"
    CHANNEL = "#CHANNEL-NAME-HERE"
    CHANNEL_ID = "CHANNEL ID GOES HERE"
    USERNAME = "******"
    ICON_EMOJI = ":robot_face:"
    DFROTZ_PATH = "./dfrotz"

    sc = SlackClient(TOKEN)
    if sc.rtm_connect():
        sc.api_call(
            "chat.postMessage",
            channel=CHANNEL,
            text="Let's play Interactive Fiction!",
            username=USERNAME,
            icon_emoji=ICON_EMOJI
            )

    p = Popen([DFROTZ_PATH, GAME], stdout=PIPE, stdin=PIPE, bufsize=1)

    q = Queue()
    t = Thread(target=enqueue_output, args=(p.stdout, q))
    t.daemon = True # thread dies with the program
    t.start()

    game_start_message = read_from_game(q)

    print(sc.api_call("chat.postMessage", channel=CHANNEL, text=game_start_message,username=USERNAME, icon_emoji=ICON_EMOJI))

    while True:
        msg = sc.rtm_read()
        if len(msg) > 0 and isinstance(msg[0],dict):
            messageInfo = msg[0]
            if "subtype" in messageInfo:
                if messageInfo["subtype"] == "bot_message":
                    print("smells like a bot")
                    continue
            if "channel" in messageInfo:
                if messageInfo["channel"] != CHANNEL_ID:
                    continue
            try:
                if messageInfo["type"] == "message":
                    print(messageInfo["user"] + " said: " + messageInfo["text"])
                    if messageInfo["text"].lower().find("quit") != -1:
                        print("Passing")
                        continue
                    if messageInfo["text"].lower().find("@") != -1:
                        print("Passing")
                        continue
                    if messageInfo["text"].lower().find("www") != -1:
                        print("URL?")
                        continue
                    if messageInfo["text"].find("`") != -1:
                        print("comment")
                        continue
                    p.stdin.write((messageInfo["text"].split("\n")[0] +"\n").encode())
                    p.stdin.flush()
                    game_message = read_from_game(q)
                    sc.api_call("chat.postMessage", channel=CHANNEL, text=game_message,username=USERNAME, icon_emoji=ICON_EMOJI)
            except:
                print("Didn't like message")
                print(messageInfo)

        time.sleep(1)

    print("done")
Пример #40
0
    for user in user_request["members"]:
        user_list[user["name"]] = user["id"]
    if "request_metadata" in user_request and "next_cursor" in user_request[
            "request_metadata"]:
        return {
            **user_list,
            **create_user_list(user_request["request_metadata"]["next_cursor"])
        }
    else:
        return user_list


def parse_direct_mention(message_text):
    matches = re.search(MENTION_REGEX, message_text)
    # the first group contains the username, the second group contains the remaining message
    return (matches.group(1), matches.group(2).strip()) if matches else (None,
                                                                         None)


# Start the server on port 3000
if __name__ == "__main__":
    starterbot_id = slack_client.api_call("auth.test")["user_id"]
    channel_request = slack_client.api_call("channels.list",
                                            exclude_archived=1)
    for channel_item in channel_request["channels"]:
        slack_channels[channel_item["name"]] = channel_item["id"]
        if starterbot_id in channel_item["members"]:
            slack_joined_channels.append(channel_item["name"])
    slack_users = create_user_list()
    server_process.start()
Пример #41
0
# For this demo app, The task ID should be the last segment of the URL
attach_json = [{
    "fallback":
    "Upgrade your Slack client to use messages like these.",
    "color":
    "#CC0000",
    "actions": [{
        "type": "button",
        "text": ":red_circle:   Complete Task: " + task_id,
        "url": "https://roach.ngrok.io/workflow/" + task_id,
    }]
}]

# Post the message to Slack, storing the result as `res`
res = slack.api_call("chat.postMessage",
                     channel="#link-buttons",
                     text="Let's get started!",
                     attachments=attach_json)

# Store the message `ts` and `channel`, so we can request the message
# permalink later when the user clicks the link button
TASK_IDS[task_id] = {'channel': res['channel'], 'ts': res['message']['ts']}


# This is where our link button will link to, showing the user a
# task to complete before redirecting them to the `/complete` page
@app.route("/workflow/<task_id>", methods=['GET'])
def test(task_id):

    task_form = """<form method="POST" action="/complete/{}">
                    <input type="submit" value="Do The Thing" />
                </form>""".format(task_id)
def parse_direct_mention(message_text):
        """
            Finds a direct mention (a mention that is at the beginning) in message text
            and returns the user ID which was mentioned. If there is no direct mention, returns None
        """
        matches = re.search(MENTION_REGEX, message_text)
        # the first group contains the username, the second group contains the remaining message
        return (matches.group(1), matches.group(2).strip()) if matches else (None, None)

if __name__ == "__main__":
    startTime = time.time()
    if slack_client.rtm_connect(with_team_state=False):
        print("Instance manager connected and running!")
        # Read bot's user ID by calling Web API method `auth.test`
        arbiter_id = slack_client.api_call("auth.test")["user_id"]

	slack_client.api_call(
	    "chat.postMessage",	
	    channel=slackChannel,
	    text="Preparing to shutdown the following Google Cloud instances in 5 min (use `@The Arbiter save <list of instance numbers>` to save instances)." 
	)
	#Get all running nodes
	for node in get_all_instances():
	    if node.state == "running":
		runningNodes.append(node)
	#Build string list of nodes
	message=""
	for idx, node in enumerate(get_node_names(runningNodes)):
	    nodeDict[idx] = node
	    message+="%s %s\n" % (idx, node)
Пример #43
0
import os
from slackclient import SlackClient

sc = SlackClient('XXX')

sc.api_call("chat.postMessage",
            channel="#etl_Chris",
            as_user="******",
            text="ETL Success")
Пример #44
0
		word = line.strip()								# remove newline (\n) characters
		nouns.append(word)								# add to list of words!

message = None

#create a loop that runs/sends random messages to slack every 5 seconds
while True:

	# we pick a random word from our text file/noun list
	noun = random.choice(nouns)
	
	# format the message - only noun is random
	message = 'The ' + noun + ' ' + verb + ' through the ' + place + '.'
	print message

	# save your message for posterity
	with open('Messages.txt', 'a') as f:		# 'a' = append to the file, not overwrite everything :)
		f.write(message + '\n')				# be sure to add a line break so your tweets don't get mashed together

	print 'posting message...'

	# Connect to Slack with our Oauth settings and post messages to general channel
	slack_client.api_call(
		"chat.postMessage",
		channel="#general",
		text=message
	)
	# wait 5 seconds before running the next loop
	time.sleep(5)

Пример #45
0
class AutoMemer:
    bot_commands = {
        "add <sub>":
        "Adds <sub> to the list of subreddits scraped",
        "delete <sub>":
        "Deletes <sub> from the list of subreddits scraped",
        "details <meme_url>":
        ("Gives details for a meme if meme_url has been scraped", ),
        "help":
        "Prints a list of commands and short descriptions",
        "increase threshold <threshold> {optional_subreddit}":
        ("Sets threshold for {optional_subreddit} to the old threshold + "
         "or - the <threshold> value passed. Defaults to global"),
        "kill":
        "Kills automemer. Program is stopped, no scraping, no posting",
        "link <url>":
        "Prints the link associated with the url passed",
        "list settings":
        "Prints out all settings",
        "list subreddits":
        "Prints a list of subreddits currently being scraped",
        "list thresholds":
        "Prints the thresholds for subs",
        "num-memes {postable_only} {by_sub}":
        ("Prints the number of memes currently waiting to be posted. "
         "To only post memes with enough upvotes use `num-memes postable_only`, to get a "
         "breakdown by subreddit use `num-memes by_sub`"),
        "pop {num}":
        "pops {num} memes (or as many as there are) from the queue",
        "set scrape interval <int>":
        "sets the scrape interval to <int> minutes",
        "set threshold <threshold> {optional_subreddit}":
        ("Sets threshold upvotes a meme must meet to be scraped. If "
         "{optional_subreddit} is specified, sets <threshold> specifically "
         "for that sub, otherwise a global threshold is set (applied to "
         "subs without a specific threshold)"),
    }

    def __init__(self, bot_id, channel_id, bot_token, debug=False):
        self.bot_id = bot_id
        self.at_bot = "<@" + bot_id + ">"
        self.channel_id = channel_id
        self.client = SlackClient(bot_token)
        self.messages = queue.Queue()
        self.lock = Lock()
        self.debug = debug
        self.users_list = self.client.api_call("users.list")

        def dict_factory(cursor, row):
            d = {}
            for idx, col in enumerate(cursor.description):
                d[col[0]] = row[idx]
            return d

        self.conn = sqlite3.connect('memes/memes.sqlite3')
        self.conn.row_factory = dict_factory
        self.cursor = self.conn.cursor()

        self.log_file = './memes/log_file.txt'
        self.scraped_path = './memes/scraped.json'
        self.settings_path = './memes/settings.json'

        # creating directories and files
        os.makedirs('memes', exist_ok=True)
        if not os.path.isfile(self.scraped_path):
            file = open(self.scraped_path, 'x')
            file.write(json.dumps({}))
            file.close()
        if not os.path.isfile(self.settings_path):
            file = open(self.settings_path, 'x')
            file.write(json.dumps({}))
            file.close()

    @staticmethod
    def current_time_as_min():
        now = datetime.datetime.now()
        midnight = now.replace(hour=0, minute=0, second=0, microsecond=0)
        return (now - midnight).seconds // 60

    def run(self):
        READ_WEBSOCKET_DELAY = 1  # 1 second delay between reading from firehose
        while True:
            try:
                if self.client.rtm_connect():
                    print("AutoMemer connected and running!")
                    while True:
                        scraped_reddit = False
                        # have we added the contents of scraped.json to our queue
                        added_memes_to_queue = False
                        post_to_slack_interval = self.load_post_to_slack_interval(
                        )

                        slack_outputs = self.parse_slack_output(
                            self.client.rtm_read())
                        for output in slack_outputs:
                            self.handle_command(output)
                        time_as_minutes = self.current_time_as_min()
                        if time_as_minutes % 10 == 0 and not scraped_reddit:
                            Process(target=scrape_reddit.scrape,
                                    args=(self.cursor, self.conn,
                                          self.lock)).start()
                            scraped_reddit = True  # we just added the memes
                        elif time_as_minutes % 10 > 0:
                            # the minute passed, reset scraped_reddit
                            scraped_reddit = False

                        if (time_as_minutes % post_to_slack_interval == 0
                                and not added_memes_to_queue):
                            self.add_new_memes_to_queue()
                            added_memes_to_queue = True
                        elif (time_as_minutes % post_to_slack_interval > 0
                              and added_memes_to_queue):
                            added_memes_to_queue = False

                        self.pop_queue()
                        time.sleep(READ_WEBSOCKET_DELAY)
                else:
                    print("Connection failed. Invalid Slack token or bot ID?")
                    break
            except (websocket._exceptions.WebSocketConnectionClosedException,
                    BrokenPipeError) as e:
                pass

    def handle_command(self, output):
        """
        Receives commands directed at the bot and determines if they
        are valid commands. If so, then acts on the commands. If not,
        returns back what it needs for clarification.
        """
        command = output.get('@mention')
        if command is None:
            return
        response = '>{}\n'.format(command)
        command = command.lower()
        # specific command responses
        if command.startswith("add"):
            response += self._command_add_sub(output)
        elif command.startswith("delete") or command.startswith('remove'):
            response += self._command_delete_sub(output)
        elif command.startswith("details"):
            response += self._command_details(output)
        elif command == "help":
            response += self._command_help()
        elif command.startswith("increase threshold"):
            response += self._command_set_threshold(output, mode="+")
        elif command.startswith("list thresholds"):
            response += self._command_list_thresholds()
        elif command.startswith("link"):
            response += self._command_details(output, link_only=True)
        elif command == "list settings":
            response += self._command_list_settings()
        elif command == "list subreddits":
            response += self._command_list_subs()
        elif command.startswith("set threshold"):
            response += self._command_set_threshold(output)
        elif command.startswith("set post interval"):
            response += self._command_set_post_interval(output)
        elif command.startswith("pop"):
            reply = self._command_pop(output)
            if reply == "":
                # if we get an empty string back we've already popped the memes
                return
            else:
                response += reply
        elif command.startswith('num-memes'):
            response += self._command_num_memes(output)
        elif command == "kill":
            self.client.api_call("chat.postMessage",
                                 channel=MEME_SPAM_CHANNEL,
                                 text="have it your way",
                                 as_user=True)
            sys.exit(0)
        elif command.startswith("echo "):
            response = ''.join(output.get('@mention').split()[1:])
        else:  # a default response
            response = (">*{}*\nI don't know this command :dealwithitparrot:\n"
                        .format(command))

        # construct the response
        msg = {
            'channel': output['channel'],
            'text': response,
        }
        if 'thread_ts' in output:
            # the message we are responding too was threaded, so thread
            msg['thread_ts'] = output['thread_ts']
        self.messages.put(msg)

    def load_post_to_slack_interval(self):
        self.lock.acquire()
        try:
            with open(self.settings_path, mode='r', encoding='utf-8') as f:
                settings = f.read()
            settings = json.loads(settings)
            interval = settings['scrape_interval']
            return interval
        except Exception as e:
            utils.log_error(e)
            return 60
        finally:
            self.lock.release()

    def add_new_memes_to_queue(self, limit=None, user_prompt=False):
        _, postable = self.count_memes()
        # post 20% of the current number of memes in the queue, or 10
        limit = limit or max(10, int(0.2 * sum(postable.values())))
        self.lock.acquire()
        try:
            with open(self.scraped_path, mode='r', encoding='utf-8') as f:
                scraped = f.read()
            scraped_memes = json.loads(scraped)
            with open(self.settings_path, mode='r', encoding='utf-8') as f:
                settings = json.loads(f.read())
            thresholds = settings['threshold_upvotes']
            memes_by_sub = defaultdict(list)
            for post, data in sorted(list(scraped_memes.items()),
                                     key=lambda x: x[1]['created_utc']):
                memes_by_sub[data['sub']].append(data)

            list_of_subs = list(memes_by_sub.keys())
            sub_ind = 0
            while limit > 0 and any(memes_by_sub.values()):
                # while we haven't reached the limit and have more memes to post
                sub = list_of_subs[sub_ind]
                sub_threshold = thresholds.get(sub.lower(),
                                               thresholds['global'])
                while memes_by_sub[sub]:  # while there are memes from this sub
                    meme = memes_by_sub[sub].pop(0)
                    del scraped_memes[meme['url']]
                    ups = int(meme.get('highest_ups'))
                    if ups > sub_threshold:
                        utils.set_posted_to_slack(self.cursor, meme['id'],
                                                  self.conn, True)

                        limit -= 1
                        meme_text = (
                            "*{title}* _(from /r/{sub})_ `{ups:,d}`\n{url}".
                            format(title=meme.get('title').strip('*'),
                                   sub=sub.strip('_'),
                                   ups=ups,
                                   url=meme['url']))
                        self.messages.put({
                            'channel': MEME_SPAM_CHANNEL,
                            'text': meme_text,
                        })
                        break
                sub_ind = (sub_ind + 1) % len(list_of_subs)

            with open(self.scraped_path, mode='w', encoding='utf-8') as f:
                f.write(json.dumps(scraped_memes, indent=2))
            if limit > 0 and user_prompt:
                self.messages.put({
                    'channel': MEME_SPAM_CHANNEL,
                    'text': 'Sorry, we ran out of memes :('
                })
        except Exception as e:
            self.messages.put({
                'channel':
                MEME_SPAM_CHANNEL,
                'text': ("There was an error :sadparrot:\n"
                         ">`{}`".format(str(e))),
            })
            utils.log_error(e)
        finally:
            self.lock.release()

    def pop_queue(self):
        if not self.messages.empty():
            msg = self.messages.get()
            if not self.debug:
                self.client.api_call("chat.postMessage", **msg, as_user=True)
            else:
                msg['api'] = 'chat.postMessage'
                msg['as_user'] = True
                msg['time'] = datetime.datetime.now().isoformat(),
                with open(self.log_file, 'a') as f:
                    f.write(json.dumps(msg, indent=2) + ',\n')

    def parse_slack_output(self, slack_rtm_output):
        """
        the Slack Real Time Messaging API is an events firehose.
        this parsing function returns None unless a message is
        directed at the Bot, based on its ID.
        """
        if slack_rtm_output:
            for output in slack_rtm_output:
                output['time'] = datetime.datetime.now().isoformat()
                if 'user' in output:
                    output['username'] = self._get_name(output['user'])
                if 'text' in output and self.at_bot in output['text']:
                    # return text after the @ mention, whitespace removed
                    output['@mention'] = output['text'].split(
                        self.at_bot)[1].strip()

            self.log_slack_rtm(slack_rtm_output)
        return slack_rtm_output

    def log_slack_rtm(self, message):
        if not isinstance(message, str):
            message = json.dumps(message, indent=2)

        with open(self.log_file, 'a') as f:
            f.write(message + ',\n')

    def count_memes(self):
        self.lock.acquire()
        try:
            with open(self.scraped_path, mode='r', encoding='utf-8') as f:
                memes = f.read()
            with open(self.settings_path, mode='r', encoding='utf-8') as f:
                settings = f.read()
            memes = json.loads(memes)
            settings = json.loads(settings)
            thresholds = settings['threshold_upvotes']

            total, postable = Counter(), Counter()
            for post, data in memes.items():
                if not data.get('over_18'):
                    sub = data.get('sub', '').lower()
                    ups = data.get('highest_ups')
                    sub_threshold = thresholds.get(sub, thresholds['global'])

                    total[sub] += 1
                    if ups >= sub_threshold:
                        postable[sub] += 1
            return total, postable
        except OSError:
            return Counter(), Counter()
        finally:
            self.lock.release()

    def _command_help(self):
        text = ""
        for command, description in sorted(AutoMemer.bot_commands.items(),
                                           key=lambda x: x[0]):
            text += '`{}` - {}\n'.format(command, description)
        return text

    def _command_add_sub(self, output):
        response = ""
        command = output.get('@mention').lower().split()
        if len(command) != 2:
            response += "command must be in the form `add [name]`"
        else:
            command = command[1]
            settings = json.loads(open(self.settings_path).read())
            settings['subs'].append(command)
            self.lock.acquire()
            try:
                with open(self.settings_path, mode='w', encoding='utf-8') as f:
                    f.write(json.dumps(settings, indent=2))
            finally:
                self.lock.release()
            response += "_/r/{}_ has been added!".format(command)
        return response

    def _command_delete_sub(self, output):
        response = ""
        command = output.get('@mention').lower().split()
        if len(command) != 2:
            response += "command must be in the form `delete [name]`"
        else:
            sub = command[1]
            settings = json.loads(open(self.settings_path).read())
            previous_subs = settings['subs']
            previous_thresholds = settings['threshold_upvotes']
            if sub not in previous_subs:
                response += (
                    "_/r/{0}_ is not currently being followed, to add it use the"
                    " command `add {0}`".format(sub))
            else:
                previous_subs.remove(sub)
                settings['subs'] = previous_subs
                if sub in previous_thresholds:
                    del previous_thresholds[sub]
                self.lock.acquire()
                try:
                    with open(self.settings_path, mode='w',
                              encoding='utf-8') as f:
                        f.write(json.dumps(settings, indent=2))
                finally:
                    self.lock.release()
                response += "_/r/{}_ has been removed".format(sub)
        return response

    def _command_list_settings(self):
        response = ""
        self.lock.acquire()
        try:
            with open(self.settings_path, mode='r', encoding='utf-8') as f:
                settings = json.loads(f.read())
        finally:
            self.lock.release()
        for key, val in sorted(settings.items()):
            if key == "subs":
                val = sorted(val)
            response += "`{key}`: {val}\n".format(key=key,
                                                  val=json.dumps(val,
                                                                 indent=2))
        return response

    def _command_list_thresholds(self):
        response = ""
        self.lock.acquire()
        try:
            settings = json.loads(open(self.settings_path).read())
            thresholds = settings.get('threshold_upvotes')
            response += json.dumps(thresholds, indent=2)
        except OSError as e:
            response += ':sadparrot: error\n'
            response += str(e)
        finally:
            self.lock.release()
        return response

    def _command_list_subs(self):
        response = ""
        self.lock.acquire()
        try:
            settings = json.loads(open(self.settings_path).read())
            subs = sorted(settings.get('subs'))
            response += (
                'The following subreddits are currently being followed: {}'.
                format(str(subs)))
        except OSError as e:
            response += ':sadparrot: error\n'
            response += str(e)
        finally:
            self.lock.release()
        return response

    def _command_set_threshold(self, output, mode=None):
        command_str = 'set'
        if mode == '+':
            command_str = 'increase'
        response = ""
        command = output.get('@mention').lower().split()
        if len(command) not in [3, 4]:
            response += (
                "command must be in the form '{change} threshold {threshold} <optional-sub>'"
                .format(change=command_str))
        elif len(command) == 3 or command[-1].lower() == 'global':
            threshold = command[2]
            try:
                threshold = int(threshold)
            except ValueError:
                response += "{threshold} is not a valid integer".format(
                    threshold=threshold)
            else:
                old_t, new_t = self._command_set_threshold_to(threshold,
                                                              mode=mode)
                response += (
                    "The global threshold has been set to *{threshold}*! (previously {old})"
                    .format(threshold=new_t, old=old_t))
        else:
            sub = command[-1].lower()
            with open(self.settings_path, mode='r', encoding='utf-8') as f:
                settings = json.loads(f.read())
            if sub not in settings['subs']:
                response += "{} is not in the list of subreddits. run `list subreddits` to view a list".format(
                    sub)
            else:
                threshold = command[2]
                try:
                    threshold = int(threshold)
                except ValueError:
                    response += "{threshold} is not a valid integer".format(
                        threshold=threshold)
                else:
                    old_t, new_t = self._command_set_threshold_to(threshold,
                                                                  sub=sub,
                                                                  mode=mode)
                    response += (
                        "The threshold upvotes for _{sub}_ has been set to *{threshold}*! (previously {old})"
                        .format(sub=sub, threshold=new_t, old=old_t))
        return response

    def _command_set_threshold_to(self, upvote_value, sub='global', mode=None):
        self.lock.acquire()
        try:
            settings = json.loads(open(self.settings_path).read())
            old_t = settings['threshold_upvotes'].get(sub, 'global')
            new_t = upvote_value
            if mode == '+':
                if old_t == 'global':
                    new_t += settings['threshold_upvotes']['global']
                else:
                    new_t += old_t
            new_t = max(1, new_t)
            settings['threshold_upvotes'][sub] = new_t
            with open(self.settings_path, 'w') as f:
                f.write(json.dumps(settings, indent=2))
            return old_t, new_t
        finally:
            self.lock.release()

    def _command_details(self, output, link_only=False):
        response = ""
        command = output.get('@mention').split()
        if len(command) != 2:
            response += "command must be in the form `details <meme_url>`\n"
        else:
            meme_url = html.unescape(command[1][1:-1])
            meme_data = scrape_reddit.update_reddit_meme(
                self.cursor, self.conn, meme_url, self.lock)
            if meme_data is None:
                response += "I could find any data for this url: `{}`, sorry\n".format(
                    meme_url)
            else:
                if link_only:
                    for meme in meme_data:
                        response += meme.get('link') + '\n'
                else:
                    for meme in meme_data:
                        for key, val in sorted(meme.items()):
                            response += "`{key}`: {data}\n".format(key=key,
                                                                   data=val)
                        response += '\n'
        return response

    def _command_set_post_interval(self, command):
        response = ""
        interval = output.get('@mention').split()
        if len(interval) != 4:
            response += "command must be in the form `set post interval <integer>`"
        else:
            interval = interval[-1]
            try:
                interval = int(interval)
            except ValueError:
                response += "{} is not an integer :parrotcop:".format(interval)
            else:
                if interval >= 1440:
                    response += ("```\n"
                                 ">>> minutes_per_day()\n"
                                 "1440"
                                 "```\n"
                                 "Too many minutes!")
                elif interval <= 0:
                    response += "Please enter a number greater than 0"
                else:
                    self.lock.acquire()
                    try:
                        with open(self.settings_path,
                                  mode='r',
                                  encoding='utf-8') as s:
                            settings = s.read()
                        settings = json.loads(settings)
                        settings['scrape_interval'] = interval
                        global scrape_interval
                        scrape_interval = interval
                        with open(self.settings_path,
                                  mode='w',
                                  encoding='utf-8') as s:
                            s.write(json.dumps(settings, indent=2))
                        response += "scrape_interval has been set to *{}*!".format(
                            str(interval))
                    finally:
                        self.lock.release()
        return response

    def _command_pop(self, output):
        response = ""
        command = output.get('@mention').split()
        if len(command) == 2:
            try:
                limit = int(command[1])
            except ValueError:
                response += "{} isn't a number!".format(str(command[1]))
            else:
                if limit <= 0:
                    response += "You can't pop 0 or fewer memes.."
                else:
                    self.add_new_memes_to_queue(limit, user_prompt=True)
        else:
            self.add_new_memes_to_queue(user_prompt=True)

        return response

    def _command_num_memes(self, output):
        response = ""
        command = output.get('@mention').lower().split()
        by_sub = 'by_sub' in command
        postable_only = 'postable_only' in command
        total, postable = self.count_memes()
        subs_lower_to_title = {sub.lower(): sub for sub in total}

        if not by_sub:
            if not postable_only:
                text = "Total memes: {}\nPostable memes: {}".format(
                    str(sum(total.values())), str(sum(postable.values())))
                response += text
            else:
                response += "Postable memes: {}".format(
                    str(sum(postable.values())))
        else:
            if not postable_only:
                for sub in sorted(list(map(lambda x: x.lower(),
                                           total.keys()))):
                    response += "*{sub}*: {good}   ({tot})\n".format(
                        sub=subs_lower_to_title[sub],
                        good=postable[subs_lower_to_title[sub]],
                        tot=total[subs_lower_to_title[sub]])
                response += "\n*Combined*: {}    ({})".format(
                    str(sum(postable.values())), str(sum(total.values())))
            else:
                for sub in sorted(list(map(lambda x: x.lower(),
                                           total.keys()))):
                    response += "*{sub}*: {ups}\n".format(
                        sub=subs_lower_to_title[sub],
                        ups=postable[subs_lower_to_title[sub]])
                response += "\n*Combined*: {}".format(
                    str(sum(postable.values())))
        return response

    def _get_name(self, user_id):
        if self.users_list is None:
            return user_id
        for member in self.users_list['members']:
            if member['id'] == user_id:
                name = member.get('name')
                if name is not None:
                    return name
                profile = members.get('profile')
                if profile is not None:
                    name = profile.get('real_name')
                    if name is not None:
                        return name
                return user_id
        return user_id
Пример #46
0
class Bot(object):
    """ Instanciates a Bot object to handle Slack onboarding interactions."""
    def __init__(self):
        super(Bot, self).__init__()
        self.name = "pythonboardingbot"
        self.emoji = ":robot_face:"
        # When we instantiate a new bot object, we can access the app
        # credentials we set earlier in our local development environment.
        self.oauth = {"client_id": os.environ.get("CLIENT_ID"),
                      "client_secret": os.environ.get("CLIENT_SECRET"),
                      # Scopes provide and limit permissions to what our app
                      # can access. It's important to use the most restricted
                      # scope that your app will need.
                      "scope": "bot"}
        self.verification = os.environ.get("VERIFICATION_TOKEN")

        # NOTE: Python-slack requires a client connection to generate
        # an oauth token. We can connect to the client without authenticating
        # by passing an empty string as a token and then reinstantiating the
        # client with a valid OAuth token once we have one.
        self.client = SlackClient("")
        # We'll use this dictionary to store the state of each message object.
        # In a production envrionment you'll likely want to store this more
        # persistantly in  a database.
        self.messages = {}

    def auth(self, code):
        """
        Authenticate with OAuth and assign correct scopes.
        Save a dictionary of authed team information in memory on the bot
        object.

        Parameters
        ----------
        code : str
            temporary authorization code sent by Slack to be exchanged for an
            OAuth token

        """
        # After the user has authorized this app for use in their Slack team,
        # Slack returns a temporary authorization code that we'll exchange for
        # an OAuth token using the oauth.access endpoint
        auth_response = self.client.api_call(
                                "oauth.access",
                                client_id=self.oauth["client_id"],
                                client_secret=self.oauth["client_secret"],
                                code=code
                                )
        # To keep track of authorized teams and their associated OAuth tokens,
        # we will save the team ID and bot tokens to the global
        # authed_teams object
        team_id = auth_response["team_id"]
        authed_teams[team_id] = {"bot_token":
                                 auth_response["bot"]["bot_access_token"]}
        # Then we'll reconnect to the Slack Client with the correct team's
        # bot token
        self.client = SlackClient(authed_teams[team_id]["bot_token"])

    def open_dm(self, user_id):
        """
        Open a DM to send a welcome message when a 'team_join' event is
        recieved from Slack.

        Parameters
        ----------
        user_id : str
            id of the Slack user associated with the 'team_join' event

        Returns
        ----------
        dm_id : str
            id of the DM channel opened by this method
        """
        new_dm = self.client.api_call("im.open",
                                      user=user_id)
        dm_id = new_dm["channel"]["id"]
        return dm_id
		
	def post_msg(self, team_id, channel):
		new_msg = self.client.api_call("chat.postMessage", channel=channel, text="Hello from Python! :tada:")
		return new_msg
		
	#def test_msg(self, team_id, user_id):
		

    def onboarding_message(self, team_id, user_id):
        """
        Create and send an onboarding welcome message to new users. Save the
        time stamp of this message on the message object for updating in the
        future.

        Parameters
        ----------
        team_id : str
            id of the Slack team associated with the incoming event
        user_id : str
            id of the Slack user associated with the incoming event

        """
        # We've imported a Message class from `message.py` that we can use
        # to create message objects for each onboarding message we send to a
        # user. We can use these objects to keep track of the progress each
        # user on each team has made getting through our onboarding tutorial.

        # First, we'll check to see if there's already messages our bot knows
        # of for the team id we've got.
        if self.messages.get(team_id):
            # Then we'll update the message dictionary with a key for the
            # user id we've recieved and a value of a new message object
            self.messages[team_id].update({user_id: message.Message()})
        else:
            # If there aren't any message for that team, we'll add a dictionary
            # of messages for that team id on our Bot's messages attribute
            # and we'll add the first message object to the dictionary with
            # the user's id as a key for easy access later.
            self.messages[team_id] = {user_id: message.Message()}
        message_obj = self.messages[team_id][user_id]
        # Then we'll set that message object's channel attribute to the DM
        # of the user we'll communicate with
        message_obj.channel = self.open_dm(user_id)
        # We'll use the message object's method to create the attachments that
        # we'll want to add to our Slack message. This method will also save
        # the attachments on the message object which we're accessing in the
        # API call below through the message object's `attachments` attribute.
        message_obj.create_attachments()
        post_message = self.client.api_call("chat.postMessage",
                                            channel=message_obj.channel,
                                            username=self.name,
                                            icon_emoji=self.emoji,
                                            text=message_obj.text,
                                            attachments=message_obj.attachments
                                            )
        timestamp = post_message["ts"]
        # We'll save the timestamp of the message we've just posted on the
        # message object which we'll use to update the message after a user
        # has completed an onboarding task.
        message_obj.timestamp = timestamp

    def update_emoji(self, team_id, user_id):
        """
        Update onboarding welcome message after recieving a "reaction_added"
        event from Slack. Update timestamp for welcome message.

        Parameters
        ----------
        team_id : str
            id of the Slack team associated with the incoming event
        user_id : str
            id of the Slack user associated with the incoming event

        """
        # These updated attachments use markdown and emoji to mark the
        # onboarding task as complete
        completed_attachments = {"text": ":white_check_mark: "
                                         "~*Add an emoji reaction to this "
                                         "message*~ :thinking_face:",
                                 "color": "#439FE0"}
        # Grab the message object we want to update by team id and user id
        message_obj = self.messages[team_id].get(user_id)
        # Update the message's attachments by switching in incomplete
        # attachment with the completed one above.
        message_obj.emoji_attachment.update(completed_attachments)
        # Update the message in Slack
        post_message = self.client.api_call("chat.update",
                                            channel=message_obj.channel,
                                            ts=message_obj.timestamp,
                                            text=message_obj.text,
                                            attachments=message_obj.attachments
                                            )
        # Update the timestamp saved on the message object
        message_obj.timestamp = post_message["ts"]

    def update_pin(self, team_id, user_id):
        """
        Update onboarding welcome message after recieving a "pin_added"
        event from Slack. Update timestamp for welcome message.

        Parameters
        ----------
        team_id : str
            id of the Slack team associated with the incoming event
        user_id : str
            id of the Slack user associated with the incoming event

        """
        # These updated attachments use markdown and emoji to mark the
        # onboarding task as complete
        completed_attachments = {"text": ":white_check_mark: "
                                         "~*Pin this message*~ "
                                         ":round_pushpin:",
                                 "color": "#439FE0"}
        # Grab the message object we want to update by team id and user id
        message_obj = self.messages[team_id].get(user_id)
        # Update the message's attachments by switching in incomplete
        # attachment with the completed one above.
        message_obj.pin_attachment.update(completed_attachments)
        # Update the message in Slack
        post_message = self.client.api_call("chat.update",
                                            channel=message_obj.channel,
                                            ts=message_obj.timestamp,
                                            text=message_obj.text,
                                            attachments=message_obj.attachments
                                            )
        # Update the timestamp saved on the message object
        message_obj.timestamp = post_message["ts"]

    def update_share(self, team_id, user_id):
        """
        Update onboarding welcome message after recieving a "message" event
        with an "is_share" attachment from Slack. Update timestamp for
        welcome message.

        Parameters
        ----------
        team_id : str
            id of the Slack team associated with the incoming event
        user_id : str
            id of the Slack user associated with the incoming event

        """
        # These updated attachments use markdown and emoji to mark the
        # onboarding task as complete
        completed_attachments = {"text": ":white_check_mark: "
                                         "~*Share this Message*~ "
                                         ":mailbox_with_mail:",
                                 "color": "#439FE0"}
        # Grab the message object we want to update by team id and user id
        message_obj = self.messages[team_id].get(user_id)
        # Update the message's attachments by switching in incomplete
        # attachment with the completed one above.
        message_obj.share_attachment.update(completed_attachments)
        # Update the message in Slack
        post_message = self.client.api_call("chat.update",
                                            channel=message_obj.channel,
                                            ts=message_obj.timestamp,
                                            text=message_obj.text,
                                            attachments=message_obj.attachments
                                            )
        # Update the timestamp saved on the message object
        message_obj.timestamp = post_message["ts"]
Пример #47
0
def invite_to_slack(email):
    if settings.DEBUG:
        return {}
    sc = SlackClient(settings.SLACK_TOKEN)
    response = sc.api_call('users.admin.invite', email=email)
    return response
Пример #48
0
class HRSlackBot(object):

    def __init__(self, host, port, botname, **kwargs):
        self.sc = SlackClient(SLACKBOT_API_TOKEN)
        self.sc.rtm_connect()
        self.botname = botname
        self.host = host
        self.port = str(port)
        self.lang = 'en'
        self.icon_url = 'https://avatars.slack-edge.com/2016-05-30/46725216032_4983112db797f420c0b5_48.jpg'
        self.session_manager = SessionManager()
        self.weights = kwargs.get('weights')

    def send_message(self, channel, attachments):
        self.sc.api_call(
            "chat.postMessage", channel=channel,
            attachments=attachments, username=self.botname.title(),
            icon_url=self.icon_url)

    def error(self, channel, msg):
        attachments = [{
            'title': msg,
            'color': 'danger',
            'fallback': msg
        }]
        logger.error(msg)
        self.send_message(channel, attachments)

    def info(self, channel, msg):
        attachments = [{
            'title': msg,
            'color': '#36a64f',
            'fallback': msg
        }]
        logger.info(msg)
        self.send_message(channel, attachments)

    def run(self):
        while True:
            time.sleep(0.2)
            messages = self.sc.rtm_read()
            if not messages:
                continue
            for message in messages:
                if message['type'] != u'message':
                    continue
                if message.get('subtype') == u'bot_message':
                    continue
                usr_obj = self.sc.api_call(
                    'users.info', token=SLACKTEST_TOKEN, user=message['user'])
                if not usr_obj['ok']:
                    continue
                profile = usr_obj['user']['profile']
                name = profile.get('first_name') or profile.get('email')
                question = message.get('text')
                channel = message.get('channel')

                sid = self.session_manager.get_sid(name, self.botname)
                session = self.session_manager.get_session(sid)
                if session is not None:
                    assert hasattr(session.sdata, 'client')
                    client = session.sdata.client
                else:
                    client = Client(HR_CHATBOT_AUTHKEY, username=name,
                        botname=self.botname, host=self.host, port=self.port,
                        response_listener=self)
                    client.set_marker('Slack')
                    if self.weights:
                        client.set_weights(self.weights)
                    self.session_manager.add_session(name, self.botname, client.session)
                    session = self.session_manager.get_session(client.session)
                    if session is not None:
                        session.sdata.client = client
                        session.sdata.channel = channel
                        self.info(channel, "Session <{url}/v1.1/session_history?session={sid}&Auth={auth}|{sid}>".format(
                            url=CHATBOT_SERVER_URL, sid=session.sid, auth=HR_CHATBOT_AUTHKEY))
                    else:
                        self.error(channel, "Can't get session")
                        continue

                logger.info("Question {}".format(question))
                if question in [':+1:', ':slightly_smiling_face:', ':)', 'gd']:
                    ret, _ = client._rate('good')
                    if ret:
                        logger.info("Rate good")
                        answer = 'Thanks for rating'
                        color = 'good'
                    else:
                        logger.info("Rate failed")
                        answer = 'Rating failed'
                        color = 'danger'
                    attachments = [{
                        'title': answer,
                        'color': color,
                        'fallback': answer
                    }]
                    self.send_message(channel, attachments)
                    continue
                if question in [':-1:', ':disappointed:', ':(', 'bd']:
                    ret, _ = client._rate('bad')
                    if ret:
                        logger.info("Rate bad")
                        answer = 'Thanks for rating'
                        color = 'good'
                    else:
                        logger.info("Rate failed")
                        answer = 'Rating failed'
                        color = 'danger'
                    attachments = [{
                        'title': answer,
                        'color': color,
                        'fallback': answer
                    }]
                    self.send_message(channel, attachments)
                    continue

                try:
                    client.ask(question)
                except Exception as ex:
                    self.error(channel, ex.message)

                # session could change after ask
                if client.session != session.sid:
                    self.session_manager.remove_session(session.sid)
                    self.session_manager.add_session(
                        name, self.botname, client.session)
                    session = self.session_manager.get_session(client.session)
                    session.sdata.client = client
                    session.sdata.channel = channel
                    self.info(channel, "Session <{url}/v1.1/session_history?session={sid}&Auth={auth}|{sid}>".format(
                        url=CHATBOT_SERVER_URL, sid=session.sid, auth=HR_CHATBOT_AUTHKEY))
                    logger.info("Session is updated")

    def on_response(self, sid, response):
        answer = ''
        title = ''
        session = self.session_manager.get_session(sid)
        if session is None:
            time.sleep(0.5)
            session = self.session_manager.get_session(sid)
            if session is None:
                logger.error("No such session {}".format(session))
                return
        channel = session.sdata.channel
        if response is None or not response.get('text'):
            answer = u"Sorry, I can't answer it right now"
        else:
            answer = response.get('text')
            trace = response.get('trace', '')
            botid = response.get('botid', '')
            if trace:
                formated_trace = format_trace(trace)
                if formated_trace:
                    title = 'answered by {}\n\ntrace:\n{}'.format(botid, '\n'.join(formated_trace))
        attachments = [{
            'pretext': answer,
            'title': title,
            'color': '#3AA3E3',
            'fallback': answer,
        }]
        self.send_message(channel, attachments)
Пример #49
0
class Tangerine(object):
    jinja_environment = Environment

    def __init__(self, slack_token=None, settings=None):
        settings = settings or {}
        settings.setdefault('tangerine', {})
        settings['tangerine'].setdefault('sleep', 0.5)
        settings['tangerine'].setdefault('template_folder', 'templates')

        self.settings = Box(settings, frozen_box=True, default_box=True)
        self.listeners = []
        self.scheduled_tasks = []

        self.client = SlackClient(
            slack_token or self.settings.tangerine.auth_token,
        )
        self.sleep = self.settings.tangerine.sleep

    @classmethod
    def config_from_yaml(cls, path_to_yaml):
        with open(path_to_yaml, 'r') as ymlfile:
            settings = yaml.load(ymlfile)
            log.info('settings from %s loaded successfully', path_to_yaml)
            return cls(settings=settings)

    def _verify_rule(self, supplied_rule):
        """Rules must be callable with (user, message) in the signature.
        Strings are automatically converted to callables that match.
        """
        # If string, make a simple match callable
        if isinstance(supplied_rule, six.string_types):
            return lambda user, message: supplied_rule in message.lower()

        if not six.callable(supplied_rule):
            raise ValueError('Bot rules must be callable or strings')

        expected = ('user', 'message')
        signature = tuple(inspect.getargspec(supplied_rule).args)
        try:
            # Support class- and instance-methods where first arg is
            # something like `self` or `cls`.
            assert len(signature) in (2, 3)
            assert expected == signature or expected == signature[-2:]
        except AssertionError:
            msg = 'Rule signuture must have only 2 arguments: user, message'
            raise ValueError(msg)

        return supplied_rule

    def listen_for(self, rule, **options):
        """Decorator for adding a Rule. See guidelines for rules."""
        trigger = None
        if isinstance(rule, six.string_types):
            trigger = rule
        rule = self._verify_rule(rule)

        def decorator(f):
            self.add_listener(rule, f, trigger, f.__doc__, **options)
            return f

        return decorator

    def cron(self, schedule, **options):
        def decorator(f):
            self.add_cron(schedule, f, **options)
            return f
        return decorator

    def run(self):
        self.running = True
        if self.client.rtm_connect():
            try:
                self.event_loop()
            except (KeyboardInterrupt, SystemExit):
                log.info('attempting graceful shutdown...')
                self.running = False
        try:
            sys.exit(0)
        except SystemExit:
            os._exit(0)

    def event_loop(self):
        while self.running:
            time.sleep(self.sleep)
            self.process_stream()
            self.process_scheduled_tasks()

    def read_stream(self):
        data = self.client.rtm_read()
        if not data:
            return data
        return [Box(d) for d in data][0]

    def process_stream(self):
        data = self.read_stream()
        if not data or data.type != 'message' or 'user' not in data:
            return
        self.respond(data.user, data.text, data.channel)

    def process_scheduled_tasks(self):
        now = datetime.datetime.now()
        for idx, task in enumerate(self.scheduled_tasks):
            if now > task.next_run:
                t = self.scheduled_tasks.pop(idx)
                t.run()
                self.add_cron(t.schedule, t.fn, **t.options)

    def respond(self, user, message, channel):
        sendable = {
            'user': user,
            'message': message,
            'channel': channel,
        }
        if not message:
            return
        for rule, view_func, _, _, options in self.listeners:
            if rule(user, message):
                args = inspect.getargspec(view_func).args
                kwargs = {k: v for k, v in sendable.items() if k in args}
                response = view_func(**kwargs)
                if response:
                    if 'hide_typing' not in options:
                        # TODO(nficano): this should be configurable
                        time.sleep(.2)
                        self.client.server.send_to_websocket({
                            'type': 'typing',
                            'channel': channel,
                        })
                        time.sleep(.5)
                    if '{user.username}' in response:
                        response = response.replace(
                            '{user.username}',
                            self.get_user_name(user),
                        )
                    self.speak(response, channel)

    def add_listener(self, rule, view_func, trigger, docs, **options):
        """Adds a listener to the listeners container; verifies that
        `rule` and `view_func` are callable.
        """
        if not six.callable(rule):
            raise TypeError('rule should be callable')
        if not six.callable(view_func):
            raise TypeError('view_func should be callable')
        self.listeners.append(
            Listener(rule, view_func, trigger, docs, options),
        )

    def add_cron(self, schedule, f, **options):
        self.scheduled_tasks.append(Task(schedule, f, **options))

    def speak(self, message, channel, **kwargs):
        self.client.api_call(
            'chat.postMessage', as_user=True,
            channel=channel, text=message, **kwargs,
        )

    def get_user_info(self, user_id):
        return self.client.api_call('users.info', user=user_id)

    def get_user_name(self, user_id):
        user = self.get_user_info(user_id)
        return user.get('user', {}).get('name')

    def get_user_id_from_username(self, username):
        for m in self.client.api_call('users.list')['members']:
            if username.lower() == m.get('name', '').lower():
                return m['id']

    def get_channel_id_from_name(self, channel):
        channel = channel.lower().replace('#', '')
        types = ','.join(['public_channel', 'private_channel'])

        response = self.client.api_call(
            'conversations.list', types=types, limit=1000,
        )
        for c in response['channels']:
            if channel == c['name'].lower():
                return c['id']

        response = self.client.api_call('channels.list', limit=1000)
        for c in response['channels']:
            if channel == c['name'].lower():
                return c['id']

    def get_channel_name_from_channel_id(self, channel_id):
        types = ','.join(['public_channel', 'private_channel'])

        response = self.client.api_call(
            'conversations.list', types=types, limit=1000,
        )
        for c in response['channels']:
            if channel_id == c['id']:
                return c['name']

        response = self.client.api_call('channels.list', limit=1000)
        for c in response['channels']:
            if channel_id == c['id']:
                return c['name']

    def get_template_path(self):
        if os.path.isabs(self.settings.tangerine.template_folder):
            return self.settings.tangerine.template_folder
        else:
            return os.path.join(
                os.getcwd(),
                self.settings.tangerine.template_folder,
            )

    def get_jinja_environment(self):
        return self.jinja_environment(
            loader=FileSystemLoader(self.get_template_path()),
            autoescape=select_autoescape(['txt']),
        )

    def render_template(self, template_name, **context):
        env = self.get_jinja_environment()
        template = env.get_template(template_name)
        return template.render(**context)
Пример #50
0

#Get all messages in a channel
def allMessages(channel='C5GRK45A9'):
    msg_endpoint = 'https://slack.com/api/channels.history?token=%s&channel=%s&pretty=1' % (
        token, channel)
    all_messages = requests.get(msg_endpoint)
    text_all_message = all_messages.text
    with open("messages.json", "w") as message_file:
        message_file.write(text_all_message)
        message_file.close()
    return all_messages.json()


# Get all channels in the Team
channels = sc.api_call("channels.list")['channels']

print("There are {} channels in OPEN-Andela.".format(len(channels)))

# Save the channels information to a .txt file
with open("channels.txt", "w") as textfile:
    textfile.write("There are {} channels in OPEN-Andela.\n".format(
        len(channels)))
    textfile.write("")
    for channel in channels:
        textfile.write("----------------------------------------------- \n")
        textfile.write("Channel Name: {} \n".format(channel["name"]))
        textfile.write("Channel Name (Normalized): {} \n".format(
            channel["name_normalized"]))
        textfile.write("Number of Members: {} \n".format(
            channel['num_members']))
Пример #51
0
class Bot(object):
    """ Instanciates a Bot object to handle Slack onboarding interactions."""
    def __init__(self):
        super(Bot, self).__init__()
        self.name = "appone"
        self.emoji = ":robot_face:"
        # When we instantiate a new bot object, we can access the app
        # credentials we set earlier in our local development environment.
        # Scopes provide and limit permissions to what our app
        # can access. It's important to use the most restricted
        # scope that your app will need.
        self.oauth = {
            "client_id": os.environ.get("SLACK_CLIENT_ID"),
            "client_secret": os.environ.get("SLACK_CLIENT_SECRET"),
            "scope": os.environ.get("SLACK_BOT_SCOPE", "bot")
        }
        self.user_name_map = {}
        self.channel_data_map = {}

        # NOTE: Python-slack requires a client connection to generate
        # an oauth token. We can connect to the client without authenticating
        # by passing an empty string as a token and then reinstantiating the
        # client with a valid OAuth token once we have one.

        bot_oauth_default = "xoxb-445512136161-446113431922-MbaetJ62o8U1mr4u91BTauSq"
        bot_oauth_token = os.environ.get("SLACK_BOT_OAUTH_ACCESS",
                                         bot_oauth_default)
        #dprint ("calling SlackClient with token %s" % (bot_oauth_token,))
        self.client = SlackClient(bot_oauth_token)

        self.circleci_user_token = os.environ['CIRCLECI_HODOLIZER_TOKEN']
        self.circleci_project_token = os.environ['CIRCLECI_HB_LITTLEBOT_TOKEN']
        self.circleci_client = circleclient.CircleClient(
            self.circleci_user_token)
        self.circleci_repo_list = []

        # We'll use this dictionary to store the state of each message object.
        # In a production envrionment you'll likely want to store this more
        # persistantly in  a database.
        self.messages = {}

    def get_all_users_map(self):
        """
        Get all users for which we have visibility and create a dictionary map 
        by user 'id' to user information. 
        """

        slack_client = self.client

        api_call = slack_client.api_call("users.list")
        users = api_call.get('members')
        if api_call.get('ok'):
            for user in users:
                self.user_name_map[user['id']] = user
        return self.user_name_map

    def get_all_channel_data_map(self):
        """
        Get all channels for which we have visibility and create a dictionary map 
        by channels 'id' to channels information. 
        """

        slack_client = self.client

        api_call = slack_client.api_call("channels.list")
        channels = api_call.get('channels')
        if api_call.get('ok'):
            for chan in channels:
                self.channel_data_map[chan['id']] = chan
        return self.channel_data_map

    def get_channel_name_map(self):
        """
            Use the self.channel_name_map created by get_all_channel_map()
            to return a map with just id:name mappings
        """
        channel_id_name_map = {}
        all_channel_map = self.get_all_channel_data_map()
        if all_channel_map:
            for id, data in all_channel_map.items():
                channel_id_name_map[data["name"]] = id
            return channel_id_name_map
        else:
            dprint("No channel mappings could be found")

    def get_bot_userid(self, bot_name):
        # Courtesy of Twilio
        # https://www.twilio.com/blog/2016/05/add-phone-calling-slack-python.html

        # retrieve all users so we can find our bot
        users = self.get_all_users_map()
        if users:
            for uid, udata in users.items():
                u_name = udata["profile"].get("display_name")
                if not u_name:
                    u_name = udata["profile"].get("real_name")
                #dprint ("got user: %s \t id: %s" % (u_name, uid))

                #dprint ("%s" % str(udata))
            for user in users:
                if 'name' in users[user] and users[user].get(
                        'name') == bot_name:
                    bot_id = users[user]["profile"].get('bot_id', user)
                    #dprint("Bot ID for '" + users[user]['name'] + "' is " + bot_id)
                    #dprint("Bot Record: %s" % str(users[user]))
                    return bot_id
        dprint("could not find bot user with the name " + bot_name)
        return ''

    def auth(self, code):
        """
        Authenticate with OAuth and assign correct scopes.
        Save a dictionary of authed team information in memory on the bot
        object.

        Parameters
        ----------
        code : str
            temporary authorization code sent by Slack to be exchanged for an
            OAuth token

        """
        # After the user has authorized this app for use in their Slack team,
        # Slack returns a temporary authorization code that we'll exchange for
        # an OAuth token using the oauth.access endpoint
        dprint("\ncalling auth client.api_call\n")
        auth_response = self.client.api_call(
            "oauth.access",
            client_id=self.oauth["client_id"],
            client_secret=self.oauth["client_secret"],
            code=code)
        dprint("\ncclient.api_call returns %s\n" % (str(auth_response), ))
        # To keep track of authorized teams and their associated OAuth tokens,
        # we will save the team ID and bot tokens to the global
        # authed_teams object
        team_id = auth_response["team_id"]
        authed_teams[team_id] = {
            "bot_token": auth_response["bot"]["bot_access_token"]
        }
        # Then we'll reconnect to the Slack Client with the correct team's
        # bot token
        self.client = SlackClient(authed_teams[team_id]["bot_token"])

    def open_dm(self, user_id):
        """
        Open a DM to send a welcome message when a 'team_join' event is
        recieved from Slack.

        Parameters
        ----------
        user_id : str
            id of the Slack user associated with the 'team_join' event

        Returns
        ----------
        dm_id : str
            id of the DM channel opened by this method
        """
        new_dm = self.client.api_call("im.open", user=user_id)
        dprint("\nOpen DM to user %s channel %s\n" %
               (user_id, str(new_dm["channel"])))
        #dprint ("\nnew_dm: %s\n" % str(new_dm))
        dm_id = new_dm["channel"]["id"]
        return dm_id

    def get_message_object(self, team_id, user_id, message_type=None):

        # We've imported a Message class from `message.py` that we can use
        # to create message objects for each onboarding message we send to a
        # user. We can use these objects to keep track of the progress each
        # user on each team has made getting through our onboarding tutorial.

        # First, we'll check to see if there's already messages our bot knows
        # of for the team id we've got.
        if self.messages.get(team_id):
            # Then we'll update the message dictionary with a key for the
            # user id we've recieved and a value of a new message object
            self.messages[team_id].update(
                {user_id: message.Message(message_type=message_type)})
        else:
            # If there aren't any message for that team, we'll add a dictionary
            # of messages for that team id on our Bot's messages attribute
            # and we'll add the first message object to the dictionary with
            # the user's id as a key for easy access later.
            self.messages[team_id] = {
                user_id: message.Message(message_type=message_type)
            }
        message_obj = self.messages[team_id][user_id]
        # Then we'll set that message object's channel attribute to the DM
        # of the user we'll communicate with
        message_obj.channel = self.open_dm(user_id)
        return message_obj

    def help_message(self, team_id, user_id, message_text):
        """
        Create and send an onboarding welcome message to new users. Save the
        time stamp of this message on the message object for updating in the
        future.

        Parameters
        ----------
        team_id : str
            id of the Slack team associated with the incoming event
        user_id : str
            id of the Slack user associated with the incoming event

        """
        message_type = "helpmsg"
        message_obj = self.get_message_object(team_id,
                                              user_id,
                                              message_type=message_type)
        message_obj.text = message_text
        post_message = self.client.api_call(
            "chat.postMessage",
            channel=message_obj.channel,
            username=self.name,
            icon_emoji=self.emoji,
            text=message_obj.text,
        )
        timestamp = post_message["ts"]
        # We'll save the timestamp of the message we've just posted on the
        # message object which we'll use to update the message after a user
        # has completed an onboarding task.
        message_obj.timestamp = timestamp

    def git_usage_message(self):

        return ("""I'm sorry. I don't understand your git command.
I understand git [%s] if you would like to try one of those.
Commit also requires a -m commit_message""" % "|".join(GIT_SUPPORTED))

    def git_handler(self, team_id, user_id, incoming_text):
        """
        Get the git status of this project. 

        Parameters
        ----------
        team_id : str
            id of the Slack team associated with the incoming event
        user_id : str
            id of the Slack user associated with the incoming event
        incoming_text: str
            The git request string

        """

        message_type = "git_handler"
        message_obj = self.get_message_object(team_id, user_id, message_type)

        # Find the action immediately following the git command.
        # git status, git add, git commit are curently supported.
        p2 = re.compile(r"(?<=\bgit\s)(\w+)")
        match_obj = p2.search(incoming_text)
        if match_obj:
            git_action = match_obj.group()
        bad_command = False
        if git_action and git_action in GIT_SUPPORTED:
            arg_string = ''
            print("git action is %s" % (git_action, ))
            if git_action == 'commit':
                # We need a commit message flagged with -m
                flag_pos = incoming_text.find("-m")
                if flag_pos >= 0:
                    arg_string = "-m '%s'" % incoming_text[flag_pos +
                                                           len("-m"):]
                else:
                    # Can't do a commit without a commit message
                    bad_command = True
            elif git_action == 'add':
                # We only commit the whole directory
                arg_string = " ."
            elif git_action == 'push' or git_action == 'status':
                # No args for these
                arg_string = ""
            else:
                bad_command = True
            if not bad_command:
                p = subprocess.Popen('git %s %s' % (git_action, arg_string),
                                     shell=True,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.STDOUT)
                for line in p.stdout.readlines():
                    message_obj.text += "%s" % line
                retval = p.wait()
            else:  # git_action undefined.
                message_obj.text = self.git_usage_message()
                retval = 1
        else:
            retval = 1

        post_message = self.client.api_call(
            "chat.postMessage",
            channel=message_obj.channel,
            username=self.name,
            icon_emoji=self.emoji,
            text=message_obj.text,
        )
        if "ts" in post_message:
            timestamp = post_message["ts"]
            message_obj.timestamp = timestamp
        else:
            dprint("post_message: %s" % str(post_message))
        return retval

    def docker_handler(self, team_id, user_id, incoming_text):
        """
        Get the docker command and handle it. 

        Parameters
        ----------
        team_id : str
            id of the Slack team associated with the incoming event
        user_id : str
            id of the Slack user associated with the incoming event
        incoming_text: str
            The docker request string

        """

        message_type = "docker_handler"
        message_obj = self.get_message_object(team_id, user_id, message_type)

        # Find the action immediately following the docker command.
        # docker container ls, docker image ls are curently supported.
        docker_action = docker_parser.parse_command(incoming_text)
        dprint("Got docker_action: %s from incoming text: %s" %
               (docker_action, incoming_text))
        if docker_action[:len('docker')] == 'docker':
            dprint("running docker action: %s" % (docker_action))
            p = subprocess.Popen('%s' % docker_action,
                                 shell=True,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.STDOUT)
            for line in p.stdout.readlines():
                message_obj.text += "%s" % line
            retval = p.wait()
        else:
            message_obj.text = docker_action  # The usage message
            retval = 0

        post_message = self.client.api_call(
            "chat.postMessage",
            channel=message_obj.channel,
            username=self.name,
            icon_emoji=self.emoji,
            text=message_obj.text,
        )
        timestamp = post_message["ts"]
        return retval

    def get_circleci_repos(self):
        """
        Get the circleci repositories that the bot user is following
        returns a list of repo names
        """
        project_info_list = self.circleci_client.projects.list_projects()
        for project_dict in project_info_list:
            self.circleci_repo_list.append(project_dict["reponame"])

    def circleci_build_info(self, raw_results):
        """
        Returns selected circleci information about the last build.

        Input is raw_results from a call to circleci build.recent
        """
        if not isinstance(raw_results, dict):
            dprint("build info: Not a dict: %s" % (str(raw_results), ))
            return None
        else:
            rr = raw_results

            build_version = rr.get("platform", "Not found")
            build_url = rr.get("build_url", "Not found")
            commit_date = rr.get("committer_date", "Not found")
            author_name = rr.get("author_name", "Not found")
            build_num = rr.get("build_num", "Not found")
            outcome = rr.get("outcome", "Not found")

            # There may be several commits in this build
            committer_names = []
            commit_urls = []
            commit_subjects = []
            commit_dates = []

            for commit_detail in rr.get("all_commit_detail", []):
                committer_names.append(rr.get("committer_name", "Not found"))
                commit_urls.append(rr.get("commit_url", "Not found"))
                commit_subjects.append(rr.get("subject", "Not found"))
                commit_dates.append(rr.get("committer_date", "Not found"))

            # Should html'ify this for return
            results_string = """
Build Version: %(build_version)s\n
Build URL: %(build_url)s\n
Commit Date: %(commit_date)s\n
Author Name: %(author_name)s\n
Build Number: %(build_num)s\n 
Outcome: %(outcome)s""" % locals()

            for commit_subject, commiter_name, commit_url, commiter_date in list(
                    zip(commit_subjects, committer_names, commit_urls,
                        commit_dates)):
                results_string = results_string + """
Commit Subject: %s\n
Committer Name: %s\n
Commit Date: %s\n
Commit URL: %s\n """ % (commit_subject, commier_name, commiter_date,
                        commit_url)

            return results_string

    def circleci_handler(self, team_id, user_id, incoming_text):

        #my_repo_name = "HB_Littlebot"
        self.get_circleci_repos()
        repo_name = ''
        outgoing_text = "Sorry, I could not determine which repo you wanted.\n" \
                        "I know about these: %s" % (str(", ".join(self.circleci_repo_list),))
        message_type = "helpmsg"

        if self.circleci_repo_list:

            # Retrieve User data
            user_info = self.circleci_client.user.info()
            dprint("\nUSER info: %s\n" % (str(user_info), ))
            user_name = user_info['login']

            incoming_text = incoming_text.lower()

            for repo in self.circleci_repo_list:
                if incoming_text.find(repo.lower()) >= 0:
                    repo_name = repo
            if repo_name:
                if incoming_text.find("last build") >= 0:
                    last_build = self.circleci_client.build.recent(
                        user_name, repo_name, branch='master')
                    if last_build:
                        outgoing_text = self.circleci_build_info(last_build[0])
                        print("build_info: %s" % (str(last_build), ))
                        message_type = "circleci_last_build"
                    else:
                        message_type = "circleci_handler"
                        outgoing_text = "Sorry, I could not get that information.\n" \
                                        "I know about these repos: %s" % (str(", ".join(self.circleci_repo_list),))
                        message_type = "helpmsg"

        dprint("circleci_handler returning %s" % outgoing_text)
        message_obj = self.get_message_object(team_id,
                                              user_id,
                                              message_type=message_type)
        message_obj.text = outgoing_text

        post_message = self.client.api_call(
            "chat.postMessage",
            channel=message_obj.channel,
            username=self.name,
            icon_emoji=self.emoji,
            text=message_obj.text,
        )
        timestamp = post_message["ts"]
        # We'll save the timestamp of the message we've just posted on the
        # message object which we'll use to update the message after a user
        # has completed an onboarding task.
        message_obj.timestamp = timestamp
        """
        # Retrieve information about projects
        project_info_list = self.circleci_client.projects.list_projects()
        #dprint ("\nPROJECT info: %s\n" % (str(project_info),))
        for project_dict in project_info_list:
            my_repo_name = "HB_Littlebot"
            if project_dict["reponame"] == my_repo_name:
                dprint ("\nPROJECT info: %s\n" % (str(project_dict),))
            repo_name = project_dict["reponame"]
        dprint ("searching for %s" % repo_name)

        # Retrieve last 10 builds of branch master
        recent_builds = self.circleci_client.build.recent(user_name, repo_name, branch='master')
        for key, val in recent_builds[0].items():
            dprint ("key:%s\n\t%s" % (key,val))
        """

    def echo_message(self, team_id, user_id, incoming_text):
        """
        Create and send an onboarding welcome message to new users. Save the
        time stamp of this message on the message object for updating in the
        future.

        Parameters
        ----------
        team_id : str
            id of the Slack team associated with the incoming event
        user_id : str
            id of the Slack user associated with the incoming event

        """

        message_type = "echo_message"
        message_obj = self.get_message_object(team_id, user_id, message_type)
        # We'll use the message object's method to create the attachments that
        # we'll want to add to our Slack message. This method will also save
        # the attachments on the message object which we're accessing in the
        # API call below through the message object's `attachments` attribute.
        #message_obj.create_attachments()

        user_name = self.user_name_map[user_id]['profile']['display_name']

        dprint("IN Echo handler with message: %s" % (incoming_text, ))
        outgoing_text = "Hi %s. You said %s." % (user_name, incoming_text)
        if incoming_text.lower().find("hunka hunka") >= 0:
            outgoing_text += " Yes, I have a burning love for bots too."
        dprint("Looking in %s for id %s" %
               (self.user_name_map[user_id]['profile'], user_id))
        message_obj.text = outgoing_text
        post_message = self.client.api_call(
            "chat.postMessage",
            channel=message_obj.channel,
            username=self.name,
            icon_emoji=self.emoji,
            text=message_obj.text,
        )
        timestamp = post_message["ts"]
        # We'll save the timestamp of the message we've just posted on the
        # message object which we'll use to update the message after a user
        # has completed an onboarding task.
        message_obj.timestamp = timestamp

    def update_pin(self, team_id, user_id):
        """
        Update onboarding welcome message after recieving a "pin_added"
        event from Slack. Update timestamp for welcome message.

        Parameters
        ----------
        team_id : str
            id of the Slack team associated with the incoming event
        user_id : str
            id of the Slack user associated with the incoming event

        """
        # These updated attachments use markdown and emoji to mark the
        # onboarding task as complete
        completed_attachments = {
            "text": ":white_check_mark: "
            "~*Pin this message*~ "
            ":round_pushpin:",
            "color": "#439FE0"
        }
        # Grab the message object we want to update by team id and user id
        #message_obj = self.messages[team_id].get(user_id)
        # Grab the message object we want to update by team id and user id
        if team_id in self.messages and user_id in self.messages[team_id]:
            message_obj = self.messages[team_id].get(user_id)
        else:
            message_type = "update_pin"
            message_obj = self.get_message_object(team_id, user_id,
                                                  message_type)
        # Update the message's attachments by switching in incomplete
        # attachment with the completed one above.
        message_obj.pin_attachment.update(completed_attachments)
        # Update the message in Slack
        post_message = self.client.api_call(
            "chat.update",
            channel=message_obj.channel,
            ts=message_obj.timestamp,
            text=message_obj.text,
            attachments=message_obj.attachments)
        # Update the timestamp saved on the message object
        message_obj.timestamp = post_message["ts"]

    def update_share(self, team_id, user_id):
        """
        Update onboarding welcome message after recieving a "message" event
        with an "is_share" attachment from Slack. Update timestamp for
        welcome message.

        Parameters
        ----------
        team_id : str
            id of the Slack team associated with the incoming event
        user_id : str
            id of the Slack user associated with the incoming event

        """
        # These updated attachments use markdown and emoji to mark the
        # onboarding task as complete
        completed_attachments = {
            "text": ":white_check_mark: "
            "~*Share this Message*~ "
            ":mailbox_with_mail:",
            "color": "#439FE0"
        }
        # Grab the message object we want to update by team id and user id
        #message_obj = self.messages[team_id].get(user_id)
        # Grab the message object we want to update by team id and user id
        if team_id in self.messages and user_id in self.messages[team_id]:
            message_obj = self.messages[team_id].get(user_id)
        else:
            message_type = "update_share"
            message_obj = self.get_message_object(team_id, user_id,
                                                  message_type)
        # Update the message's attachments by switching in incomplete
        # attachment with the completed one above.
        message_obj.share_attachment.update(completed_attachments)
        # Update the message in Slack
        post_message = self.client.api_call(
            "chat.update",
            channel=message_obj.channel,
            ts=message_obj.timestamp,
            text=message_obj.text,
            attachments=message_obj.attachments)
        # Update the timestamp saved on the message object
        message_obj.timestamp = post_message["ts"]

    def send_message(self, team_id, user_id, message_text):
        """
        Send a message on the part of the app for something that doesn't have
        explicit handling.

        Parameters
        ----------
        team_id : str
            id of the Slack team associated with the incoming event
        user_id : str
            id of the Slack user associated with the incoming event
        message : A text message to send to the caller. 
        """

        # Grab the message object we want to update by team id and user id
        #message_obj = self.messages[team_id].get(user_id)
        # Grab the message object we want to update by team id and user id
        if team_id in self.messages and user_id in self.messages[team_id]:
            message_obj = self.messages[team_id].get(user_id)
        else:
            message_type = "send_message"
            message_obj = self.get_message_object(team_id, user_id,
                                                  message_type)
        # Update the message in Slack
        message_obj.text = message_text
        post_message = self.client.api_call(
            "chat.update",
            channel=message_obj.channel,
            ts=message_obj.timestamp,
            text=message_obj.text,
        )
        # Update the timestamp saved on the message object
        message_obj.timestamp = post_message["ts"]
Пример #52
0
import os
from slackclient import SlackClient

# globals for use throughout script
BOT_NAME = 'vroomba'
# this should be pulled from an environment variable, check readme for deets
slack_client = SlackClient(os.environ.get('SLACK_BOT_TOKEN'))

if __name__ == "__main__":
    api_call = slack_client.api_call("users.list")
    if api_call.get('ok'):
        # retrieve all users so we can find the bot
        users = api_call.get('members')
        for user in users:
            if user.get('name') == BOT_NAME:
                print("Bot ID for " + user['name'] + " is " + user.get('id'))
            else:
                print("not " + BOT_NAME + ", hiding ID...")
Пример #53
0
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
Пример #54
0
                response = random_response()
                url = get_youtube_url(split_command[1].strip())
                response = "{0}\n\n{1}".format(response, url)
                break
    else:
        response = "You are missing the all important punctuation fool."

    logging.info("{0}: {1}".format(command, response))

    # Sends the response back to the channel
    CLIENT.api_call("chat.postMessage",
                    channel=channel,
                    text=response,
                    as_user=True)


# end def handle_command

if __name__ == "__main__":
    if CLIENT.rtm_connect(with_team_state=False):
        print("Starter Bot connected and running!")
        # Read bot's user ID by calling Web API method `auth.test`
        starterbot_id = CLIENT.api_call("auth.test")["user_id"]
        while True:
            command, channel = parse_bot_commands(CLIENT.rtm_read())
            if command:
                handle_command(command, channel)
            time.sleep(RTM_READ_DELAY)
    else:
        print("Connection failed. Exception traceback printed above.")
Пример #55
0
class Bot:
    def __init__(self, token, name="beaker", verbose=False):
        self.token = token
        self.name = name
        self.plugins = []
        self.module_objects = []
        self.cron_plugins = []
        self.tag = "@"
        self.user_id = None
        self.verbose = verbose
        self.admins = defaultdict(dict)
        self.scheduler = BackgroundScheduler()
        try:
            self.sc = SlackClient(self.token)
        except Exception as e:
            print(e)
            sys.exit()
        self.get_plugins()
        self.setup_cron_jobs()
        self.read_admins()
        atexit.register(self.save_admins)

    def read_admins(self):
        try:
            with open("admins.json", "r") as fp:
                self.admins = json.load(fp)
        except (JSONDecodeError, FileNotFoundError):
            pass

    def get_plugins(self, reload_modules=False):
        modules = [
            file for file in os.listdir("plugins") if file.endswith(".py")
            and file != "base.py" and not file.startswith("__")
        ]
        if not reload_modules:
            for module in modules:
                self.module_objects.append(
                    import_module("plugins." + module.split(".")[0]))
        else:
            reload(plugins.base)
            new_modules = []
            for module in self.module_objects:
                new_module = reload(module)
                new_modules.append(new_module)
            self.module_objects.clear()
            self.module_objects = new_modules
            self.plugins.clear()
            invalidate_caches()
        if self.verbose:
            print(plugins.base.Plugin.__subclasses__())
        for subclass in plugins.base.Plugin.__subclasses__():
            _klass = subclass()
            self.plugins.append(_klass)
            if hasattr(_klass, "CRON"):
                self.cron_plugins.append(_klass)

        if self.verbose:
            print("module objects: {}".format(self.module_objects))
            print("plugins: {}".format(self.plugins))
            print("Cron plugins: {}".format(self.cron_plugins))

    def setup_cron_jobs(self):
        self.scheduler.start()
        for plugin in self.cron_plugins:
            self.scheduler.add_job(plugin.cron,
                                   CronTrigger.from_crontab(plugin.CRON),
                                   jitter=60 * 10)

    def help(self, params):
        # No params, general beaker help
        if not params:
            return {
                "text":
                "Beaker bot help. You're on your own for now, Ain't nobody got time for writing help"
            }
        for module in self.plugins:
            if params in module.commands:
                return module.help()
        # Module not found
        else:
            return {"text": "could not find module {}".format(params)}

    def call_plugin(self, command, params=""):
        for plugin in self.plugins:
            if command in plugin.commands:
                data = plugin.message_recieved(plugin, params)
                return data
        else:
            return {
                "text":
                "Could not find a plugin for command {}".format(command)
            }

    def show_commands(self):
        commands = []
        for module in self.plugins:
            commands.extend([c for c in module.commands])
        # TODO: These internal commands should be defined on the class object
        commands.extend(["help", "say", "whatdayisit", "refresh"])
        help_message = "Available commands: {}".format(", ".join(sorted(commands))) \
            if commands else "No commands available"
        return {"text": help_message}

    def handle_message(self, message):
        # Ignore messages from the bot itself
        if message.get("user", "") == self.user_id:
            return
        if not message.get("text"):
            return
        if self.verbose:
            print(message)

        # The first character for the first word should be our call tag. If not us, return
        if message["text"][0] != self.tag:
            return
        # Split message into individual words
        split = message["text"].split(" ")
        # The command is the word that follows the tag
        command = split[0][1:]
        # The params to the command are any words that follow the command
        params = " ".join(split[1:])
        data = {}
        # First look for the command in our internal handlers
        if command == "help":
            data = self.help(params)
        elif command == "whatdayisit":
            data["text"] = datetime.datetime.now().strftime('%A')
        elif command == "say":
            data["text"] = " ".join(split[1:])
        elif command == "summon":
            # TODO: find a neater way to allow a method to delete a message so we can put this somewhere else
            self.sc.api_call("chat.delete",
                             channel=message["channel"],
                             ts=message["ts"])
            data["text"] = "@" + " @".join(split[1:])
            data["username"] = "******"
            data[
                "icon_url"] = "http://seriousmovielover.com/wordpress/wp-content/uploads/2009/10/python2.jpg"
            data["as_user"] = False
        elif command == "commands":
            data = self.show_commands()
        elif command == "refresh":
            self.get_plugins(True)
            data["text"] = "successfully refreshed plugins"
        elif command == "register":
            self.register(message["user"], params)
        # Not found in internal commands, look for plugin to call
        else:
            data = self.call_plugin(command, params)
        if isinstance(data, str):
            data = {"text": data}
        data.setdefault("name", self.name)
        data.setdefault("as_user", True)
        if data:
            self.sc.api_call("chat.postMessage",
                             channel=message["channel"],
                             **data)

    def register(self, user, params):
        password = params
        if user in self.admins:
            print(self.admins)
            if self.verify_password(self.admins[user]["password"], password):
                print("user verified")
            else:
                print("incorrect password")
        else:
            self.admins[user]["password"] = self.hash_password(password)
            self.admins[user]["authed"] = True
            print("created new user with password {}".format(
                self.admins[user]["password"]))
        print(self.admins)

    def hash_password(self, password):
        """Hash a password for storing."""
        salt = hashlib.sha256(os.urandom(60)).hexdigest().encode('ascii')
        pwdhash = hashlib.pbkdf2_hmac('sha512', password.encode('utf-8'), salt,
                                      100000)
        pwdhash = binascii.hexlify(pwdhash)
        return (salt + pwdhash).decode('ascii')

    def verify_password(self, stored_password, provided_password):
        """Verify a stored password against one provided by user"""
        salt = stored_password[:64]
        print(stored_password)
        stored_password = stored_password[64:]
        pwdhash = hashlib.pbkdf2_hmac('sha512',
                                      provided_password.encode('utf-8'),
                                      salt.encode('ascii'), 100000)
        pwdhash = binascii.hexlify(pwdhash).decode('ascii')
        return pwdhash == stored_password

    def connect(self):
        if self.sc.rtm_connect(auto_reconnect=True):
            self.user_id = self.sc.server.login_data["self"]["id"]
            while 1:
                for message in self.sc.rtm_read():
                    self.handle_message(message)

    def run(self):
        self.connect()

    def save_admins(self):
        for user in self.admins.keys():
            self.admins[user]["authed"] = False
        with open("admins.json", "w") as fp:
            json.dump(self.admins, fp)
Пример #56
0
class SlackEvents(object):

    def __init__(self, slack_token, ui_url, bot_user, activity_channel,
                 map_user):
        self.sc = SlackClient(slack_token)
        self.ui_url = ui_url
        self.bot_user = bot_user
        self.activity_channel = activity_channel
        self.map_user = map_user
        self.channel_template = "mi-{}"

    def get_channel_name(self, case_id):
        return self.channel_template.format(case_id)[:21]

    def lookup_slack_channel_id(self, channel_name):
        # TODO: conditional caching based on output
        response = self.sc.api_call(
            "channels.list"
        )

        if not response['ok']:
            raise Exception(
                "Error while looking up channel ID: {}".format(response))

        for channel in response['channels']:
            if channel['name'] == channel_name:
                return channel['id']

        return None

    def lookup_slack_user_id(self, username):
        # TODO: conditional caching based on output
        response = self.sc.api_call(
            "users.list"
        )

        if not response['ok']:
            raise Exception(
                "Error while looking up user ID: {}".format(response))

        for member in response['members']:
            if member['name'] == username:
                return member['id']

        return None

    def get_case_url(self, case_id):
        url_template = "{}/#/cases/{{}}".format(self.ui_url)
        return url_template.format(case_id)

    def case_created(self, event):
        response = self.sc.api_call(
            "channels.create",
            name=self.get_channel_name(event['case']['id'])
        )

        if not response['ok']:
            logging.critical("Error while creating channel: %s", response)
            return

        normalized_name = response['channel']['name_normalized']
        channel_id = response['channel']['id']
        logging.info("Created channel '%s' in Slack", normalized_name)

        # Set channel purpose
        response = self.sc.api_call(
            "channels.setPurpose",
            channel=channel_id,
            purpose="Workspace for McAfee Investigator case '{}'. "
                    "Events related to this case will be posted here. ".format(
                        event['case']['name'])
        )
        if not response['ok']:
            logging.warning("Unable to set channel purpose: %s", response)

        slack_username = self.map_user(event['user'])
        slack_user_id = self.lookup_slack_user_id(slack_username)
        if slack_user_id:
            response = self.sc.api_call(
                "channels.invite",
                channel=channel_id,
                user=slack_user_id
            )
            if not response['ok']:
                logging.warning(
                    "Unable to invite user to channel: %s", response)
        else:
            logging.warning("User with handle '%s' not found", slack_username)

        response = self.sc.api_call(
            "chat.postMessage",
            channel=channel_id,
            as_user=False,
            link_names=True,
            parse="full",
            username=self.bot_user,
            attachments=[
                {
                    "title": "Case information",
                    "fallback": "Case URL: {}".format(
                        self.get_case_url(event['case']['id'])),
                    "fields": [
                        {
                            "title": "Name",
                            "value": event['case']['name']
                        },
                        {
                            "title": "ID",
                            "value": event['case']['id']
                        },
                        {
                            "title": "Reported by",
                            "value": event['user']
                        },
                    ],
                    "actions": [
                        {
                            "type": "button",
                            "text": "Open in McAfee Investigator",
                            "url": self.get_case_url(event['case']['id'])
                        }
                    ]
                }
            ]
        )
        if not response['ok']:
            logging.warning("Unable to post basic case information: %s",
                            response)

        # Mention the new case on the general channel
        activity_channel_id = self.lookup_slack_channel_id(
            self.activity_channel)
        if not activity_channel_id:
            logging.warning("Channel with name '%s' not found",
                            self.activity_channel)
            return

        response = self.sc.api_call(
            "chat.postMessage",
            channel=activity_channel_id,
            as_user=False,
            link_names=True,
            parse="full",
            username=self.bot_user,
            text="New channel #{} created for McAfee Investigator case `{}`. "
                 "@{} has been invited to join it".format(
                     normalized_name, event['case']['name'], slack_username)
        )

        if not response['ok']:
            logging.warning(
                "Unable to mention case creation on general channel: %s",
                response)

    def case_priority_updated(self, event):
        channel_id = self.lookup_slack_channel_id(
            self.get_channel_name(event['case']['id']))
        if not channel_id:
            logging.warning(
                "Channel with name '%s' not found", event['case']['id'])
            return

        response = self.sc.api_call(
            "chat.postMessage",
            channel=channel_id,
            as_user=False,
            link_names=True,
            parse="full",
            username=self.bot_user,
            attachments=[
                {
                    'title': "Priority update",
                    'text': priority_mapping[event['case']['priority']],
                    'color': color_mapping[event['case']['priority']]
                }
            ]
        )
        if not response['ok']:
            logging.warning("Unable to post priority update: %s", response)

    def case_status_updated(self, event):
        channel_id = self.lookup_slack_channel_id(
            self.get_channel_name(event['case']['id']))
        if not channel_id:
            logging.warning(
                "Channel with name '%s' not found", event['case']['id'])
            return

        response = self.sc.api_call(
            "chat.postMessage",
            channel=channel_id,
            as_user=False,
            link_names=True,
            parse="full",
            username=self.bot_user,
            attachments=[
                {
                    'title': "Status update",
                    'text': status_mapping[event['case']['status']],
                    'color': color_mapping['info']
                }
            ]
        )
        if not response['ok']:
            logging.warning("Unable to post status update: %s", response)

    def case_selected_ui(self, event):
        """A user started looking at a case in the UI
        """
        channel_id = self.lookup_slack_channel_id(
            self.get_channel_name(event['case']['id']))
        if not channel_id:
            logging.warning("Channel with name '%s' not found",
                            event['case']['id'])
            return

        response = self.sc.api_call(
            "chat.postMessage",
            channel=channel_id,
            as_user=False,
            link_names=True,
            parse="full",
            username=self.bot_user,
            attachments=[
                {
                    'title': "Time spent in case",
                    'text': 'User {} is currently looking at this case'.format(
                        event['user']),
                    'color': color_mapping['info']
                }
            ]
        )
        if not response['ok']:
            logging.warning("Unable to post status update: %s", response)

    def case_unselected_ui(self, event):
        """A user stopped looking at a case in the UI
        """
        channel_id = self.lookup_slack_channel_id(
            self.get_channel_name(event['case']['id']))
        if not channel_id:
            logging.warning(
                "Channel with name '%s' not found", event['case']['id'])
            return

        def map_time(seconds):
            return "{} seconds".format(seconds)

        response = self.sc.api_call(
            "chat.postMessage",
            channel=channel_id,
            as_user=False,
            link_names=True,
            parse="full",
            username=self.bot_user,
            attachments=[
                {
                    'title': "Time spent in case",
                    'text': 'User {} spent {} in this case'.format(
                        event['user'],
                        map_time(
                            event['case']
                            ['investigation-time']['elapsed-time'])),
                    'color': color_mapping['info']
                }
            ]
        )
        if not response['ok']:
            logging.warning("Unable to post status update: %s", response)
Пример #57
0
class Bot(object):
    """ Instanciates a Bot object to handle Slack onboarding interactions."""
    def __init__(self):
        super(Bot, self).__init__()
        self.name = "simplebot"
        self.targetChannel = ""
        # When we instantiate a new bot object, we can access the app
        # credentials we set earlier in our local development environment.
        self.oauth = {
            "client_id": os.environ.get("SLACK_CLIENT_ID"),
            "client_secret": os.environ.get("SLACK_CLIENT_SECRET"),
            # Scopes provide and limit permissions to what our app
            # can access. It's important to use the most restricted
            # scope that your app will need.
            "scope": "bot"
        }
        self.verification = os.environ.get("SLACK_VERIFICATION_TOKEN")

        # NOTE: Python-slack requires a client connection to generate
        # an oauth token. We can connect to the client without authenticating
        # by passing an empty string as a token and then reinstantiating the
        # client with a valid OAuth token once we have one.
        # self.client = SlackClient(os.environ.get("SLACK_BOT_TOKEN"))
        self.client = SlackClient("")
        # We'll use this dictionary to store the state of each message object.
        # In a production envrionment you'll likely want to store this more
        # persistantly in a database.
        self.messages = {}

    def auth(self, code):
        """
        Authenticate with OAuth and assign correct scopes.
        Save a dictionary of authed team information in memory on the bot
        object.

        Parameters
        ----------
        code : str
            temporary authorization code sent by Slack to be exchanged for an
            OAuth token

        """
        # After the user has authorized this app for use in their Slack team,
        # Slack returns a temporary authorization code that we'll exchange for
        # an OAuth token using the oauth.access endpoint
        auth_response = self.client.api_call(
            "oauth.access",
            client_id=self.oauth["client_id"],
            client_secret=self.oauth["client_secret"],
            code=code)

        # Save the bot token to an environmental variable or to your data store
        # for later use
        os.environ["SLACK_USER_TOKEN"] = auth_response['access_token']
        os.environ["SLACK_BOT_TOKEN"] = auth_response['bot'][
            'bot_access_token']

        # To keep track of authorized teams and their associated OAuth tokens,
        # we will save the team ID and bot tokens to the global
        # authed_teams object
        team_id = auth_response["team_id"]
        authed_teams[team_id] = {
            "bot_token": auth_response["bot"]["bot_access_token"]
        }
        # Then we'll reconnect to the Slack Client with the correct team's
        # SLACK_BOT_TOKEN
        self.client = SlackClient(authed_teams[team_id]["bot_token"])
Пример #58
0
import os
from slackclient import SlackClient

slack_token = os.environ["SLACK_API_TOKEN"]
sc = SlackClient(slack_token)

# Get the group channels with the following
# for group in sc.api_call("groups.list").get("groups"):
#    print("{}-{}".format(group['id'],group['name']))

sc.api_call(
  "chat.postMessage",
  channel="GDZULG3U0",
  text="Hello from Python! :tada:"
)
Пример #59
0
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")))
Пример #60
0
from slackclient import SlackClient

slack_token = os.environ['xoxp-403424165366-403181525847-421195613985-7594c85ab117e23784fdff76fe3120d0']
sc = SlackClient(slack_token)

sc.api_call(
  "chat.postMessage",
  channel="#modules-exercise",
  text="Hello from Python! :tada:"
)