Exemple #1
0
    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))
Exemple #2
0
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),
    )
Exemple #3
0
    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.")
Exemple #4
0
    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.")
Exemple #5
0
    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))
Exemple #6
0
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
Exemple #7
0
    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))
Exemple #8
0
    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))
Exemple #9
0
    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)
Exemple #10
0
    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')
Exemple #11
0
    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)
Exemple #12
0
    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')
Exemple #13
0
    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)
Exemple #14
0
    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)
Exemple #15
0
    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())
Exemple #16
0
    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())
Exemple #17
0
    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)
Exemple #18
0
    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())
Exemple #19
0
 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)
Exemple #20
0
    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())
Exemple #21
0
    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.')