def test_process_returns_unicode(self): plugin = Mock() plugin.process.return_value = ['foo', 'bar', self.snowman] with patch.object(registry, 'prioritized') as prio: prio.return_value = [plugin] responses = registry.process('', '', '', '') assert all(map(lambda x: isinstance(x, unicode), responses))
def test_process_ignores_exception(self): settings.PLUGIN_FIRST_RESPONDER_ONLY = True things = [Mock(), Mock()] # Make the middle one raise things[0].process.side_effect = Exception things[1].process.return_value = 'foo' with patch.object(registry, 'prioritized') as prio: prio.return_value = things response = registry.process(None, '#bots', 'me', 'foobar') assert response == [u'foo']
def test_process_returns_first_response(self): settings.PLUGIN_FIRST_RESPONDER_ONLY = True things = [Mock(), Mock(), Mock()] # Make the middle one raise things[0].process.return_value = ['foo', 'bar', None] things[1].process.return_value = self.snowman things[2].process.return_value = 'baz' with patch.object(registry, 'prioritized') as prio: prio.return_value = things response = registry.process(None, '#bots', 'me', 'foobar') assert response == [u'foo', u'bar']
def test_process_stops_when_async(self): things = [Mock(), Mock(), Mock()] # Make the middle one raise things[0].process.return_value = None things[1].process.side_effect = ResponseNotReady things[2].process.return_value = None with patch.object(registry, 'prioritized') as prio: prio.return_value = things assert [] == registry.process(None, '#bots', 'me', 'foobar') assert things[1].process.called assert not things[2].process.called
def on_message(self, element): """ Handler for an XMPP message. This method handles logging channel messages (if it occurs on a public channel) as well as allowing the plugin manager to send the message to all registered plugins. Should the plugin manager yield a response, it will be sent back. :param message: A <message/> element, instance of `twisted.words.xish.domish.Element` """ nick = self.parse_nick(element) channel = self.parse_channel(element) message = self.parse_message(element) # This will be empty for messages that were delayed if not message: return # If we don't ignore this, we'll get infinite replies if nick == self.nickname: return # Log the incoming message and notify message subscribers logger.debug('[<--] %s/%s - %s', channel, nick, message) is_public = self.is_public_channel(channel) # When we get a priv msg, the channel is our current nick, so we need to # respond to the user that is talking to us if is_public: # Only log convos on public channels self.log_channel_message(channel, nick, message) else: channel = nick # Some things should go first try: channel, nick, message = registry.preprocess( self, channel, nick, message) except (TypeError, ValueError): pass # if not message.has_response: responses = registry.process(self, channel, nick, message) if responses: message = u'\n'.join(responses) self.msg(channel, message) if is_public: self.log_channel_message(channel, self.nickname, message) # Update last message self.last_message[channel][nick] = message
def on_message(self, element): """ Handler for an XMPP message. This method handles logging channel messages (if it occurs on a public channel) as well as allowing the plugin manager to send the message to all registered plugins. Should the plugin manager yield a response, it will be sent back. :param message: A <message/> element, instance of `twisted.words.xish.domish.Element` """ nick = self.parse_nick(element) channel = self.parse_channel(element) message = self.parse_message(element) # This will be empty for messages that were delayed if not message: return # If we don't ignore this, we'll get infinite replies if nick == self.nickname: return # Log the incoming message and notify message subscribers logger.debug('[<--] %s/%s - %s', channel, nick, message) is_public = self.is_public_channel(channel) # When we get a priv msg, the channel is our current nick, so we need to # respond to the user that is talking to us if is_public: # Only log convos on public channels self.log_channel_message(channel, nick, message) else: channel = nick # Some things should go first try: channel, nick, message = registry.preprocess(self, channel, nick, message) except (TypeError, ValueError): pass # if not message.has_response: responses = registry.process(self, channel, nick, message) if responses: message = u'\n'.join(responses) self.msg(channel, message) if is_public: self.log_channel_message(channel, self.nickname, message) # Update last message self.last_message[channel][nick] = message
def test_process_async_honors_first_response(self): things = [Mock(), Mock(), Mock()] # Make the middle one raise things[0].process.side_effect = ResponseNotReady things[1].process.return_value = None things[2].process.return_value = None with patch.object(registry, 'prioritized') as prio: with patch.object(settings, 'PLUGIN_FIRST_RESPONDER_ONLY', True): prio.return_value = things assert [] == registry.process(None, '#bots', 'me', 'foobar') assert things[0].process.called assert not things[1].process.called assert not things[2].process.called
def test_process_async_honors_all_responses(self): things = [Mock(), Mock(), Mock()] # Make the middle one raise things[0].process.return_value = None things[1].process.side_effect = ResponseNotReady things[2].process.return_value = None with patch.object(registry, 'prioritized') as prio: with patch.object(settings, 'PLUGIN_FIRST_RESPONDER_ONLY', False): prio.return_value = things assert [] == registry.process(None, '#bots', 'me', 'foobar') assert things[0].process.called assert things[1].process.called assert things[2].process.called
def privmsg(self, user, channel, message): """ Handler for an IRC message. This method handles logging channel messages (if it occurs on a public channel) as well as allowing the plugin manager to send the message to all registered plugins. Should the plugin manager yield a response, it will be sent back over IRC. :param user: IRC user string of the form ``{nick}!~{user}@{host}`` :param channel: the channel from which the message came :param message: the message contents """ user = self.parse_nick(user) message = message.strip() # Log the incoming message and notify message subscribers logger.debug('[<--] %s/%s - %s', channel, user, message) is_public = self.is_public_channel(channel) # When we get a priv msg, the channel is our current nick, so we need to # respond to the user that is talking to us if is_public: # Only log convos on public channels self.log_channel_message(channel, user, message) else: channel = user # Some things should go first try: channel, user, message = registry.preprocess( self, channel, user, message) except (TypeError, ValueError): pass # if not message.has_response: responses = registry.process(self, channel, user, message) if responses: message = u'\n'.join(responses) self.msg(channel, message) if is_public: self.log_channel_message(channel, self.nickname, message) # Update last message self.last_message[channel][user] = message
def privmsg(self, user, channel, message): """ Handler for an IRC message. This method handles logging channel messages (if it occurs on a public channel) as well as allowing the plugin manager to send the message to all registered plugins. Should the plugin manager yield a response, it will be sent back over IRC. :param user: IRC user string of the form ``{nick}!~{user}@{host}`` :param channel: the channel from which the message came :param message: the message contents """ user = self.parse_nick(user) message = message.strip() # Log the incoming message and notify message subscribers logger.debug('[<--] %s/%s - %s', channel, user, message) is_public = self.is_public_channel(channel) # When we get a priv msg, the channel is our current nick, so we need to # respond to the user that is talking to us if is_public: # Only log convos on public channels self.log_channel_message(channel, user, message) else: channel = user # Some things should go first try: channel, user, message = registry.preprocess(self, channel, user, message) except (TypeError, ValueError): pass # if not message.has_response: responses = registry.process(self, channel, user, message) if responses: message = u'\n'.join(responses) self.msg(channel, message) if is_public: self.log_channel_message(channel, self.nickname, message) # Update last message self.last_message[channel][user] = message
def slack_message(self, data): """ Handler for an incoming Slack message event. This method allows the plugin manager to send the message to all registered plugins. Should the plugin manager yield a response, it will be sent back over Slack. :param data: dict from JSON received in WebSocket message """ # Look up the human-readable name for this user ID. user = self._get_user_name(data['user']) # If we don't ignore this, we'll get infinite replies if user == self.nickname: return channel = self._get_channel_name(data['channel']) if channel: # If this was a legit channel, prefix it with a hash for later consistency channel = u'#{}'.format(channel) # I'm not sure if 100% of all messages have a "text" value. Use a blank # string fallback to be safe. message = data.get('text', '') message = self._parse_incoming_message(message) # Log the incoming message logger.debug('[<--] %s/%s - %s', channel, user, message) # Some things should go first try: channel, user, message = registry.preprocess( self, channel, user, message) except (TypeError, ValueError): pass # Update last message self.last_message[channel][user] = message responses = registry.process(self, channel, user, message) if responses: return self.msg(channel, u'\n'.join(responses))
def slack_message(self, data): """ Handler for an incoming Slack message event. This method allows the plugin manager to send the message to all registered plugins. Should the plugin manager yield a response, it will be sent back over Slack. :param data: dict from JSON received in WebSocket message """ # Look up the human-readable name for this user ID. user = self._get_user_name(data['user']) # If we don't ignore this, we'll get infinite replies if user == self.nickname: return channel = self._get_channel_name(data['channel']) if channel: # If this was a legit channel, prefix it with a hash for later consistency channel = u'#{}'.format(channel) # I'm not sure if 100% of all messages have a "text" value. Use a blank # string fallback to be safe. message = data.get('text', '') message = self._parse_incoming_message(message) # Log the incoming message logger.debug('[<--] %s/%s - %s', channel, user, message) # Some things should go first try: channel, user, message = registry.preprocess(self, channel, user, message) except (TypeError, ValueError): pass # Update last message self.last_message[channel][user] = message responses = registry.process(self, channel, user, message) if responses: return self.msg(channel, u'\n'.join(responses))