Exemple #1
0
    async def incoming(self, msg):
        """
        Handler for the incoming events of type 'message'

        Create a message object from the incoming message and sent it
        to the plugins

        :param msg: incoming message
        :return:
        """
        logger.debug('Message handler received %s', msg)

        slack = registry.get('slack')
        message = await SlackMessage.from_raw(msg, slack)

        if not message.frm:  # Message without frm (i.e: slackbot)
            logger.debug('Ignoring message without frm')
            return

        if isinstance(self._save, list) and message.subtype in self._save \
                or self._save is True:
            try:
                db = registry.get('database')
                await self._save_incoming(message, db)
            except IntegrityError:
                logger.debug('Message "%s" already saved. Aborting.',
                             message.timestamp)
                return

        if message.frm.id in (self.bot.id, self.bot.bot_id):
            logger.debug('Ignoring message from ourselves')
            return

        await self._dispatch(message, slack)
Exemple #2
0
    async def _incoming(self, request):
        data = await request.post()
        data = {**data}

        if data['token'] != self._token:
            return Response(text='Invalid')

        logger.debug('Command handler received: %s', data['command'])

        slack = registry.get('slack')
        func = self._endpoints.get(data['command'])

        if not func:
            raise SlackUnknownCommand(data['command'])

        command = await SlackCommand.from_raw(data, slack)

        if isinstance(self._save, list) and data['command'] in self._save \
                or self._save is True:
            logger.debug('Saving incoming command %s from %s', command.command,
                         command.frm.id)
            db = registry.get('database')
            await database.__dict__[db.type].dispatcher.save_incoming_command(
                db, command)
            await db.commit()

        coroutine = func(command, slack)
        ensure_future(coroutine=coroutine, loop=self._loop, logger=logger)
        return Response(status=200)
Exemple #3
0
    async def _incoming(self, event):
        logger.debug('Event handler received: %s', event)

        slack = registry.get('slack')

        if isinstance(self._save, list) and event['type'] in self._save \
                or self._save is True:
            db = registry.get('database')
            await self._store_incoming(event, db)

        for func in self._endpoints.get(event['type'], list()):
            f = func(event, slack)
            ensure_future(coroutine=f, loop=self._loop, logger=logger)
Exemple #4
0
    async def _delete(self, id_, db=None):

        if not db:
            db = registry.get('database')

        await database.__dict__[db.type].group.delete(db, id_)
        await db.commit()
    async def send_issue_msg(self, issue, color):
        att = Attachment(fallback='issue {}'.format(issue.data['action']),
                         color=color,
                         text='*<{url}|{title}>*\n{body}'.format(
                             url=issue.data['issue']['html_url'],
                             title=issue.data['issue']['title'],
                             body=issue.data['issue']['body']),
                         title='Issue {action} in <{repo_url}|{name}>'.format(
                             repo_url=issue.data['repository']['html_url'],
                             name=issue.data['repository']['name'],
                             action=issue.data['action'],
                         ),
                         author_icon=issue.data['sender']['avatar_url'],
                         author_name=issue.data['sender']['login'],
                         author_link=issue.data['sender']['html_url'],
                         footer=', '.join(
                             label['name']
                             for label in issue.data['issue']['labels']))

        slack = registry.get('slack')
        channel = await slack.channels.get(
            name=self.config['github']['channel'])
        msg = SlackMessage(to=channel)
        msg.attachments.append(att)
        await slack.send(msg)
    async def send_pr_msg(self, pr, action, color):
        footer = '+ {add} / - {del_}'.format(
            add=pr.data['pull_request']['additions'],
            del_=pr.data['pull_request']['deletions'])

        att = Attachment(fallback='pull request {}'.format(action),
                         title='Pull request {action} in <{repo_url}|{name}>:'
                         ' <{url}|{title}>'.format(
                             repo_url=pr.data['repository']['html_url'],
                             url=pr.data['pull_request']['html_url'],
                             name=pr.data['repository']['name'],
                             action=pr.data['action'],
                             title=pr.data['pull_request']['title'],
                         ),
                         color=color,
                         text='*<{url}|{title}>*\n{body}'.format(
                             url=pr.data['pull_request']['html_url'],
                             title=pr.data['pull_request']['title'],
                             body=pr.data['pull_request']['body']),
                         author_icon=pr.data['sender']['avatar_url'],
                         author_name=pr.data['sender']['login'],
                         author_link=pr.data['sender']['html_url'],
                         footer=footer)

        slack = registry.get('slack')
        channel = await slack.channels.get(
            name=self.config['github']['channel'])
        msg = SlackMessage(to=channel)
        msg.attachments.append(att)
        await slack.send(msg)
