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()
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))
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)
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))
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)
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)
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
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
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)
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], ))
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
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()
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, })
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
def convert_message_to_generic(message: MessageEvent) -> MessageEvent: message.args = [message.command] + message.args message.command = '*' return message
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)