Exemple #1
0
    def test_handle_message(self):
        expected = MessageEvent(
            username='******',
            channel_name='general',
            text='?I like to :poop:',
        )
        result = None

        def mock_handle_message(_, message: MessageEvent,
                                reply_channel: Callable[[str], bool]):
            nonlocal result
            result = message

        patcher = mock.patch(target='frisky.bot.Frisky.handle_message',
                             new=mock_handle_message)

        with responses.RequestsMock() as rm:
            rm.add('GET', f'{URL}/users.info?user=W012A3CDE', body=USER_OK)
            rm.add('GET',
                   f'{URL}/conversations.info?channel=123',
                   body=conversation)

            try:
                patcher.start()
                handle_message_event(
                    MessageSent(channel='123',
                                user='******',
                                text='?I like to :poop:',
                                ts='123',
                                event_ts='123',
                                channel_type='channel'))
                self.assertEqual(expected, result)
            finally:
                patcher.stop()
Exemple #2
0
def handle_reaction_event(event: ReactionAdded):
    user = slack_api_client.get_user(event.user)
    channel = slack_api_client.get_channel(event.item.channel)
    item_user = slack_api_client.get_user(event.item_user)
    added = event.type == 'reaction_added'

    message_text = None
    if not channel.is_private:
        message = slack_api_client.get_message(channel, event.item.ts)
        if message is not None:
            if len(message.text) > 0:
                message_text = sanitize_message_text(message.text)
            elif message.files is not None and len(message.files) > 0:
                message_text = message.files[0].permalink

    else:
        logger.debug(
            'Did not query api for message, because we are in a private channel'
        )

    frisky.handle_reaction(ReactionEvent(
        emoji=event.reaction,
        username=user.get_short_name(),
        added=added,
        message=MessageEvent(
            username=item_user.get_short_name(),
            channel_name=channel.name,
            text=message_text,
        ),
    ),
                           reply_channel=lambda reply: slack_api_client.
                           post_message(channel, reply))
Exemple #3
0
 def test_unhandled_command_returns_none(self):
     message_event = MessageEvent(
         username='******',
         channel_name='general',
         text='?hello world'
     )
     response = self.plugin.handle_message(message_event)
     self.assertIsNone(response)
Exemple #4
0
def handle_message_event(event: MessageSent):
    if not event.text.startswith(settings.FRISKY_PREFIX):
        return

    user = slack_api_client.get_user(event.user)
    channel = slack_api_client.get_channel(event.channel)

    frisky.handle_message(
        MessageEvent(
            username=user.get_short_name(),
            channel_name=channel.name,
            text=sanitize_message_text(event.text),
        ),
        reply_channel=lambda reply: reply_channel(channel, reply))
Exemple #5
0
 def test_unhandled_reaction_returns_none(self):
     message_event = MessageEvent(
         username='******',
         channel_name='general',
         text='?hello world'
     )
     reaction_event = ReactionEvent(
         emoji='bacon',
         username='******',
         added=True,
         message=message_event
     )
     response = self.plugin.handle_reaction(reaction_event)
     self.assertIsNone(response)
Exemple #6
0
 def handle_message(self, message: MessageEvent, reply_channel: Callable[[FriskyResponse], bool]) -> None:
     if message.channel_name in self.ignored_channels or message.username == self.name:
         return
     message.command, message.args = self.parse_message_string(message.text)
     if message.command != '':
         plugins = self.get_plugins_for_command(message.command)
         if len(plugins) == 0:
             # Reformat the message as a generic one
             message = self.convert_message_to_generic(message)
             plugins = self.get_generic_handlers()
         for plugin in plugins:
             reply = plugin.handle_message(message)
             if reply is not None:
                 reply_channel(reply)
Exemple #7
0
 def handle_message_synchronously(self, message: MessageEvent) -> List[FriskyResponse]:
     message.command, message.args = self.parse_message_string(message.text)
     replies = []
     if message.command != '':
         plugins = self.get_plugins_for_command(message.command)
         if len(plugins) == 0:
             # Reformat the message as a generic one
             message = self.convert_message_to_generic(message)
             plugins = self.get_generic_handlers()
         for plugin in plugins:
             reply = plugin.handle_message(message)
             if reply is not None:
                 replies.append(reply)
     return replies