Exemple #7
0
    async def start(self):
        logger.debug('Starting slack plugin')

        db = registry.get('database')
        if db.type not in SUPPORTED_DATABASE:
            raise SlackSetupError('Database must be one of %s',
                                  ', '.join(SUPPORTED_DATABASE))

        await self._create_db_table()

        slack = self.factory()
        sync.add_to_slack(slack)

        if self._rtm_client:
            data = await self._http_client.rtm_connect()
            self.bot = await self._users.get(data['self']['id'])
            self.bot.type = 'rtm'
            self._dispatcher['message'].bot = self.bot
            self._dispatcher['event'].bot = self.bot
            await self._rtm_client.connect(url=data['url'])
        else:
            self.bot = User(id_='B000000000')
            self.bot.type = 'event'
            if 'message' in self._dispatcher:
                self._dispatcher['message'].bot = self.bot
            if 'event' in self._dispatcher:
                self._dispatcher['event'].bot = self.bot
            self._started = True
Exemple #8
0
    async def _add(self, group, db=None):

        if not db:
            db = registry.get('database')

        await database.__dict__[db.type].group.add(db, group)
        await db.commit()
Exemple #9
0
    async def get(self, id_=None, fetch=False):

        db = registry.get('database')
        data = await database.__dict__[db.type].group.find(db, id_)

        if data and (fetch or data['last_update'] <
                     (time.time() - self._refresh)):
            group = await self._query(id_)

            if group:
                await self._add(group, db=db)
            else:
                await self._delete(group, db=db)

        elif data:
            group = Group(id_=data['id'],
                          raw=json.loads(data['raw']),
                          last_update=data['last_update'])
        else:
            logger.debug(
                'Group "%s" not found in the channel store. '
                'Querying the Slack API', id_)

            group = await self._query(id_)

            if group:
                await self._add(group, db=db)

        return group
Exemple #10
0
    async def thread(self, message, limit=20):
        db = registry.get('database')

        thread_ts = message.thread or message.timestamp
        raw_msgs = await database.__dict__[db.type].message.get_thread(
            db, thread_ts, limit)
        messages = await self._create_object(raw_msgs)
        return messages
Exemple #11
0
    async def _create_object(self, raw_msgs):
        slack = registry.get('slack')
        messages = list()
        for raw_msg in raw_msgs:
            message = await SlackMessage.from_raw(data=raw_msg['raw'],
                                                  slack=slack)
            messages.append(message)

        return messages
Exemple #12
0
    async def _add(self, channel, db=None):
        """
        Add a channel to the channel store
        """

        if not db:
            db = registry.get('database')

        await database.__dict__[db.type].channel.add(db, channel)
        await db.commit()
Exemple #13
0
 async def _create_db_table(self):
     db = registry.get('database')
     await db.execute('''
         CREATE TABLE IF NOT EXISTS candy (
         user TEXT PRIMARY KEY NOT NULL,
         candy INT DEFAULT 0
         )
         ''')
     await db.set_plugin_metadata(self)
     await db.commit()
Exemple #14
0
    async def ensure_dm(self, user, db=None):

        if not user.send_id:
            if not db:
                db = registry.get('database')

            user.dm_id = await self._client.open_dm(user.id)
            await database.__dict__[db.type].user.update_dm_id(
                db, user.id, user.dm_id)
            await db.commit()
