def test_send_reply(self): client = FakeClient() profile = client.get_profile() handler = ExternalBotHandler( client=client, root_dir=None, bot_details=None, bot_config_file=None ) to = {"id": 43} expected = [ ( {"type": "private", "display_recipient": [to]}, {"type": "private", "to": [to["id"]]}, None, ), ( {"type": "private", "display_recipient": [to, profile]}, {"type": "private", "to": [to["id"], profile["id"]]}, "widget_content", ), ( {"type": "stream", "display_recipient": "Stream name", "subject": "Topic"}, {"type": "stream", "to": "Stream name", "subject": "Topic"}, "test widget", ), ] response_text = "Response" for test in expected: client.send_message = MagicMock() handler.send_reply(test[0], response_text, test[2]) client.send_message.assert_called_once_with( dict(test[1], content=response_text, widget_content=test[2]) )
def test_basics(self): client = FakeClient() handler = ExternalBotHandler( client=client, root_dir=None, bot_details=None, bot_config_file=None ) message = None handler.send_message(message)
def main(): # type: () -> None args = parse_args() if os.path.isfile(args.bot): bot_path = os.path.abspath(args.bot) bot_name = os.path.splitext(os.path.basename(bot_path))[0] else: bot_path = os.path.abspath( os.path.join(current_dir, 'bots', args.bot, args.bot + '.py')) bot_name = args.bot bot_dir = os.path.dirname(bot_path) if args.provision: provision_bot(os.path.dirname(bot_path), args.force) lib_module = import_module_from_source(bot_path, bot_name) message = {'content': args.message, 'sender_email': '*****@*****.**'} message_handler = lib_module.handler_class() with patch('zulip.Client') as mock_client: mock_bot_handler = ExternalBotHandler(mock_client, bot_dir) mock_bot_handler.send_reply = MagicMock() mock_bot_handler.send_message = MagicMock() mock_bot_handler.update_message = MagicMock() if hasattr(message_handler, 'initialize') and callable( message_handler.initialize): message_handler.initialize(mock_bot_handler) message_handler.handle_message(message=message, bot_handler=mock_bot_handler, state_handler=StateHandler()) print("On sending {} bot the message \"{}\"".format( bot_name, args.message)) # send_reply and send_message have slightly arguments; the # following takes that into account. # send_reply(original_message, response) # send_message(response_message) if mock_bot_handler.send_reply.called: output_message = list(mock_bot_handler.send_reply.call_args)[0][1] elif mock_bot_handler.send_message.called: output_message = list( mock_bot_handler.send_message.call_args)[0][0] elif mock_bot_handler.update_message.called: output_message = list( mock_bot_handler.update_message.call_args)[0][0]['content'] print( "the bot updates a message with the following text (in quotes):\n\"{}\"" .format(output_message)) sys.exit() else: print("the bot sent no reply.") sys.exit() print( "the bot gives the following output message (in quotes):\n\"{}\"". format(output_message))
def test_react(self): client = FakeClient() handler = ExternalBotHandler( client = client, root_dir=None, bot_details=None, bot_config_file=None ) emoji_name = 'wave' message = {'id': 10} expected = {'message_id': message['id'], 'emoji_name': 'wave', 'reaction_type': 'unicode_emoji'} client.add_reaction = MagicMock() handler.react(message, emoji_name) client.add_reaction.assert_called_once_with(dict(expected))
def test_react(self): client = FakeClient() handler = ExternalBotHandler( client=client, root_dir=None, bot_details=None, bot_config_file=None ) emoji_name = "wave" message = {"id": 10} expected = { "message_id": message["id"], "emoji_name": "wave", "reaction_type": "unicode_emoji", } client.add_reaction = MagicMock() handler.react(message, emoji_name) client.add_reaction.assert_called_once_with(dict(expected))
def load_bot_handlers(): # type: () -> Any for bot in available_bots: client = Client(email=bots_config[bot]["email"], api_key=bots_config[bot]["key"], site=bots_config[bot]["site"]) try: bot_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'bots', bot) # TODO: Figure out how to pass in third party config info. bot_handler = ExternalBotHandler( client, bot_dir, bot_details={}, bot_config_file=None ) bot_handlers[bot] = bot_handler lib_module = get_bot_lib_module(bot) message_handler = lib_module.handler_class() if hasattr(message_handler, 'validate_config'): config_data = bot_handlers[bot].get_config_info(bot) try: lib_module.handler_class.validate_config(config_data) except ConfigValidationError as e: print("There was a problem validating your config file:\n\n{}".format(e)) sys.exit(1) if hasattr(message_handler, 'initialize'): message_handler.initialize(bot_handler=bot_handler) except SystemExit: return BadRequest("Cannot fetch user profile for bot {}, make sure you have set up the flaskbotrc " "file correctly.".format(bot))
def test_content_and_full_content(self): client = FakeClient() client.get_profile() ExternalBotHandler(client=client, root_dir=None, bot_details=None, bot_config_file=None)
def handle_bot(bot): # type: (str) -> Union[str, BadRequest] lib_module = get_bot_lib_module(bot) if lib_module is None: return BadRequest( "Can't find the configuration or Bot Handler code for bot {}. " "Make sure that the `zulip_bots` package is installed, and " "that your flaskbotrc is set up correctly".format(bot)) client = Client(email=bots_config[bot]["email"], api_key=bots_config[bot]["key"], site=bots_config[bot]["site"]) try: bot_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'bots', bot) restricted_client = ExternalBotHandler(client, bot_dir) except SystemExit: return BadRequest( "Cannot fetch user profile for bot {}, make sure you have set up the flaskbotrc " "file correctly.".format(bot)) message_handler = lib_module.handler_class() # TODO: Handle stateful bots properly. state_handler = StateHandler() event = request.get_json(force=True) message_handler.handle_message(message=event["message"], bot_handler=restricted_client, state_handler=state_handler) return json.dumps("")
def _create_client_and_handler_for_file_upload(self): client = FakeClient() client.upload_file = MagicMock() handler = ExternalBotHandler( client=client, root_dir=None, bot_details=None, bot_config_file=None ) return client, handler
def test_content_and_full_content(self): client = FakeClient() profile = client.get_profile() handler = ExternalBotHandler(client=client, root_dir=None, bot_details=None, bot_config_file=None) to = {'email': 'Some@User'}
def test_send_reply(self): client = FakeClient() profile = client.get_profile() handler = ExternalBotHandler( client=client, root_dir=None, bot_details=None, bot_config_file=None ) to = {'id': 43} expected = [({'type': 'private', 'display_recipient': [to]}, {'type': 'private', 'to': [to['id']]}, None), ({'type': 'private', 'display_recipient': [to, profile]}, {'type': 'private', 'to': [to['id'], profile['id']]}, 'widget_content'), ({'type': 'stream', 'display_recipient': 'Stream name', 'subject': 'Topic'}, {'type': 'stream', 'to': 'Stream name', 'subject': 'Topic'}, 'test widget')] response_text = "Response" for test in expected: client.send_message = MagicMock() handler.send_reply(test[0], response_text, test[2]) client.send_message.assert_called_once_with(dict( test[1], content=response_text, widget_content=test[2]))
def test_send_reply(self): client = FakeClient() profile = client.get_profile() handler = ExternalBotHandler( client=client, root_dir=None, bot_details=None, bot_config_file=None ) to = {'email': 'Some@User'} expected = [({'type': 'private', 'display_recipient': [to]}, {'type': 'private', 'to': [to['email']]}, None), ({'type': 'private', 'display_recipient': [to, profile]}, {'type': 'private', 'to': [to['email']]}, 'widget_content'), ({'type': 'stream', 'display_recipient': 'Stream name', 'subject': 'Topic'}, {'type': 'stream', 'to': 'Stream name', 'subject': 'Topic'}, 'test widget')] response_text = "Response" for test in expected: client.send_message = MagicMock() handler.send_reply(test[0], response_text, test[2]) client.send_message.assert_called_once_with(dict( test[1], content=response_text, widget_content=test[2]))
def test_extract_query_without_mention(self): client = FakeClient() handler = ExternalBotHandler( client=client, root_dir=None, bot_details=None, bot_config_file=None ) message = {"content": "@**Alice** Hello World"} self.assertEqual(extract_query_without_mention(message, handler), "Hello World") message = {"content": "@**Alice|alice** Hello World"} self.assertEqual(extract_query_without_mention(message, handler), "Hello World") message = {"content": "@**Alice Renamed|alice** Hello World"} self.assertEqual(extract_query_without_mention(message, handler), "Hello World") message = {"content": "Not at start @**Alice|alice** Hello World"} self.assertEqual(extract_query_without_mention(message, handler), None)
def load_bot_handlers(): # type: () -> Any for bot in available_bots: client = Client(email=bots_config[bot]["email"], api_key=bots_config[bot]["key"], site=bots_config[bot]["site"]) try: bot_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'bots', bot) bot_handlers[bot] = ExternalBotHandler(client, bot_dir) except SystemExit: return BadRequest("Cannot fetch user profile for bot {}, make sure you have set up the flaskbotrc " "file correctly.".format(bot))
def test_is_private_message_but_not_group_pm(self): client = FakeClient() handler = ExternalBotHandler( client=client, root_dir=None, bot_details=None, bot_config_file=None ) message = {} message["display_recipient"] = "some stream" message["type"] = "stream" self.assertFalse(is_private_message_but_not_group_pm(message, handler)) message["type"] = "private" message["display_recipient"] = [{"email": "*****@*****.**"}] message["sender_id"] = handler.user_id self.assertFalse(is_private_message_but_not_group_pm(message, handler)) message["sender_id"] = 0 # someone else self.assertTrue(is_private_message_but_not_group_pm(message, handler)) message["display_recipient"] = [{"email": "*****@*****.**"}, {"email": "*****@*****.**"}] self.assertFalse(is_private_message_but_not_group_pm(message, handler))
def load_bot_handlers( available_bots: List[str], bots_config: Dict[str, Dict[str, str]], third_party_bot_conf: Optional[configparser.ConfigParser] = None, ) -> Dict[str, ExternalBotHandler]: bot_handlers = {} for bot in available_bots: client = Client(email=bots_config[bot]["email"], api_key=bots_config[bot]["key"], site=bots_config[bot]["site"]) bot_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'bots', bot) bot_handler = ExternalBotHandler( client, bot_dir, bot_details={}, bot_config_parser=third_party_bot_conf) bot_handlers[bot] = bot_handler return bot_handlers
def test_is_private_message_but_not_group_pm(self): client = FakeClient() handler = ExternalBotHandler( client=client, root_dir=None, bot_details=None, bot_config_file=None ) message = {} message['display_recipient'] = 'some stream' message['type'] = 'stream' self.assertFalse(is_private_message_but_not_group_pm(message, handler)) message['type'] = 'private' message['display_recipient'] = [{'email': '*****@*****.**'}] message['sender_id'] = handler.user_id self.assertFalse(is_private_message_but_not_group_pm(message, handler)) message['sender_id'] = 0 # someone else self.assertTrue(is_private_message_but_not_group_pm(message, handler)) message['display_recipient'] = [{'email': '*****@*****.**'}, {'email': '*****@*****.**'}] self.assertFalse(is_private_message_but_not_group_pm(message, handler))
def handle_bot(bot): # type: (str) -> Union[str, BadRequest] if bot not in available_bots: return BadRequest("requested bot service {} not supported".format(bot)) client = Client(email=bots_config[bot]["email"], api_key=bots_config[bot]["key"], site=bots_config[bot]["site"]) try: restricted_client = ExternalBotHandler(client) except SystemExit: return BadRequest( "Cannot fetch user profile for bot {}, make sure you have set up the flaskbotrc " "file correctly.".format(bot)) message_handler = bots_lib_module[bot].handler_class() # TODO: Handle stateful bots properly. state_handler = StateHandler() event = json.loads(request.data) message_handler.handle_message(message=event["message"], bot_handler=restricted_client, state_handler=state_handler) return "Success!"