Exemple #8
0
    def send_message(self, message, user='******', channel='testing'):
        result = None
        event = MessageEvent(
            username=user,
            channel_name=channel,
            text=message,
        )

        def callback(response: str) -> bool:
            nonlocal result
            result = response
            return True

        self.frisky.handle_message(event, callback)
        return result
Exemple #9
0
def process_from_cli(data):
    text = data['message']
    if not text.startswith(settings.FRISKY_PREFIX):
        text = f'{settings.FRISKY_PREFIX}{text}'
    message = MessageEvent(
        username=data['username'],
        channel_name=data['channel'],
        text=text,
    )
    conversation = Conversation(
        id=data['channel'],
        name=data['channel'],
        is_channel=True,
    )
    for reply in frisky.handle_message_synchronously(message):
        if reply is not None:
            slack_api_client.post_message(conversation, reply)
Exemple #10
0
 def handle_message(self, message: MessageEvent) -> FriskyResponse:
     if len(message.args) != 1 or message.args[0] == 'help':
         return self._help_text
     meme_id = MemeAlias.objects.get_id_for_alias(message.args[0])
     if meme_id == -1:
         return 'NO SUCH MEME'
     try:
         meme_message: str = Learn.objects.random(message.args[0]).content
     except ValueError:
         return 'NO SUCH LEARN'
     return self.get_plugin_for_command('meme').handle_message(
         MessageEvent(
             username=message.username,
             channel_name=message.channel_name,
             text='',
             command='meme',
             args=[message.args[0], '', meme_message],
         ))
Exemple #11
0
    def handle_message(self, message: MessageEvent) -> Optional[str]:
        """
        example usage: `?pipe votes thing | learn thing | ping`
        :param message:
        :return:
        """
        if message.command not in ('pipe', '|'):
            return
        built_args = []
        for arg in message.args:
            arg = arg.strip()
            if ' ' in arg:
                built_args.append(f'"{arg}"')
            else:
                built_args.append(arg)
        raw_text = ' '.join(built_args)
        split_commands = raw_text.split('|')

        previous_result: Optional[str] = None
        for item in split_commands:
            item = item.strip(' ')
            if previous_result:
                item = ' '.join([item, f'"{previous_result}"'])
            split_item = quotesplit(item.strip(' '))
            command: str = split_item[0]
            args: List[str] = split_item[1:]
            plugin = self.get_plugin_for_command(command)

            event = MessageEvent(username=message.username,
                                 channel_name=message.channel_name,
                                 text=item,
                                 command=command,
                                 args=args)
            if plugin is None:
                plugin = self.get_generic_handler()
                if plugin is None:
                    return
                event = self.convert_message_to_generic(event)
            previous_result = plugin.handle_message(event)
        return previous_result
Exemple #12
0
    def test_handle_reaction(self):
        expected = ReactionEvent(
            emoji='poop',
            username='******',
            added=True,
            message=MessageEvent(
                username='******',
                channel_name='general',
                text=
                'I find you punny and would like to smell your nose letter',
            ))
        result = None

        def mock_handle_reaction(_, reaction: ReactionEvent,
                                 reply_channel: Callable[[str], bool]):
            nonlocal result
            result = reaction

        patcher = mock.patch(target='frisky.bot.Frisky.handle_reaction',
                             new=mock_handle_reaction)

        with responses.RequestsMock() as rm:
            rm.add('GET', f'{URL}/users.info?user=W012A3CDE', body=USER_OK)
            rm.add('GET',
                   f'{URL}/conversations.info?channel=123',
                   body=conversation)
            api = f'{URL}/conversations.history?channel=C012AB3CD&oldest=123&latest=123&inclusive=true&limit=1'
            rm.add('GET', api, body=message)
            try:
                patcher.start()
                handle_reaction_event(event=ReactionAdded(
                    type='reaction_added',
                    user='******',
                    item=ReactionItem(type='message', channel='123', ts='123'),
                    reaction='poop',
                    item_user='******',
                    event_ts='123'))
                self.assertEqual(expected, result)
            finally:
                patcher.stop()