Exemple #15
0
    async def repo_deleted(self, event):

        slack = registry.get('slack')
        channel = await slack.channels.get(
            name=self.config['github']['channel'])
        msg = SlackMessage(to=channel)
        msg.text = 'Repository {repo} deleted by {user} :cold_sweat:'.format(
            repo=event.data['repository']['name'],
            user=event.data['sender']['login'])
        await slack.send(msg)
Exemple #16
0
    async def release_created(self, event):

        slack = registry.get('slack')
        channel = await slack.channels.get(
            name=self.config['github']['channel'])
        msg = SlackMessage(to=channel)
        msg.text = 'Release {release} created in {repo} by {user}'.format(
            release=event.data['release']['tag_name'],
            repo=event.data['repository']['name'],
            user=event.data['sender']['login'])
        await slack.send(msg)
Exemple #17
0
    async def hiring(self):
        slack = registry.get('slack')

        channel = await slack.channels.get(name='job_board')
        message = SlackMessage(to=channel)
        message.text = self.config['python_jobs']['hiring']
        await slack.send(message)

        message_tips = SlackMessage(to=channel)
        message_tips.text = self.config['python_jobs']['hiring_tips']
        message_tips.thread = message.thread
        await slack.send(message_tips)
Exemple #18
0
    async def _add(self, user, db=None):
        """
        Add an user to the UserManager

        :param user: users to add
        """

        if not db:
            db = registry.get('database')

        await database.__dict__[db.type].user.add(db, user)
        await db.commit()
Exemple #19
0
    async def _delete(self, id_, db=None):
        """
        Delete an user from the UserManager

        :param id_: id of the user
        :return: None
        """

        if not db:
            db = registry.get('database')

        await database.__dict__[db.type].user.delete(db, id_)
        await db.commit()
Exemple #20
0
    async def _incoming(self, request):
        data = await request.post()

        if 'payload' not in data:
            return Response(text='Invalid', status=400)

        payload = json.loads(data['payload'])

        if 'token' not in payload or payload['token'] != self._token:
            return Response(text='Invalid', status=400)

        logger.debug('Action handler received: %s', payload)

        slack = registry.get('slack')
        settings = self._endpoints.get(payload['callback_id'])

        if not settings:
            raise SlackUnknownAction(payload)

        action = await SlackAction.from_raw(payload, slack, settings=settings)

        if isinstance(self._save, list) and payload['callback_id'] \
                in self._save or self._save is True:
            logger.debug('Saving incoming action %s from %s',
                         action.callback_id, action.frm.id)
            db = registry.get('database')
            await database.__dict__[db.type].dispatcher.save_incoming_action(
                db, action)
            await db.commit()

        coroutine = settings['func'](action, slack)
        ensure_future(coroutine=coroutine, loop=self._loop, logger=logger)

        if settings.get('public'):
            return Response(status=200,
                            body=json.dumps({"response_type": "in_channel"}),
                            content_type='application/json; charset=utf-8')
        else:
            return Response(status=200)
Exemple #21
0
    async def _delete(self, id_, db=None):
        """
        Delete a channel from the channel store

        :param id_: id of the channel
        :return: None
        """

        if not db:
            db = registry.get('database')

        await database.__dict__[db.type].channel.delete(db, id_)
        await db.commit()
Exemple #22
0
    def add(self):
        github = registry.get('github')

        github.register(self.issues_opened, 'issues', action='opened')
        github.register(self.issues_closed, 'issues', action='closed')
        github.register(self.issues_reopened, 'issues', action='reopened')

        github.register(self.pr_opened, 'pull_request', action='opened')
        github.register(self.pr_closed, 'pull_request', action='closed')
        github.register(self.pr_reopened, 'pull_request', action='reopened')

        github.register(self.release_created, 'release', action='published')
        github.register(self.repo_created, 'repository', action='created')
        github.register(self.repo_deleted, 'repository', action='deleted')
Exemple #23
0
    async def add(self, user, count=1):
        db = registry.get('database')
        await db.execute('''SELECT candy FROM candy WHERE user = ? ''',
                         (user, ))
        value = await db.fetchone()
        if value:
            value = value['candy'] + count
        else:
            value = count

        await db.execute(
            '''INSERT OR REPLACE INTO candy (user, candy)
                            VALUES (?, ?)''', (user, value))
        await db.commit()
        return value
