bot server: Raise BadRequest when bot code can't be imported.

This adds support to check and raise a BadRequest when either the
configuration of bot couldn't be found or the BotHandler code of bot
couldn't be fetched. There can be cases where flaskbotrc contains config
details of a bot, but the user hasn't added it's handler class code. This
fixes server to handle such cases, by reporting it to user.
This also fixes the response of bot server to make it possible to skip
the response message.
This commit is contained in:
vaibhav 2017-07-16 15:29:21 +05:30 committed by Tim Abbott
parent a1429f36b2
commit c4876dddae
2 changed files with 20 additions and 12 deletions

View file

@ -35,10 +35,9 @@ class BotServerTests(BotServerTestCase):
check_success=True) check_success=True)
assert mock_ExternalBotHandler.called assert mock_ExternalBotHandler.called
def test_bot_not_supported(self): def test_bot_module_not_exists(self):
# type: () -> None # type: () -> None
available_bots = ['testbot'] self.assert_bot_server_response(bots_lib_module={},
self.assert_bot_server_response(available_bots=available_bots,
payload_url="/bots/not_supported_bot", payload_url="/bots/not_supported_bot",
check_success=False) check_success=False)

View file

@ -34,20 +34,29 @@ def load_lib_modules():
# type: () -> None # type: () -> None
for bot in available_bots: for bot in available_bots:
try: try:
module_name = 'zulip_bots.{bot}.{bot}'.format(bot=bot) module_name = 'zulip_bots.bots.{bot}.{bot}'.format(bot=bot)
bots_lib_module[bot] = import_module(module_name) lib_module = import_module(module_name)
bots_lib_module[bot] = lib_module
except ImportError: except ImportError:
print("\n Import Error: Bot \"{}\" doesn't exists. Please make sure you have set up the flaskbotrc " print("\n Import Error: Bot \"{}\" doesn't exists. Please make sure you have set up the flaskbotrc "
"file correctly.\n".format(bot)) "file correctly.\n".format(bot))
sys.exit(1)
def get_bot_lib_module(bot):
# type: (str) -> Any
if bot in bots_lib_module.keys():
return bots_lib_module[bot]
return None
app = Flask(__name__) app = Flask(__name__)
@app.route('/bots/<bot>', methods=['POST']) @app.route('/bots/<bot>', methods=['POST'])
def handle_bot(bot): def handle_bot(bot):
# type: (str) -> Union[str, BadRequest] # type: (str) -> Union[str, BadRequest]
if bot not in available_bots: lib_module = get_bot_lib_module(bot)
return BadRequest("requested bot service {} not supported".format(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!".format(bot))
client = Client(email=bots_config[bot]["email"], client = Client(email=bots_config[bot]["email"],
api_key=bots_config[bot]["key"], api_key=bots_config[bot]["key"],
site=bots_config[bot]["site"]) site=bots_config[bot]["site"])
@ -58,7 +67,8 @@ def handle_bot(bot):
except SystemExit: except SystemExit:
return BadRequest("Cannot fetch user profile for bot {}, make sure you have set up the flaskbotrc " return BadRequest("Cannot fetch user profile for bot {}, make sure you have set up the flaskbotrc "
"file correctly.".format(bot)) "file correctly.".format(bot))
message_handler = bots_lib_module[bot].handler_class()
message_handler = lib_module.handler_class()
# TODO: Handle stateful bots properly. # TODO: Handle stateful bots properly.
state_handler = StateHandler() state_handler = StateHandler()
@ -67,7 +77,7 @@ def handle_bot(bot):
message_handler.handle_message(message=event["message"], message_handler.handle_message(message=event["message"],
bot_handler=restricted_client, bot_handler=restricted_client,
state_handler=state_handler) state_handler=state_handler)
return "Success!" return json.dumps("")
def parse_args(): def parse_args():
# type: () -> Tuple[Any, Any] # type: () -> Tuple[Any, Any]
@ -110,8 +120,7 @@ def main():
global available_bots global available_bots
available_bots = list(bots_config.keys()) available_bots = list(bots_config.keys())
load_lib_modules() load_lib_modules()
app.run(host=options.hostname, port=int(options.port), debug=True)
app.run(host=options.hostname, port=options.port, debug=True)
if __name__ == '__main__': if __name__ == '__main__':
main() main()