Exemple #13
0
def get_response(request):
    if request.method != 'POST':
        raise Http404()

    api_token = get_jwt_from_headers(request.headers)
    if api_token.get('general', None) != 'true':
        logging.debug('Token was valid, but not for general api')
        raise Http404()
    received_json_data = json.loads(request.body.decode("utf-8"))

    message = received_json_data['message']
    username = received_json_data['username']
    channel = received_json_data['channel']

    if not message.startswith(settings.FRISKY_PREFIX):
        message = f'{settings.FRISKY_PREFIX}{message}'

    from frisky.bot import get_configured_frisky_instance
    frisky = get_configured_frisky_instance()
    responses = frisky.handle_message_synchronously(
        MessageEvent(username=username, channel_name=channel, text=message))
    return JsonResponse({
        'replies': responses,
    })
Exemple #14
0
    def send_reaction(self,
                      reaction,
                      from_user,
                      to_user,
                      reacted_message='yolo',
                      channel='testing',
                      reaction_removed=False):
        result = None
        event = ReactionEvent(emoji=reaction,
                              username=from_user,
                              added=not reaction_removed,
                              message=MessageEvent(
                                  username=to_user,
                                  channel_name=channel,
                                  text=reacted_message,
                              ))

        def callback(response: str) -> bool:
            nonlocal result
            result = response
            return True

        self.frisky.handle_reaction(event, callback)
        return result
Exemple #15
0
 def convert_message_to_generic(message: MessageEvent) -> MessageEvent:
     message.args = [message.command] + message.args
     message.command = '*'
     return message
Exemple #16
0
def process_event(data):
    slack_api_client = SlackApiClient(settings.SLACK_ACCESS_TOKEN)
    # noinspection PyBroadException
    try:
        if data['event'].get('subtype') in SUBTYPE_BLACKLIST:
            logger.debug(f'Ignoring {data["event"]["event_id"]}, subtype was in blacklist')
            return
        event_wrapper: Event = Event.from_dict(data)
        event = event_wrapper.get_event()
        # team = slack_api_client.get_workspace(data['team_id'])
        frisky = Frisky(
            name=settings.FRISKY_NAME,
            prefix=settings.FRISKY_PREFIX,
            ignored_channels=settings.FRISKY_IGNORED_CHANNELS,
        )

        if isinstance(event, ReactionAdded):
            user = slack_api_client.get_user(event.user)
            channel = slack_api_client.get_channel(event.item.channel)
            item_user = slack_api_client.get_user(event.item_user)
            added = event.type == 'reaction_added'
            message = slack_api_client.get_message(channel, event.item.ts)

            frisky.handle_reaction(
                ReactionEvent(
                    emoji=event.reaction,
                    username=user.get_short_name(),
                    added=added,
                    message=MessageEvent(
                        username=item_user.get_short_name(),
                        channel_name=channel.name,
                        text=message.text,
                        command='',
                        args=tuple(),
                    ),
                ),
                reply_channel=lambda reply: slack_api_client.post_message(channel, reply)
            )
        elif isinstance(event, MessageSent):
            user = slack_api_client.get_user(event.user)
            if event.channel_type == 'im':
                # TODO: Is there an api method (or a reason) to look this up?
                channel = Conversation(id=event.channel, name=user.name)
            elif event.channel_type == 'channel':
                channel = slack_api_client.get_channel(event.channel)
            else:
                return
            frisky.handle_message(
                MessageEvent(
                    username=user.get_short_name(),
                    channel_name=channel.name,
                    text=event.text,
                    command='',
                    args=tuple(),
                ),
                reply_channel=lambda res: reply(slack_api_client, channel, res)
            )
    except KeyError as err:
        stacktrace = traceback.format_exc()
        slack_api_client.emergency_log(stacktrace)
        slack_api_client.emergency_log(f'Trouble deserializing this event:\n{str(data)}')
        logger.warning('KeyError thrown deserializing event', exc_info=err)
    except Exception as err:
        stacktrace = traceback.format_exc()
        log_message = f'{stacktrace}\nCaused by:\n{str(data)}'
        slack_api_client.emergency_log(log_message)
        logger.warning('General exception thrown handling event', exc_info=err)