Exemple #24
0
    async def get(self, id_=None, name=None, fetch=False):
        """
        Return a Channel from the Channel Manager

        :param id_: id of the channel
        :param name: name of the channel
        :param update: query the slack api for updated channel info
        :return: Channel
        """
        if not id_ and not name:
            raise SyntaxError('id_ or name must be supplied')

        db = registry.get('database')
        if name:
            data = await database.__dict__[db.type].channel.find_by_name(db,
                                                                         name)
        else:
            data = await database.__dict__[db.type].channel.find_by_id(db, id_)

        if data and (
                fetch or data['last_update'] < (time.time() - self._refresh)):
            channel = await self._query_by_id(data['id'])

            if channel:
                await self._add(channel, db=db)
            else:
                await self._delete(channel, db=db)

        elif data:
            channel = Channel(
                id_=data['id'],
                raw=json.loads(data['raw']),
                last_update=data['last_update']
            )
        else:
            logger.debug('Channel "%s" not found in the channel store. '
                         'Querying the Slack API', (id_ or name))
            if id_:
                channel = await self._query_by_id(id_)
            else:
                channel = await self._query_by_name(name)

            if channel:
                await self._add(channel, db=db)

        return channel
Exemple #25
0
    async def pypi_search(self, command, slack):
        response = command.response()
        pypi = registry.get('pypi')
        results = await pypi.search(command.text)

        if not command.text:
            response.response_type = 'ephemeral'
            response.text = 'Please enter the package name you wish to find'
            await slack.send(response)
            return

        if results:
            for result in results[:3]:
                att = Attachment(title=result['name'],
                                 fallback=result['name'],
                                 text=result['summary'],
                                 title_link='{}/{}'.format(
                                     pypi.ROOT_URL, result['name']))
                response.attachments.append(att)

            if len(results) == 4:
                att = Attachment(title=results[3]['name'],
                                 fallback=results[3]['name'],
                                 text=results[3]['summary'],
                                 title_link='{}/{}'.format(
                                     pypi.ROOT_URL, results[3]['name']))
                response.attachments.append(att)

            elif len(results) > 3:
                path = pypi.SEARCH_PATH.format(command.text)
                more_info = Attachment(
                    title='{0} more results..'.format(len(results) - 3),
                    fallback='{0} more results..'.format(len(results) - 3),
                    title_link='{}/{}'.format(pypi.ROOT_URL, path))
                response.attachments.append(more_info)

            response.response_type = 'in_channel'
            response.text = "<@{}> Searched PyPi for `{}`".format(
                command.frm.id, command.text)
        else:
            response.response_type = 'ephemeral'
            response.text = "Could not find anything on PyPi matching" \
                            " `{0}`".format(command.text)

        await slack.send(response)
Exemple #26
0
    def add(self):
        slack = registry.get('slack')
        slack.add_message('^help',
                          self.help_,
                          flags=re.IGNORECASE,
                          mention=True)
        slack.add_message(
            'tell (<(#|@)(?P<to_id>[A-Z0-9]*)(|.*)?>)'
            ' (?P<item>.*)',
            self.publish,
            flags=re.IGNORECASE,
            mention=True,
            admin=True)
        slack.add_message('hello',
                          self.hello,
                          mention=True,
                          flags=re.IGNORECASE)

        slack.add_message('hodor',
                          self.hodor,
                          flags=re.IGNORECASE,
                          channel_id='C699LH85A')

        slack.add_command('/admin', func=self.share_admin)

        slack.add_message(self.config['candy']['trigger'],
                          self.add_candy_message)
        slack.add_command('/leaderboard', self.leaderboard)
        slack.add_event('reaction_added', self.add_candy_reaction)

        slack.add_command('/do', self.share_digital_ocean)

        slack.add_action('choose_file', self.choose_file)
        slack.add_command('/file', self.file)

        slack.add_command('/gif', self.gif_search)
        slack.add_action('gif_search', self.gif_search_action)

        slack.add_event('team_join', self.team_join)
        slack.add_event('team_join', self.members_joined)

        slack.add_command('/pypi', self.pypi_search)

        slack.add_command('/moveto', self.move_to)
