def consume(self, event: Mapping[str, Any]) -> None: user_profile_id = event["user_profile_id"] user_profile = get_user_profile_by_id(user_profile_id) message: Dict[str, Any] = event["message"] # TODO: Do we actually want to allow multiple Services per bot user? services = get_bot_services(user_profile_id) for service in services: bot_handler = get_bot_handler(str(service.name)) if bot_handler is None: logging.error( "Error: User %s has bot with invalid embedded bot service %s", user_profile_id, service.name, ) continue try: if hasattr(bot_handler, "initialize"): bot_handler.initialize( self.get_bot_api_client(user_profile)) if event["trigger"] == "mention": message["content"] = extract_query_without_mention( message=message, client=cast(ExternalBotHandler, self.get_bot_api_client(user_profile)), ) assert message["content"] is not None bot_handler.handle_message( message=message, bot_handler=self.get_bot_api_client(user_profile), ) except EmbeddedBotQuitException as e: logging.warning(str(e))
def do_update_outgoing_webhook_service( bot_profile: UserProfile, service_interface: int, service_payload_url: str ) -> None: # TODO: First service is chosen because currently one bot can only have one service. # Update this once multiple services are supported. service = get_bot_services(bot_profile.id)[0] service.base_url = service_payload_url service.interface = service_interface service.save() send_event( bot_profile.realm, dict( type="realm_bot", op="update", bot=dict( user_id=bot_profile.id, services=[ dict( base_url=service.base_url, interface=service.interface, token=service.token ) ], ), ), bot_owner_user_ids(bot_profile), )
def test_create_outgoing_webhook_bot(self, **extras: Any) -> None: self.login(self.example_email('hamlet')) bot_info = { 'full_name': 'Outgoing Webhook test bot', 'short_name': 'outgoingservicebot', 'bot_type': UserProfile.OUTGOING_WEBHOOK_BOT, 'payload_url': ujson.dumps('http://127.0.0.1:5002/bots/followup'), } bot_info.update(extras) result = self.client_post("/json/bots", bot_info) self.assert_json_success(result) bot_email = "*****@*****.**" bot_realm = get_realm('zulip') bot = get_user(bot_email, bot_realm) services = get_bot_services(bot.id) service = services[0] self.assertEqual(len(services), 1) self.assertEqual(service.name, "outgoingservicebot") self.assertEqual(service.base_url, "http://127.0.0.1:5002/bots/followup") self.assertEqual(service.user_profile, bot) # invalid URL test case. bot_info['payload_url'] = ujson.dumps('http://127.0.0.:5002/bots/followup') result = self.client_post("/json/bots", bot_info) self.assert_json_error(result, "Enter a valid URL.")
def test_create_outgoing_webhook_bot(self, **extras: Any) -> None: self.login(self.example_email('hamlet')) bot_info = { 'full_name': 'Outgoing Webhook test bot', 'short_name': 'outgoingservicebot', 'bot_type': UserProfile.OUTGOING_WEBHOOK_BOT, 'payload_url': ujson.dumps('http://127.0.0.1:5002/bots/followup'), } bot_info.update(extras) result = self.client_post("/json/bots", bot_info) self.assert_json_success(result) bot_email = "*****@*****.**" bot_realm = get_realm('zulip') bot = get_user(bot_email, bot_realm) services = get_bot_services(bot.id) service = services[0] self.assertEqual(len(services), 1) self.assertEqual(service.name, "outgoingservicebot") self.assertEqual(service.base_url, "http://127.0.0.1:5002/bots/followup") self.assertEqual(service.user_profile, bot) # invalid URL test case. bot_info['payload_url'] = ujson.dumps( 'http://127.0.0.:5002/bots/followup') result = self.client_post("/json/bots", bot_info) self.assert_json_error(result, "Enter a valid URL.")
def consume(self, event): # type: (Mapping[str, Any]) -> None user_profile_id = event['user_profile_id'] user_profile = get_user_profile_by_id(user_profile_id) message = cast(Dict[str, Any], event['message']) # TODO: Do we actually want to allow multiple Services per bot user? services = get_bot_services(user_profile_id) for service in services: bot_handler = get_bot_handler(str(service.name)) if bot_handler is None: logging.error( "Error: User %s has bot with invalid embedded bot service %s" % (user_profile_id, service.name)) continue if event['trigger'] == 'mention': message['content'] = extract_query_without_mention( message=message, client=self.get_bot_api_client(user_profile), ) if message['content'] is None: return bot_handler.handle_message( message=message, bot_handler=self.get_bot_api_client(user_profile))
def get_service_dicts_for_bot(user_profile_id: int) -> List[Dict[str, Any]]: user_profile = get_user_profile_by_id(user_profile_id) services = get_bot_services(user_profile_id) service_dicts: List[Dict[str, Any]] = [] if user_profile.bot_type == UserProfile.OUTGOING_WEBHOOK_BOT: service_dicts = [ { "base_url": service.base_url, "interface": service.interface, "token": service.token, } for service in services ] elif user_profile.bot_type == UserProfile.EMBEDDED_BOT: try: service_dicts = [ { "config_data": get_bot_config(user_profile), "service_name": services[0].name, } ] # A ConfigError just means that there are no config entries for user_profile. except ConfigError: pass return service_dicts
def consume(self, event: Mapping[str, Any]) -> None: user_profile_id = event['user_profile_id'] user_profile = get_user_profile_by_id(user_profile_id) message = cast(Dict[str, Any], event['message']) # TODO: Do we actually want to allow multiple Services per bot user? services = get_bot_services(user_profile_id) for service in services: bot_handler = get_bot_handler(str(service.name)) if bot_handler is None: logging.error("Error: User %s has bot with invalid embedded bot service %s" % ( user_profile_id, service.name)) continue try: if hasattr(bot_handler, 'initialize'): bot_handler.initialize(self.get_bot_api_client(user_profile)) if event['trigger'] == 'mention': message['content'] = extract_query_without_mention( message=message, client=self.get_bot_api_client(user_profile), ) assert message['content'] is not None bot_handler.handle_message( message=message, bot_handler=self.get_bot_api_client(user_profile) ) except EmbeddedBotQuitException as e: logging.warning(str(e))
def consume(self, event: Mapping[str, Any]) -> None: user_profile_id = event['user_profile_id'] user_profile = get_user_profile_by_id(user_profile_id) message = cast(Dict[str, Any], event['message']) # TODO: Do we actually want to allow multiple Services per bot user? services = get_bot_services(user_profile_id) for service in services: bot_handler = get_bot_handler(str(service.name)) if bot_handler is None: logging.error( "Error: User %s has bot with invalid embedded bot service %s" % (user_profile_id, service.name)) continue try: if hasattr(bot_handler, 'initialize'): bot_handler.initialize( self.get_bot_api_client(user_profile)) if event['trigger'] == 'mention': message['content'] = extract_query_without_mention( message=message, client=self.get_bot_api_client(user_profile), ) assert message['content'] is not None bot_handler.handle_message( message=message, bot_handler=self.get_bot_api_client(user_profile)) except EmbeddedBotQuitException as e: logging.warning(str(e))
def consume(self, event: Dict[str, Any]) -> None: message = event["message"] event["command"] = message["content"] services = get_bot_services(event["user_profile_id"]) for service in services: event["service_name"] = str(service.name) service_handler = get_outgoing_webhook_service_handler(service) do_rest_call(service.base_url, event, service_handler)
def test_create_embedded_bot(self, **extras: Any) -> None: self.login(self.example_email('hamlet')) # Test to create embedded bot with correct service_name bot_config_info = {'key': 'value'} bot_info = { 'full_name': 'Embedded test bot', 'short_name': 'embeddedservicebot', 'bot_type': UserProfile.EMBEDDED_BOT, 'service_name': 'followup', 'config_data': ujson.dumps(bot_config_info), } bot_info.update(extras) with self.settings(EMBEDDED_BOTS_ENABLED=False): result = self.client_post("/json/bots", bot_info) self.assert_json_error(result, 'Embedded bots are not enabled.') result = self.client_post("/json/bots", bot_info) self.assert_json_success(result) bot_email = "*****@*****.**" bot_realm = get_realm('zulip') bot = get_user(bot_email, bot_realm) services = get_bot_services(bot.id) service = services[0] bot_config = get_bot_config(bot) self.assertEqual(bot_config, bot_config_info) self.assertEqual(len(services), 1) self.assertEqual(service.name, "followup") self.assertEqual(service.user_profile, bot) # Test to create embedded bot with incorrect service_name bot_info = { 'full_name': 'Embedded test bot', 'short_name': 'embeddedservicebot', 'bot_type': UserProfile.EMBEDDED_BOT, 'service_name': 'not_existing_service', } bot_info.update(extras) result = self.client_post("/json/bots", bot_info) self.assert_json_error(result, 'Invalid embedded bot name.') # Test to create embedded bot with an invalid config value malformatted_bot_config_info = {'foo': ['bar', 'baz']} bot_info = { 'full_name': 'Embedded test bot', 'short_name': 'embeddedservicebot2', 'bot_type': UserProfile.EMBEDDED_BOT, 'service_name': 'followup', 'config_data': ujson.dumps(malformatted_bot_config_info) } bot_info.update(extras) result = self.client_post("/json/bots", bot_info) self.assert_json_error( result, 'config_data contains a value that is not a string')
def consume(self, event: Mapping[str, Any]) -> None: message = event['message'] dup_event = cast(Dict[str, Any], event) dup_event['command'] = message['content'] services = get_bot_services(event['user_profile_id']) for service in services: dup_event['service_name'] = str(service.name) service_handler = get_outgoing_webhook_service_handler(service) rest_operation, request_data = service_handler.process_event(dup_event) do_rest_call(rest_operation, request_data, dup_event, service_handler)
def test_create_embedded_bot(self, **extras: Any) -> None: self.login(self.example_email('hamlet')) # Test to create embedded bot with correct service_name bot_config_info = {'key': 'value'} bot_info = { 'full_name': 'Embedded test bot', 'short_name': 'embeddedservicebot', 'bot_type': UserProfile.EMBEDDED_BOT, 'service_name': 'followup', 'config_data': ujson.dumps(bot_config_info), } bot_info.update(extras) with self.settings(EMBEDDED_BOTS_ENABLED=False): result = self.client_post("/json/bots", bot_info) self.assert_json_error(result, 'Embedded bots are not enabled.') result = self.client_post("/json/bots", bot_info) self.assert_json_success(result) bot_email = "*****@*****.**" bot_realm = get_realm('zulip') bot = get_user(bot_email, bot_realm) services = get_bot_services(bot.id) service = services[0] bot_config = get_bot_config(bot) self.assertEqual(bot_config, bot_config_info) self.assertEqual(len(services), 1) self.assertEqual(service.name, "followup") self.assertEqual(service.user_profile, bot) # Test to create embedded bot with incorrect service_name bot_info = { 'full_name': 'Embedded test bot', 'short_name': 'embeddedservicebot', 'bot_type': UserProfile.EMBEDDED_BOT, 'service_name': 'not_existing_service', } bot_info.update(extras) result = self.client_post("/json/bots", bot_info) self.assert_json_error(result, 'Invalid embedded bot name.') # Test to create embedded bot with an invalid config value malformatted_bot_config_info = {'foo': ['bar', 'baz']} bot_info = { 'full_name': 'Embedded test bot', 'short_name': 'embeddedservicebot2', 'bot_type': UserProfile.EMBEDDED_BOT, 'service_name': 'followup', 'config_data': ujson.dumps(malformatted_bot_config_info) } bot_info.update(extras) result = self.client_post("/json/bots", bot_info) self.assert_json_error(result, 'config_data contains a value that is not a string')
def consume(self, event: Mapping[str, Any]) -> None: message = event['message'] dup_event = cast(Dict[str, Any], event) dup_event['command'] = message['content'] services = get_bot_services(event['user_profile_id']) for service in services: dup_event['service_name'] = str(service.name) service_handler = get_outgoing_webhook_service_handler(service) rest_operation, request_data = service_handler.process_event(dup_event) do_rest_call(rest_operation, request_data, dup_event, service_handler)
def consume(self, event: Dict[str, Any]) -> None: message = event['message'] event['command'] = message['content'] services = get_bot_services(event['user_profile_id']) for service in services: event['service_name'] = str(service.name) service_handler = get_outgoing_webhook_service_handler(service) request_data = service_handler.build_bot_request(event) if request_data: do_rest_call(service.base_url, request_data, event, service_handler)
def consume(self, event): # type: (Mapping[str, Any]) -> None user_profile_id = event['user_profile_id'] user_profile = get_user_profile_by_id(user_profile_id) message = cast(Dict[str, Any], event['message']) # TODO: Do we actually want to allow multiple Services per bot user? services = get_bot_services(user_profile_id) for service in services: self.get_bot_handler(service).handle_message( message=message, client=self.get_bot_api_client(user_profile), state_handler=self.get_state_handler())
def consume(self, event): # type: (Mapping[str, Any]) -> None user_profile_id = event['user_profile_id'] user_profile = get_user_profile_by_id(user_profile_id) message = cast(Dict[str, Any], event['message']) self.remove_leading_mention_if_necessary(message, user_profile) # TODO: Do we actually want to allow multiple Services per bot user? services = get_bot_services(user_profile_id) for service in services: self.get_bot_handler(service).handle_message( message=message, client=self.get_bot_api_client(user_profile), state_handler=self.get_state_handler())
def consume(self, event): # type: (Mapping[str, Any]) -> None message = event['message'] services = get_bot_services(event['user_profile_id']) rest_operation = {'method': 'POST', 'relative_url_path': '', 'request_kwargs': {}, 'base_url': ''} dup_event = cast(Dict[str, Any], event) dup_event['command'] = message['content'] for service in services: rest_operation['base_url'] = str(service.base_url) dup_event['service_name'] = str(service.name) do_rest_call(rest_operation, dup_event)
def consume(self, event): # type: (Mapping[str, Any]) -> None user_profile_id = event['user_profile_id'] user_profile = get_user_profile_by_id(user_profile_id) message = cast(Dict[str, Any], event['message']) # TODO: Do we actually want to allow multiple Services per bot user? services = get_bot_services(user_profile_id) for service in services: bot_handler = get_bot_handler(str(service.name)) if bot_handler is None: logging.error("Error: User %s has bot with invalid embedded bot service %s" % (user_profile_id, service.name)) continue bot_handler.handle_message( message=message, bot_handler=self.get_bot_api_client(user_profile), state_handler=self.get_state_handler())
def test_create_embedded_bot(self, **extras: Any) -> None: bot_config_info = {'key': 'value'} self.create_test_bot(short_name='embeddedservicebot', user_profile=self.example_user("hamlet"), bot_type=UserProfile.EMBEDDED_BOT, service_name='followup', config_data=ujson.dumps(bot_config_info), **extras) bot_email = "*****@*****.**" bot_realm = get_realm('zulip') bot = get_user(bot_email, bot_realm) services = get_bot_services(bot.id) service = services[0] bot_config = get_bot_config(bot) self.assertEqual(bot_config, bot_config_info) self.assertEqual(len(services), 1) self.assertEqual(service.name, "followup") self.assertEqual(service.user_profile, bot)
def consume(self, event): # type: (Mapping[str, Any]) -> None user_profile_id = event['user_profile_id'] user_profile = get_user_profile_by_id(user_profile_id) message = cast(Dict[str, Any], event['message']) # TODO: Do we actually want to allow multiple Services per bot user? services = get_bot_services(user_profile_id) for service in services: bot_handler = get_bot_handler(str(service.name)) if bot_handler is None: logging.error("Error: User %s has bot with invalid embedded bot service %s" % (user_profile_id, service.name)) continue bot_handler.handle_message( message=message, bot_handler=self.get_bot_api_client(user_profile), state_handler=self.get_state_handler())
def test_create_embedded_bot(self, **extras): # type: (**Any) -> None self.login(self.example_email('hamlet')) # Test to create embedded bot with correct service_name bot_info = { 'full_name': 'Embedded test bot', 'short_name': 'embeddedservicebot', 'bot_type': UserProfile.EMBEDDED_BOT, 'service_name': 'converter', } bot_info.update(extras) with self.settings(EMBEDDED_BOTS_ENABLED=False): result = self.client_post("/json/bots", bot_info) self.assert_json_error(result, 'Embedded bots are not enabled.') result = self.client_post("/json/bots", bot_info) self.assert_json_success(result) bot_email = "*****@*****.**" bot_realm = get_realm('zulip') bot = get_user(bot_email, bot_realm) services = get_bot_services(bot.id) service = services[0] self.assertEqual(len(services), 1) self.assertEqual(service.name, "converter") self.assertEqual(service.user_profile, bot) # Test to create embedded bot with incorrect service_name bot_info = { 'full_name': 'Embedded test bot', 'short_name': 'embeddedservicebot', 'bot_type': UserProfile.EMBEDDED_BOT, 'service_name': 'not_existing_service', } bot_info.update(extras) result = self.client_post("/json/bots", bot_info) self.assert_json_error(result, 'Invalid embedded bot name.')