Exemple #27
0
    async def all(self, fetch=False, deleted=False):
        """
        Retrieve all user of the slack team

        When fetch is True no dm_id are provided

        :param fetch:
        :param deleted:
        :return:
        """
        db = registry.get('database')

        if fetch:
            users = list()
            fetched_data = await self._client.get_users()
            for data in fetched_data:
                user = User(id_=data['id'],
                            raw=data,
                            last_update=time.time(),
                            deleted=data['deleted'])

                await database.__dict__[db.type].user.add(db,
                                                          user,
                                                          dm_id=False)
                if deleted:
                    users.append(user)
                elif not deleted and not user.deleted:
                    users.append(user)
            await db.commit()
        else:
            data = await database.__dict__[db.type
                                           ].user.get_all(db, deleted=deleted)
            users = [
                User(id_=raw_data['id'],
                     raw=raw_data['raw'],
                     last_update=raw_data['last_update'],
                     dm_id=raw_data['dm_id'],
                     deleted=raw_data['deleted']) for raw_data in data
            ]

        return users
Exemple #28
0
    async def leaderboard(self, command, slack):
        response = command.response()

        candy = registry.get('candy')
        data = await candy.top(count=10)
        att = Attachment(
            title='{} Leaderboard'.format(self.config['candy']['trigger']),
            fallback='{} Leaderboard'.format(self.config['candy']['trigger']),
            color='good')

        if not data:
            response.text = 'No data to display'
        else:
            response.response_type = 'in_channel'
            for user in data:
                slack_user = await slack.users.get(user['user'])
                att.text += '{} *{}*\n'.format(slack_user.name, user['candy'])

            response.attachments.append(att)

        await slack.send(response)
Exemple #29
0
    async def add_candy_message(self, message, slack, *_):
        users_raw = self.config['candy']['user_regex'].findall(message.text)
        users = [
            user[2:-1] for user in users_raw if user[2:-1] != message.frm.id
        ]

        if not users:
            return

        candy = registry.get('candy')
        response = message.response()
        count = len(self.config['candy']['trigger_regex'].findall(
            message.text))

        receivers_messages = list()
        for user in users:
            slack_user = await slack.users.get(user, dm=True)
            user_count = await candy.add(user, count)
            msg = response.clone()
            msg.to = slack_user

            text_message = '<@{sender}> gave you {count} {trigger}.' \
                           ' You now have {user_count} {trigger}.'
            msg.text = text_message.format(
                sender=message.frm.id,
                count=count,
                trigger=self.config['candy']['trigger'],
                user_count=user_count)
            receivers_messages.append(msg)

        response.to = message.frm
        response.text = 'You gave {count} {trigger} to <@{user}>'.format(
            count=count,
            trigger=self.config['candy']['trigger'],
            user='******'.join(users))

        await slack.send(response)
        for msg in receivers_messages:
            await slack.send(msg)
Exemple #30
0
    async def get(self, id_, fetch=False, dm=False):
        """
        Return an User from the User Manager

        If the user doesn't exist query the slack API for it

        :param id_: id of the user
        :param dm: Query the direct message channel id
        :param update: query the slack api for updated user info
        :return: User
        """
        db = registry.get('database')
        data = await database.__dict__[db.type].user.find(db, id_)

        if data and (fetch
                     or data['last_update'] < time.time() - self._refresh):
            user = await self._query(id_, data['dm_id'])

            if user:
                await self._add(user)
            else:
                await self._delete(id_, db)
        elif data:
            user = User(id_=id_,
                        raw=json.loads(data['raw']),
                        dm_id=data['dm_id'],
                        last_update=data['last_update'],
                        deleted=data['deleted'])
        else:
            user = await self._query(id_)
            if user:
                await self._add(user)
        if dm:
            await self.ensure_dm(user, db)

        return user