def test_conversation_handler(self, dp, bot, user1, user2):
        handler = ConversationHandler(entry_points=self.entry_points, states=self.states,
                                      fallbacks=self.fallbacks)
        dp.add_handler(handler)

        # User one, starts the state machine.
        message = Message(0, user1, None, self.group, text='/start', bot=bot)
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.THIRSTY

        # The user is thirsty and wants to brew coffee.
        message.text = '/brew'
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.BREWING

        # Lets see if an invalid command makes sure, no state is changed.
        message.text = '/nothing'
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.BREWING

        # Lets see if the state machine still works by pouring coffee.
        message.text = '/pourCoffee'
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.DRINKING

        # Let's now verify that for another user, who did not start yet,
        # the state has not been changed.
        message.from_user = user2
        dp.process_update(Update(update_id=0, message=message))
        with pytest.raises(KeyError):
            self.current_state[user2.id]
    def test_CommandHandler_commandList(self):
        self._setup_updater('', messages=0)
        handler = CommandHandler(['foo', 'bar', 'spameggs'], self.telegramHandlerTest)
        self.updater.dispatcher.add_handler(handler)
        bot = self.updater.bot
        user = User(0, 'TestUser')
        queue = self.updater.start_polling(0.01)

        message = Message(0, user, 0, None, text='/foo', bot=bot)
        queue.put(Update(0, message=message))
        sleep(.1)
        self.assertEqual(self.received_message, '/foo')

        message.text = '/bar'
        queue.put(Update(1, message=message))
        sleep(.1)
        self.assertEqual(self.received_message, '/bar')

        message.text = '/spameggs'
        queue.put(Update(2, message=message))
        sleep(.1)
        self.assertEqual(self.received_message, '/spameggs')

        self.reset()
        message.text = '/not_in_list'
        queue.put(Update(3, message=message))
        sleep(.1)
        self.assertTrue(self.received_message is None)
 def test_parse_caption_entity(self):
     caption = (b'\\U0001f469\\u200d\\U0001f469\\u200d\\U0001f467'
                b'\\u200d\\U0001f467\\U0001f431http://google.com').decode('unicode-escape')
     entity = MessageEntity(type=MessageEntity.URL, offset=13, length=17)
     message = Message(1, self.from_user, self.date, self.chat, caption=caption,
                       caption_entities=[entity])
     assert message.parse_caption_entity(entity) == 'http://google.com'
    def test_webhook_no_ssl(self):
        print("Testing Webhook without SSL")
        bot = MockBot("", messages=0)
        self.updater.bot = bot
        d = self.updater.dispatcher
        d.addTelegramMessageHandler(self.telegramHandlerTest)

        # Select random port for travis
        port = randrange(1024, 49152)
        self.updater.start_webhook("127.0.0.1", port)
        sleep(0.5)

        # Now, we send an update to the server via urlopen
        message = Message(1, User(1, "Tester 2"), datetime.now(), GroupChat(1, "Test Group 2"))

        message.text = "Webhook Test 2"
        update = Update(1)
        update.message = message

        try:
            payload = bytes(update.to_json(), encoding="utf-8")
        except TypeError:
            payload = bytes(update.to_json())

        header = {"content-type": "application/json", "content-length": str(len(payload))}

        r = Request("http://127.0.0.1:%d/" % port, data=payload, headers=header)

        urlopen(r)
        sleep(1)
        self.assertEqual(self.received_message, "Webhook Test 2")
    def de_json(data, bot):
        """
        Args:
            data (dict):
            bot (telegram.Bot):

        Returns:
            telegram.Update:
        """
        if not data:
            return None

        data = super(Update, Update).de_json(data, bot)

        data['message'] = Message.de_json(data.get('message'), bot)
        data['edited_message'] = Message.de_json(data.get('edited_message'), bot)
        data['inline_query'] = InlineQuery.de_json(data.get('inline_query'), bot)
        data['chosen_inline_result'] = ChosenInlineResult.de_json(
            data.get('chosen_inline_result'), bot)
        data['callback_query'] = CallbackQuery.de_json(data.get('callback_query'), bot)
        data['shipping_query'] = ShippingQuery.de_json(data.get('shipping_query'), bot)
        data['pre_checkout_query'] = PreCheckoutQuery.de_json(data.get('pre_checkout_query'), bot)
        data['channel_post'] = Message.de_json(data.get('channel_post'), bot)
        data['edited_channel_post'] = Message.de_json(data.get('edited_channel_post'), bot)

        return Update(**data)
    def test_conversation_timeout_keeps_extending(self, dp, bot, user1):
        handler = ConversationHandler(entry_points=self.entry_points, states=self.states,
                                      fallbacks=self.fallbacks, conversation_timeout=0.5)
        dp.add_handler(handler)

        # Start state machine, wait, do something, verify the timeout is extended.
        # t=0 /start (timeout=.5)
        # t=.25 /brew (timeout=.75)
        # t=.5 original timeout
        # t=.6 /pourCoffee (timeout=1.1)
        # t=.75 second timeout
        # t=1.1 actual timeout
        message = Message(0, user1, None, self.group, text='/start', bot=bot)
        dp.process_update(Update(update_id=0, message=message))
        assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY
        sleep(0.25)  # t=.25
        dp.job_queue.tick()
        assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY
        message.text = '/brew'
        dp.process_update(Update(update_id=0, message=message))
        assert handler.conversations.get((self.group.id, user1.id)) == self.BREWING
        sleep(0.35)  # t=.6
        dp.job_queue.tick()
        assert handler.conversations.get((self.group.id, user1.id)) == self.BREWING
        message.text = '/pourCoffee'
        dp.process_update(Update(update_id=0, message=message))
        assert handler.conversations.get((self.group.id, user1.id)) == self.DRINKING
        sleep(.4)  # t=1
        dp.job_queue.tick()
        assert handler.conversations.get((self.group.id, user1.id)) == self.DRINKING
        sleep(.1)  # t=1.1
        dp.job_queue.tick()
        assert handler.conversations.get((self.group.id, user1.id)) is None
    def test_conversation_handler_fallback(self, dp, bot, user1, user2):
        handler = ConversationHandler(entry_points=self.entry_points, states=self.states,
                                      fallbacks=self.fallbacks)
        dp.add_handler(handler)

        # first check if fallback will not trigger start when not started
        message = Message(0, user1, None, self.group, text='/eat', bot=bot)
        dp.process_update(Update(update_id=0, message=message))
        with pytest.raises(KeyError):
            self.current_state[user1.id]

        # User starts the state machine.
        message.text = '/start'
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.THIRSTY

        # The user is thirsty and wants to brew coffee.
        message.text = '/brew'
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.BREWING

        # Now a fallback command is issued
        message.text = '/eat'
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.THIRSTY
    def test_webhook(self):
        print('Testing Webhook')
        self._setup_updater('', messages=0)
        d = self.updater.dispatcher
        d.addTelegramMessageHandler(
            self.telegramHandlerTest)

        # Select random port for travis
        port = randrange(1024, 49152)
        self.updater.start_webhook('127.0.0.1', port,
                                   url_path='TOKEN',
                                   cert='./tests/test_updater.py',
                                   key='./tests/test_updater.py')
        sleep(0.5)
        # SSL-Wrapping will fail, so we start the server without SSL
        Thread(target=self.updater.httpd.serve_forever).start()

        # Now, we send an update to the server via urlopen
        message = Message(1, User(1, "Tester"), datetime.now(),
                          Chat(1, "group", title="Test Group"))

        message.text = "Webhook Test"
        update = Update(1)
        update.message = message

        try:
            payload = bytes(update.to_json(), encoding='utf-8')
        except TypeError:
            payload = bytes(update.to_json())

        header = {
            'content-type': 'application/json',
            'content-length': str(len(payload))
        }

        r = Request('http://127.0.0.1:%d/TOKEN' % port,
                    data=payload,
                    headers=header)

        urlopen(r)

        sleep(1)
        self.assertEqual(self.received_message, 'Webhook Test')

        print("Test other webhook server functionalities...")
        request = Request('http://localhost:%d/webookhandler.py' % port)
        response = urlopen(request)
        self.assertEqual(b'', response.read())
        self.assertEqual(200, response.code)

        request.get_method = lambda: 'HEAD'

        response = urlopen(request)
        self.assertEqual(b'', response.read())
        self.assertEqual(200, response.code)

        # Test multiple shutdown() calls
        self.updater.httpd.shutdown()
        self.updater.httpd.shutdown()
        self.assertTrue(True)
 def test_parse_entities_url_emoji(self):
     url = b'http://github.com/?unicode=\\u2713\\U0001f469'.decode('unicode-escape')
     text = 'some url'
     link_entity = MessageEntity(type=MessageEntity.URL, offset=0, length=8, url=url)
     message = Message(1, self.from_user, self.date, self.chat,
                       text=text, entities=[link_entity])
     assert message.parse_entities() == {link_entity: text}
     assert next(iter(message.parse_entities())).url == url
 def test_parse_caption_entities(self):
     text = (b'\\U0001f469\\u200d\\U0001f469\\u200d\\U0001f467'
             b'\\u200d\\U0001f467\\U0001f431http://google.com').decode('unicode-escape')
     entity = MessageEntity(type=MessageEntity.URL, offset=13, length=17)
     entity_2 = MessageEntity(type=MessageEntity.BOLD, offset=13, length=1)
     message = Message(1, self.from_user, self.date, self.chat,
                       caption=text, caption_entities=[entity_2, entity])
     assert message.parse_caption_entities(MessageEntity.URL) == {entity: 'http://google.com'}
     assert message.parse_caption_entities() == {entity: 'http://google.com', entity_2: 'h'}
    def mockUpdate(self, text):
        message = Message(0, None, None, None)
        message.text = text
        update = Update(0)

        if self.edited:
            update.edited_message = message
        else:
            update.message = message

        return update
    def mock_update(self, text):
        message = Message(0, User(0, 'Testuser'), None, Chat(0, Chat.GROUP), bot=self)
        message.text = text
        update = Update(0)

        if self.edited:
            update.edited_message = message
        else:
            update.message = message

        return update
    def test_webhook(self):
        print("Testing Webhook")
        bot = MockBot("", messages=0)
        self.updater.bot = bot
        d = self.updater.dispatcher
        d.addTelegramMessageHandler(self.telegramHandlerTest)

        # Select random port for travis
        port = randrange(1024, 49152)
        self.updater.start_webhook(
            "127.0.0.1", port, url_path="TOKEN", cert="./tests/test_updater.py", key="./tests/test_updater.py"
        )
        sleep(0.5)
        # SSL-Wrapping will fail, so we start the server without SSL
        Thread(target=self.updater.httpd.serve_forever).start()

        # Now, we send an update to the server via urlopen
        message = Message(1, User(1, "Tester"), datetime.now(), GroupChat(1, "Test Group"))

        message.text = "Webhook Test"
        update = Update(1)
        update.message = message

        try:
            payload = bytes(update.to_json(), encoding="utf-8")
        except TypeError:
            payload = bytes(update.to_json())

        header = {"content-type": "application/json", "content-length": str(len(payload))}

        r = Request("http://127.0.0.1:%d/TOKEN" % port, data=payload, headers=header)

        urlopen(r)

        sleep(1)
        self.assertEqual(self.received_message, "Webhook Test")

        print("Test other webhook server functionalities...")
        request = Request("http://localhost:%d/webookhandler.py" % port)
        response = urlopen(request)
        self.assertEqual(b"", response.read())
        self.assertEqual(200, response.code)

        request.get_method = lambda: "HEAD"

        response = urlopen(request)
        self.assertEqual(b"", response.read())
        self.assertEqual(200, response.code)

        # Test multiple shutdown() calls
        self.updater.httpd.shutdown()
        self.updater.httpd.shutdown()
        self.assertTrue(True)
    def test_webhook(self):
        self._setup_updater('', messages=0)
        d = self.updater.dispatcher
        handler = MessageHandler([], self.telegramHandlerTest)
        d.addHandler(handler)

        ip = '127.0.0.1'
        port = randrange(1024, 49152)  # Select random port for travis
        self.updater.start_webhook(ip,
                                   port,
                                   url_path='TOKEN',
                                   cert='./tests/test_updater.py',
                                   key='./tests/test_updater.py',
                                   webhook_url=None)
        sleep(0.5)
        # SSL-Wrapping will fail, so we start the server without SSL
        Thread(target=self.updater.httpd.serve_forever).start()

        # Now, we send an update to the server via urlopen
        message = Message(1,
                          User(1, "Tester"),
                          datetime.now(),
                          Chat(1, "group", title="Test Group"))

        message.text = "Webhook Test"
        update = Update(1)
        update.message = message

        self._send_webhook_msg(ip, port, update.to_json(), 'TOKEN')

        sleep(1)
        self.assertEqual(self.received_message, 'Webhook Test')

        print("Test other webhook server functionalities...")
        response = self._send_webhook_msg(ip, port, None, 'webookhandler.py')
        self.assertEqual(b'', response.read())
        self.assertEqual(200, response.code)

        response = self._send_webhook_msg(
            ip, port,
            None, 'webookhandler.py',
            get_method=lambda: 'HEAD')

        self.assertEqual(b'', response.read())
        self.assertEqual(200, response.code)

        # Test multiple shutdown() calls
        self.updater.httpd.shutdown()
        self.updater.httpd.shutdown()
        self.assertTrue(True)
Beispiel #15
0
        def decorator(self, *args, **kwargs):
            """
            decorator
            """
            url, data = func(self, *args, **kwargs)

            if not data.get('chat_id'):
                raise TelegramError('Invalid chat_id')

            if kwargs.get('reply_to_message_id'):
                reply_to_message_id = kwargs.get('reply_to_message_id')
                data['reply_to_message_id'] = reply_to_message_id

            if kwargs.get('reply_markup'):
                reply_markup = kwargs.get('reply_markup')
                if isinstance(reply_markup, ReplyMarkup):
                    data['reply_markup'] = reply_markup.to_json()
                else:
                    data['reply_markup'] = reply_markup

            result = request.post(url, data)

            if result is True:
                return result

            return Message.de_json(result)
Beispiel #16
0
    def forwardMessage(self, chat_id, from_chat_id, message_id):
        """Use this method to forward messages of any kind.

        Args:
          chat_id:
            Unique identifier for the message recipient — User or GroupChat id.
          from_chat_id:
            Unique identifier for the chat where the original message was sent
            — User or GroupChat id.
          message_id:
            Unique message identifier.

        Returns:
          A telegram.Message instance representing the message forwarded.
        """

        url = "%s/forwardMessage" % (self.base_url)

        if not self.__auth:
            raise TelegramError({"message": "API must be authenticated."})

        data = {}
        if chat_id:
            data["chat_id"] = chat_id
        if from_chat_id:
            data["from_chat_id"] = from_chat_id
        if message_id:
            data["message_id"] = message_id

        json_data = self._requestUrl(url, "POST", data=data)
        data = self._parseAndCheckTelegram(json_data.decode())

        return Message.de_json(data)
Beispiel #17
0
    def _post_message(url, data, kwargs, timeout=None, network_delay=2.):
        """Posts a message to the telegram servers.

        Returns:
            telegram.Message

        """
        if not data.get('chat_id'):
            raise TelegramError('Invalid chat_id')

        if kwargs.get('reply_to_message_id'):
            reply_to_message_id = kwargs.get('reply_to_message_id')
            data['reply_to_message_id'] = reply_to_message_id

        if kwargs.get('reply_markup'):
            reply_markup = kwargs.get('reply_markup')
            if isinstance(reply_markup, ReplyMarkup):
                data['reply_markup'] = reply_markup.to_json()
            else:
                data['reply_markup'] = reply_markup

        result = request.post(url, data, timeout=timeout,
                              network_delay=network_delay)

        if result is True:
            return result

        return Message.de_json(result)
Beispiel #18
0
        def decorator(self, *args, **kwargs):
            url, data = func(self, *args, **kwargs)

            if kwargs.get('reply_to_message_id'):
                data['reply_to_message_id'] = \
                    kwargs.get('reply_to_message_id')

            if kwargs.get('disable_notification'):
                data['disable_notification'] = \
                    kwargs.get('disable_notification')

            if kwargs.get('reply_markup'):
                reply_markup = kwargs.get('reply_markup')
                if isinstance(reply_markup, ReplyMarkup):
                    data['reply_markup'] = reply_markup.to_json()
                else:
                    data['reply_markup'] = reply_markup

            result = request.post(url, data,
                                  timeout=kwargs.get('timeout'))

            if result is True:
                return result

            return Message.de_json(result)
Beispiel #19
0
        def decorator(self, *args, **kwargs):
            """
            decorator
            """
            url, data = func(self, *args, **kwargs)

            if not kwargs.get('chat_id'):
                raise TelegramError('Invalid chat_id.')

            if kwargs.get('reply_to_message_id'):
                reply_to_message_id = kwargs.get('reply_to_message_id')
                data['reply_to_message_id'] = reply_to_message_id

            if kwargs.get('reply_markup'):
                reply_markup = kwargs.get('reply_markup')
                if isinstance(reply_markup, ReplyMarkup):
                    data['reply_markup'] = reply_markup.to_json()
                else:
                    data['reply_markup'] = reply_markup

            json_data = Bot._requestUrl(url, 'POST', data=data)
            data = Bot._parseAndCheckTelegram(json_data)

            if data is True:
                return data

            return Message.de_json(data)
    def de_json(data):
        if not data:
            return None

        data['from_user'] = User.de_json(data.get('from'))
        data['message'] = Message.de_json(data.get('message'))

        return CallbackQuery(**data)
    def de_json(cls, data, bot):
        if not data:
            return None

        data = super(Update, cls).de_json(data, bot)

        data['message'] = Message.de_json(data.get('message'), bot)
        data['edited_message'] = Message.de_json(data.get('edited_message'), bot)
        data['inline_query'] = InlineQuery.de_json(data.get('inline_query'), bot)
        data['chosen_inline_result'] = ChosenInlineResult.de_json(
            data.get('chosen_inline_result'), bot)
        data['callback_query'] = CallbackQuery.de_json(data.get('callback_query'), bot)
        data['shipping_query'] = ShippingQuery.de_json(data.get('shipping_query'), bot)
        data['pre_checkout_query'] = PreCheckoutQuery.de_json(data.get('pre_checkout_query'), bot)
        data['channel_post'] = Message.de_json(data.get('channel_post'), bot)
        data['edited_channel_post'] = Message.de_json(data.get('edited_channel_post'), bot)

        return cls(**data)
Beispiel #22
0
    def de_json(data):
        """
        Args:
            data (dict):

        Returns:
            telegram.Update:
        """
        if not data:
            return None

        data['message'] = Message.de_json(data.get('message'))
        data['edited_message'] = Message.de_json(data.get('edited_message'))
        data['inline_query'] = InlineQuery.de_json(data.get('inline_query'))
        data['chosen_inline_result'] = ChosenInlineResult.de_json(data.get('chosen_inline_result'))
        data['callback_query'] = CallbackQuery.de_json(data.get('callback_query'))

        return Update(**data)
Beispiel #23
0
    def de_json(data):
        if 'message' in data:
            from telegram import Message
            message = Message.de_json(data['message'])
        else:
            message = None

        return Update(update_id=data.get('update_id', None),
                      message=message)
Beispiel #24
0
    def de_json(cls, data, bot):
        if not data:
            return None

        data['photo'] = ChatPhoto.de_json(data.get('photo'), bot)
        from telegram import Message
        data['pinned_message'] = Message.de_json(data.get('pinned_message'), bot)

        return cls(bot=bot, **data)
    def test_conversation_handler_end(self, caplog, dp, bot, user1):
        handler = ConversationHandler(entry_points=self.entry_points, states=self.states,
                                      fallbacks=self.fallbacks)
        dp.add_handler(handler)

        message = Message(0, user1, None, self.group, text='/start', bot=bot)
        dp.process_update(Update(update_id=0, message=message))
        message.text = '/brew'
        dp.process_update(Update(update_id=0, message=message))
        message.text = '/pourCoffee'
        dp.process_update(Update(update_id=0, message=message))
        message.text = '/end'
        with caplog.at_level(logging.ERROR):
            dp.process_update(Update(update_id=0, message=message))
        assert len(caplog.records) == 0
        assert self.current_state[user1.id] == self.END
        with pytest.raises(KeyError):
            print(handler.conversations[(self.group.id, user1.id)])
    def de_json(cls, data, bot):
        if not data:
            return None

        data = super(CallbackQuery, cls).de_json(data, bot)

        data['from_user'] = User.de_json(data.get('from'), bot)
        data['message'] = Message.de_json(data.get('message'), bot)

        return cls(bot=bot, **data)
    def test_end_on_first_message_async(self, dp, bot, user1):
        start_end_async = (lambda bot, update: dp.run_async(self.start_end, bot, update))

        handler = ConversationHandler(
            entry_points=[CommandHandler('start', start_end_async)], states={}, fallbacks=[])
        dp.add_handler(handler)

        # User starts the state machine with an async function that immediately ends the
        # conversation. Async results are resolved when the users state is queried next time.
        message = Message(0, user1, None, self.group, text='/start', bot=bot)
        dp.update_queue.put(Update(update_id=0, message=message))
        sleep(.1)
        # Assert that the Promise has been accepted as the new state
        assert len(handler.conversations) == 1

        message.text = 'resolve promise pls'
        dp.update_queue.put(Update(update_id=0, message=message))
        sleep(.1)
        # Assert that the Promise has been resolved and the conversation ended.
        assert len(handler.conversations) == 0
    def test_conversation_timeout_two_users(self, dp, bot, user1, user2):
        handler = ConversationHandler(entry_points=self.entry_points, states=self.states,
                                      fallbacks=self.fallbacks, conversation_timeout=0.5)
        dp.add_handler(handler)

        # Start state machine, do something as second user, then reach timeout
        message = Message(0, user1, None, self.group, text='/start', bot=bot)
        dp.process_update(Update(update_id=0, message=message))
        assert handler.conversations.get((self.group.id, user1.id)) == self.THIRSTY
        message.text = '/brew'
        message.from_user = user2
        dp.job_queue.tick()
        dp.process_update(Update(update_id=0, message=message))
        assert handler.conversations.get((self.group.id, user2.id)) is None
        message.text = '/start'
        dp.job_queue.tick()
        dp.process_update(Update(update_id=0, message=message))
        assert handler.conversations.get((self.group.id, user2.id)) == self.THIRSTY
        sleep(0.5)
        dp.job_queue.tick()
        assert handler.conversations.get((self.group.id, user1.id)) is None
        assert handler.conversations.get((self.group.id, user2.id)) is None
    def test_webhook_no_ssl(self):
        self._setup_updater('', messages=0)
        d = self.updater.dispatcher
        d.addTelegramMessageHandler(
            self.telegramHandlerTest)

        ip = '127.0.0.1'
        port = randrange(1024, 49152)  # Select random port for travis
        self.updater.start_webhook(ip, port)
        sleep(0.5)

        # Now, we send an update to the server via urlopen
        message = Message(1, User(1, "Tester 2"), datetime.now(),
                          Chat(1, 'group', title="Test Group 2"))

        message.text = "Webhook Test 2"
        update = Update(1)
        update.message = message

        self._send_webhook_msg(ip, port, update.to_json())
        sleep(1)
        self.assertEqual(self.received_message, 'Webhook Test 2')
Beispiel #30
0
    def sendPhoto(self,
                  chat_id,
                  photo,
                  caption=None,
                  reply_to_message_id=None,
                  reply_markup=None):
        """Use this method to send photos.

        Args:
          chat_id:
            Unique identifier for the message recipient — User or GroupChat id.
          photo:
            Photo to send. You can either pass a file_id as String to resend a
            photo that is already on the Telegram servers, or upload a new
            photo using multipart/form-data.
          caption:
            Photo caption (may also be used when resending photos by file_id).
            [Optional]
          reply_to_message_id:
            If the message is a reply, ID of the original message. [Optional]
          reply_markup:
            Additional interface options. A JSON-serialized object for a custom
            reply keyboard, instructions to hide keyboard or to force a reply
            from the user. [Optional]

        Returns:
          A telegram.Message instance representing the message posted.
        """

        url = '%s/sendPhoto' % (self.base_url)

        if not self.__auth:
            raise TelegramError({'message': "API must be authenticated."})

        data = {'chat_id': chat_id,
                'photo': photo}

        if caption:
            data['caption'] = caption
        if reply_to_message_id:
            data['reply_to_message_id'] = reply_to_message_id
        if reply_markup:
            if isinstance(reply_markup, ReplyMarkup):
                data['reply_markup'] = reply_markup.to_json()
            else:
                data['reply_markup'] = reply_markup

        json_data = self._requestUrl(url, 'POST', data=data)
        data = self._parseAndCheckTelegram(json_data.content)

        return Message.de_json(data)
    def test_all_posibilities_de_json_and_to_dict(self, bot, message_params):
        new = Message.de_json(message_params.to_dict(), bot)

        assert new.to_dict() == message_params.to_dict()
def update():
    return Update(
        0,
        Message(0, User(0, 'Testuser', False), datetime.datetime.utcnow(),
                Chat(0, 'private')))
Beispiel #33
0
def warn(user: User,
         chat: Chat,
         reason: str,
         message: Message,
         warner: User = None) -> str:

    if is_user_admin(chat, user.id):
        # message.reply_text("Damn admins, They are too far to be One Punched!")
        return ""

    if warner:
        warner_tag = mention_html(warner.id, warner.first_name)
    else:
        warner_tag = "Automated warn filter."

    limit, soft_warn = sql.get_warn_setting(chat.id)
    num_warns, reasons = sql.warn_user(user.id, chat.id, reason)
    if num_warns >= limit:
        sql.reset_warns(user.id, chat.id)
        if soft_warn:  # kick
            chat.unban_member(user.id)
            reply = f"{limit} warnings, {mention_html(user.id, user.first_name)} with a normal warn! "

        else:  # ban
            chat.kick_member(user.id)
            reply = f"{limit} warnings, {mention_html(user.id, user.first_name)} with a Serious warn "

        for warn_reason in reasons:
            reply += f"\n - {html.escape(warn_reason)}"

        message.bot.send_sticker(chat.id,
                                 BAN_STICKER)  # banhammer marie sticker
        keyboard = []
        log_reason = (
            f"<b>{html.escape(chat.title)}:</b>\n"
            f"#WARN_BAN\n"
            f"<b>Admin:</b> {warner_tag}\n"
            f"<b>User:</b> {mention_html(user.id, user.first_name)}\n"
            f"<b>Reason:</b> {reason}\n"
            f"<b>Counts:</b> <code>{num_warns}/{limit}</code>")

    else:

        keyboard = InlineKeyboardMarkup([{
            InlineKeyboardButton("Remove warn",
                                 callback_data="rm_warn({})".format(user.id))
        }])

        reply = f"{mention_html(user.id, user.first_name)} has {num_warns}/{limit} warnings... watch out!"
        if reason:
            reply += f"\nReason for last warn:\n{html.escape(reason)}"

        log_reason = (
            f"<b>{html.escape(chat.title)}:</b>\n"
            f"#WARNn<b>Admin:</b> {warner_tag}\n"
            f"<b>User:</b> {mention_html(user.id, user.first_name)}\n"
            f"<b>Reason:</b> {reason}\n"
            f"<b>Counts:</b> <code>{num_warns}/{limit}</code>")

    try:
        message.reply_text(reply,
                           reply_markup=keyboard,
                           parse_mode=ParseMode.HTML)
    except BadRequest as excp:
        if excp.message == "Reply message not found":
            # Do not reply
            message.reply_text(reply,
                               reply_markup=keyboard,
                               parse_mode=ParseMode.HTML,
                               quote=False)
        else:
            raise
    return log_reason
Beispiel #34
0
def extract_user_and_text(message: Message,
                          args: List[str]) -> (Optional[int], Optional[str]):
    prev_message = message.reply_to_message
    split_text = message.text.split(None, 1)

    if len(split_text) < 2:
        return id_from_reply(message)  # only option possible

    text_to_parse = split_text[1]

    text = ""

    entities = list(message.parse_entities([MessageEntity.TEXT_MENTION]))
    if len(entities) > 0:
        ent = entities[0]
    else:
        ent = None

    # if entity offset matches (command end/text start) then all good
    if entities and ent and ent.offset == len(
            message.text) - len(text_to_parse):
        ent = entities[0]
        user_id = ent.user.id
        text = message.text[ent.offset + ent.length:]

    elif len(args) >= 1 and args[0][0] == '@':
        user = args[0]
        user_id = get_user_id(user)
        if not user_id:
            message.reply_text("این آیدی داخل دیتا بیس من ثبت نشده! لطفا"
                               "یا روش ریپلی بزن یا یه پیام ازش فوروارد کن")
            return None, None

        else:
            user_id = user_id
            res = message.text.split(None, 2)
            if len(res) >= 3:
                text = res[2]

    elif len(args) >= 1 and args[0].isdigit():
        user_id = int(args[0])
        res = message.text.split(None, 2)
        if len(res) >= 3:
            text = res[2]

    elif prev_message:
        user_id, text = id_from_reply(message)

    else:
        return None, None

    try:
        message.bot.get_chat(user_id)
    except BadRequest as excp:
        if excp.message in ("User_id_invalid", "Chat not found"):
            message.reply_text("او ، اینجور که پیداس من ایشونو نمیشناسم   "
                               "لطفا یه پیام ازش برام فوروارد کن تا آشنا شیم  "
                               "بعد دستوری که میخوای رو اجرا میکنم")
        else:
            LOGGER.exception("Exception %s on user %s", excp.message, user_id)

        return None, None

    return user_id, text
Beispiel #35
0
    def test_addConversationHandlerPerMessage(self):
        self._setup_updater('', messages=0)
        d = self.updater.dispatcher
        user = User(first_name="Misses Test", id=123)
        second_user = User(first_name="Mister Test", id=124)

        def entry(bot, update):
            return 1

        def one(bot, update):
            return 2

        def two(bot, update):
            return ConversationHandler.END

        handler = ConversationHandler(
            entry_points=[CallbackQueryHandler(entry)],
            states={
                1: [CallbackQueryHandler(one)],
                2: [CallbackQueryHandler(two)]
            },
            fallbacks=[],
            per_message=True)
        d.add_handler(handler)
        queue = self.updater.start_polling(0.01)

        # User one, starts the state machine.
        message = Message(0,
                          user,
                          None,
                          self.group,
                          text="msg w/ inlinekeyboard",
                          bot=self.bot)

        cbq = CallbackQuery(0,
                            user,
                            None,
                            message=message,
                            data='data',
                            bot=self.bot)
        queue.put(Update(update_id=0, callback_query=cbq))
        sleep(.1)
        self.assertEquals(
            handler.conversations[(self.group.id, user.id,
                                   message.message_id)], 1)

        cbq = CallbackQuery(0,
                            user,
                            None,
                            message=message,
                            data='data',
                            bot=self.bot)
        queue.put(Update(update_id=0, callback_query=cbq))
        sleep(.1)
        self.assertEquals(
            handler.conversations[(self.group.id, user.id,
                                   message.message_id)], 2)

        # Let's now verify that for a different user in the same group, the state will not be
        # updated
        cbq = CallbackQuery(0,
                            second_user,
                            None,
                            message=message,
                            data='data',
                            bot=self.bot)
        queue.put(Update(update_id=0, callback_query=cbq))
        sleep(.1)
        self.assertEquals(
            handler.conversations[(self.group.id, user.id,
                                   message.message_id)], 2)
Beispiel #36
0
def message(bot):
    return Message(1, None, None, None, text='test message', bot=bot)
 def setUp(self):
     self.message = Message(0, User(0, "Testuser"), datetime.now(), Chat(0, 'private'))
     self.e = functools.partial(MessageEntity, offset=0, length=0)
Beispiel #38
0
def get_note_type(msg: Message):
    data_type = None
    content = None
    text = ""
    raw_text = msg.text or msg.caption
    args = raw_text.split(None, 2)  # use python's maxsplit to separate cmd and args
    note_name = args[1]

    buttons = []
    # determine what the contents of the filter are - text, image, sticker, etc
    if len(args) >= 3:
        offset = len(args[2]) - len(raw_text)  # set correct offset relative to command + notename
        text, buttons = button_markdown_parser(args[2], entities=msg.parse_entities() or msg.parse_caption_entities(),
                                               offset=offset)
        if buttons:
            data_type = Types.BUTTON_TEXT
        else:
            data_type = Types.TEXT

    elif msg.reply_to_message:
        entities = msg.reply_to_message.parse_entities()
        msgtext = msg.reply_to_message.text or msg.reply_to_message.caption
        if len(args) >= 2 and msg.reply_to_message.text:  # not caption, text
            text, buttons = button_markdown_parser(msgtext,
                                                   entities=entities)
            if buttons:
                data_type = Types.BUTTON_TEXT
            else:
                data_type = Types.TEXT

        elif msg.reply_to_message.sticker:
            content = msg.reply_to_message.sticker.file_id
            data_type = Types.STICKER

        elif msg.reply_to_message.document:
            content = msg.reply_to_message.document.file_id
            text, buttons = button_markdown_parser(msgtext, entities=entities)
            data_type = Types.DOCUMENT

        elif msg.reply_to_message.photo:
            content = msg.reply_to_message.photo[-1].file_id  # last elem = best quality
            text, buttons = button_markdown_parser(msgtext, entities=entities)
            data_type = Types.PHOTO

        elif msg.reply_to_message.audio:
            content = msg.reply_to_message.audio.file_id
            text, buttons = button_markdown_parser(msgtext, entities=entities)
            data_type = Types.AUDIO

        elif msg.reply_to_message.voice:
            content = msg.reply_to_message.voice.file_id
            text, buttons = button_markdown_parser(msgtext, entities=entities)
            data_type = Types.VOICE

        elif msg.reply_to_message.video:
            content = msg.reply_to_message.video.file_id
            text, buttons = button_markdown_parser(msgtext, entities=entities)
            data_type = Types.VIDEO

        elif msg.reply_to_message.video_note:
            content = msg.reply_to_message.video_note.file_id
            text, buttons = button_markdown_parser(msgtext, entities=entities)
            data_type = Types.VIDEO_NOTE

    return note_name, text, data_type, content, buttons
Beispiel #39
0
def warn(user: User,
         chat: Chat,
         reason: str,
         message: Message,
         warner: User = None) -> str:
    if is_user_admin(chat, user.id):
        message.reply_text("Damn Admins, can't even be warned!")
        return ""

    if warner:
        warner_tag = mention_html(warner.id, warner.first_name)
    else:
        warner_tag = "Automated warn filter."

    limit, soft_warn = sql.get_warn_setting(chat.id)
    num_warns, reasons = sql.warn_user(user.id, chat.id, reason)
    if num_warns >= limit:
        sql.reset_warns(user.id, chat.id)
        if soft_warn:  # kick
            chat.unban_member(user.id)
            reply = "{} warnings, {} has been kicked!".format(
                limit, mention_html(user.id, user.first_name))

        else:  # ban
            chat.kick_member(user.id)
            reply = "{} warnings, {} has been banned!".format(
                limit, mention_html(user.id, user.first_name))

        for warn_reason in reasons:
            reply += "\n - {}".format(html.escape(warn_reason))

        message.bot.send_sticker(chat.id,
                                 BAN_STICKER)  # banhammer marie sticker
        keyboard = []
        log_reason = "<b>{}:</b>" \
                     "\n#WARN_BAN" \
                     "\n<b>Admin:</b> {}" \
                     "\n<b>User:</b> {} (<code>{}</code>)" \
                     "\n<b>Reason:</b> {}"\
                     "\n<b>Counts:</b> <code>{}/{}</code>".format(html.escape(chat.title),
                                                                  warner_tag,
                                                                  mention_html(user.id, user.first_name),
                                                                  user.id, reason, num_warns, limit)

    else:
        keyboard = InlineKeyboardMarkup([[
            InlineKeyboardButton("Remove warn (Admin Only)",
                                 callback_data="rm_warn({})".format(user.id))
        ]])

        reply = "{} has {}/{} warnings... watch out!".format(
            mention_html(user.id, user.first_name), num_warns, limit)
        if reason:
            reply += "\nReason for last warn:\n{}".format(html.escape(reason))

        log_reason = "<b>{}:</b>" \
                     "\n#WARN" \
                     "\n<b>Admin:</b> {}" \
                     "\n<b>User:</b> {} (<code>{}</code>)" \
                     "\n<b>Reason:</b> {}"\
                     "\n<b>Counts:</b> <code>{}/{}</code>".format(html.escape(chat.title),
                                                                  warner_tag,
                                                                  mention_html(user.id, user.first_name),
                                                                  user.id, reason, num_warns, limit)

    try:
        message.reply_text(reply,
                           reply_markup=keyboard,
                           parse_mode=ParseMode.HTML)
    except BadRequest as excp:
        if excp.message == "Reply message not found":
            # Do not reply
            message.reply_text(reply,
                               reply_markup=keyboard,
                               parse_mode=ParseMode.HTML,
                               quote=False)
        else:
            raise
    return log_reason
Beispiel #40
0
 def make_assertion(url, data, **kwargs):
     result = all(im.media.filename == 'custom_filename'
                  for im in data['media'])
     # We are a bit hacky here b/c Bot.send_media_group expects a list of Message-dicts
     return [Message(0, None, None, text=result).to_dict()]
Beispiel #41
0
    def editMessageText(self,
                        text,
                        chat_id=None,
                        message_id=None,
                        inline_message_id=None,
                        parse_mode=None,
                        disable_web_page_preview=None,
                        reply_markup=None,
                        **kwargs):
        """Use this method to edit text messages sent by the bot or via the bot
        (for inline bots).

        Args:
          text:
            New text of the message.
          chat_id:
            Required if inline_message_id is not specified. Unique identifier
            for the target chat or username of the target channel (in the
            format @channelusername).
          message_id:
            Required if inline_message_id is not specified. Unique identifier
            of the sent message.
          inline_message_id:
            Required if chat_id and message_id are not specified. Identifier of
            the inline message.
          parse_mode:
            Send Markdown or HTML, if you want Telegram apps to show bold,
            italic, fixed-width text or inline URLs in your bot's message.
          disable_web_page_preview:
            Disables link previews for links in this message.
          reply_markup:
            A JSON-serialized object for an inline keyboard.

        Keyword Args:
            timeout (Optional[float]): If this value is specified, use it as
                the definitive timeout (in seconds) for urlopen() operations.

        Returns:
            :class:`telegram.Message`: On success, if edited message is sent by
            the bot, the edited message is returned, otherwise `True` is
            returned.

        Raises:
            :class:`telegram.TelegramError`

        """

        url = '{0}/editMessageText'.format(self.base_url)

        data = {'text': text}

        if chat_id:
            data['chat_id'] = chat_id
        if message_id:
            data['message_id'] = message_id
        if inline_message_id:
            data['inline_message_id'] = inline_message_id
        if parse_mode:
            data['parse_mode'] = parse_mode
        if disable_web_page_preview:
            data['disable_web_page_preview'] = disable_web_page_preview
        if reply_markup:
            if isinstance(reply_markup, ReplyMarkup):
                data['reply_markup'] = reply_markup.to_json()
            else:
                data['reply_markup'] = reply_markup

        result = request.post(url, data, timeout=kwargs.get('timeout'))

        return Message.de_json(result)
Beispiel #42
0
def warn(user: User,
         chat: Chat,
         reason: str,
         message: Message,
         warner: User = None) -> str:
    if is_user_admin(chat, user.id):
        # message.reply_text("Damn admins, They are too far to be One Punched!")
        return

    if user.id in TIGERS:
        if warner:
            message.reply_text("Tigers cant be warned.")
        else:
            message.reply_text(
                "Tiger triggered an auto warn filter!\n I can't warn tigers but they should avoid abusing this."
            )
        return

    if user.id in WOLVES:
        if warner:
            message.reply_text("Wolf disasters are warn immune.")
        else:
            message.reply_text(
                "Wolf Disaster triggered an auto warn filter!\nI can't warn wolves but they should avoid abusing this."
            )
        return

    if warner:
        warner_tag = mention_html(warner.id, warner.first_name)
    else:
        warner_tag = "Automated warn filter."

    limit, soft_warn = sql.get_warn_setting(chat.id)
    num_warns, reasons = sql.warn_user(user.id, chat.id, reason)
    if num_warns >= limit:
        sql.reset_warns(user.id, chat.id)
        if soft_warn:  # punch
            chat.unban_member(user.id)
            reply = (
                f"<code>�</code><b>Punch Event</b>\n"
                f"<code> </code><b>•  User:</b> {mention_html(user.id, user.first_name)}\n"
                f"<code> </code><b>•  Count:</b> {limit}")

        else:  # ban
            chat.kick_member(user.id)
            reply = (
                f"<code>�</code><b>Ban Event</b>\n"
                f"<code> </code><b>•  User:</b> {mention_html(user.id, user.first_name)}\n"
                f"<code> </code><b>•  Count:</b> {limit}")

        for warn_reason in reasons:
            reply += f"\n - {html.escape(warn_reason)}"

        # message.bot.send_sticker(chat.id, BAN_STICKER)  # Saitama's sticker
        keyboard = None
        log_reason = (
            f"<b>{html.escape(chat.title)}:</b>\n"
            f"#WARN_BAN\n"
            f"<b>Admin:</b> {warner_tag}\n"
            f"<b>User:</b> {mention_html(user.id, user.first_name)}\n"
            f"<b>Reason:</b> {reason}\n"
            f"<b>Counts:</b> <code>{num_warns}/{limit}</code>")

    else:
        keyboard = InlineKeyboardMarkup([[
            InlineKeyboardButton("🔘 Remove warn",
                                 callback_data="rm_warn({})".format(user.id))
        ]])

        reply = (
            f"<code>�</code><b>Warn Event</b>\n"
            f"<code> </code><b>•  User:</b> {mention_html(user.id, user.first_name)}\n"
            f"<code> </code><b>•  Count:</b> {num_warns}/{limit}")
        if reason:
            reply += f"\n<code> </code><b>•  Reason:</b> {html.escape(reason)}"

        log_reason = (
            f"<b>{html.escape(chat.title)}:</b>\n"
            f"#WARN\n"
            f"<b>Admin:</b> {warner_tag}\n"
            f"<b>User:</b> {mention_html(user.id, user.first_name)}\n"
            f"<b>Reason:</b> {reason}\n"
            f"<b>Counts:</b> <code>{num_warns}/{limit}</code>")

    try:
        message.reply_text(reply,
                           reply_markup=keyboard,
                           parse_mode=ParseMode.HTML)
    except BadRequest as excp:
        if excp.message == "Reply message not found":
            # Do not reply
            message.reply_text(reply,
                               reply_markup=keyboard,
                               parse_mode=ParseMode.HTML,
                               quote=False)
        else:
            raise
    return log_reason
Beispiel #43
0
def extract_unt_fedban(message: Message,
                       args: List[str]) -> (Optional[int], Optional[str]):
    prev_message = message.reply_to_message
    split_text = message.text.split(None, 1)

    if len(split_text) < 2:
        return id_from_reply(message)  # only option possible

    text_to_parse = split_text[1]

    text = ""

    entities = list(message.parse_entities([MessageEntity.TEXT_MENTION]))
    if len(entities) > 0:
        ent = entities[0]
    else:
        ent = None

    # if entity offset matches (command end/text start) then all good
    if entities and ent and ent.offset == len(
            message.text) - len(text_to_parse):
        ent = entities[0]
        user_id = ent.user.id
        text = message.text[ent.offset + ent.length:]

    elif len(args) >= 1 and args[0][0] == '@':
        user = args[0]
        user_id = get_user_id(user)
        if not user_id and not isinstance(user_id, int):
            message.reply_text(
                "Saya tidak memiliki pengguna di db saya. Anda akan dapat berinteraksi dengan mereka jika "
                "Anda membalas pesan orang itu, atau meneruskan salah satu dari pesan pengguna itu."
            )
            return None, None

        else:
            user_id = user_id
            res = message.text.split(None, 2)
            if len(res) >= 3:
                text = res[2]

    elif len(args) >= 1 and args[0].isdigit():
        user_id = int(args[0])
        res = message.text.split(None, 2)
        if len(res) >= 3:
            text = res[2]

    elif prev_message:
        user_id, text = id_from_reply(message)

    else:
        return None, None

    try:
        message.bot.get_chat(user_id)
    except BadRequest as excp:
        if excp.message in ("User_id_invalid",
                            "Chat not found") and not isinstance(user_id, int):
            message.reply_text(
                "Saya sepertinya tidak pernah berinteraksi dengan pengguna ini "
                "sebelumnya - silakan meneruskan pesan dari mereka untuk memberi saya kontrol! "
                "(Seperti boneka voodoo, saya butuh sepotong untuk bisa"
                "untuk menjalankan perintah tertentu...)")
            return None, None
        elif excp.message != "Chat not found":
            LOGGER.exception("Exception %s on user %s", excp.message, user_id)
            return None, None
        elif not isinstance(user_id, int):
            return None, None

    return user_id, text
def check_chat_type(message: telegram.Message):
    if message.chat.type not in ["group", "supergroup"]:
        message.reply_text("Use me in groups or supergroups only!")
        return 0
    else:
        return 1
 def test_filters_reply(self):
     another_message = Message(1, User(1, "TestOther"), datetime.now(), Chat(0, 'private'))
     self.message.text = 'test'
     self.assertFalse(Filters.reply(self.message))
     self.message.reply_to_message = another_message
     self.assertTrue(Filters.reply(self.message))
Beispiel #46
0
def update():
    _update = Update(0)
    _update.message = Message(0, 0, datetime.utcnow(), Chat(0, 0))
    return _update
Beispiel #47
0
 def test_channel_message_without_chat(self, bot):
     handler = ConversationHandler(entry_points=[CommandHandler('start', self.start_end)],
                                   states={}, fallbacks=[])
     message = Message(0, None, None, Chat(0, Chat.CHANNEL, 'Misses Test'), bot=bot)
     update = Update(0, message=message)
     assert not handler.check_update(update)
Beispiel #48
0
def warn(user: User,
         chat: Chat,
         reason: str,
         message: Message,
         warner: User = None) -> str:
    bot = dispatcher.bot

    if is_user_admin(chat, user.id):
        message.reply_text(tld(chat.id, 'warns_warn_admin_no_warn'))
        return ""

    if warner:
        warner_tag = mention_html(warner.id, warner.first_name)
    else:
        warner_tag = tld(chat.id, 'warns_warn_admin_autofilter')

    limit, soft_warn = sql.get_warn_setting(chat.id)
    num_warns, reasons = sql.warn_user(user.id, chat.id, reason)
    if num_warns >= limit:
        sql.reset_warns(user.id, chat.id)
        if soft_warn:  # kick
            chat.unban_member(user.id)
            reply = tld(chat.id, 'warns_max_warn_kick').format(
                limit, mention_html(user.id, user.first_name))

        else:  # ban
            chat.kick_member(user.id)
            reply = tld(chat.id, 'warns_max_warn_ban').format(
                limit, mention_html(user.id, user.first_name))

        for warn_reason in reasons:
            reply += "\n - {}".format(html.escape(warn_reason))

        keyboard = []
        log_reason = tld(chat.id, 'warns_warn_ban_log_channel').format(
            html.escape(chat.title), warner_tag,
            mention_html(user.id, user.first_name), user.id, reason, num_warns,
            limit)

    else:
        keyboard = [[
            InlineKeyboardButton(tld(chat.id, 'warns_btn_remove_warn'),
                                 callback_data="rm_warn({})".format(user.id))
        ]]
        rules = rules_sql.get_rules(chat.id)

        if rules:
            keyboard[0].append(
                InlineKeyboardButton(tld(chat.id, 'warns_btn_rules'),
                                     url="t.me/{}?start={}".format(
                                         bot.username, chat.id)))

        reply = tld(chat.id, 'warns_user_warned').format(
            mention_html(user.id, user.first_name), num_warns, limit)
        if reason:
            reply += tld(chat.id, 'warns_latest_warn_reason').format(
                html.escape(reason))

        log_reason = tld(chat.id, 'warns_warn_log_channel').format(
            html.escape(chat.title), warner_tag,
            mention_html(user.id, user.first_name), user.id, reason, num_warns,
            limit)

    try:
        message.reply_text(reply,
                           reply_markup=InlineKeyboardMarkup(keyboard),
                           parse_mode=ParseMode.HTML)
    except BadRequest as excp:
        if excp.message == "Reply message not found":
            # Do not reply
            message.reply_text(reply,
                               reply_markup=InlineKeyboardMarkup(keyboard),
                               parse_mode=ParseMode.HTML,
                               quote=False)
        else:
            raise
    return log_reason
Beispiel #49
0
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program.  If not, see [http://www.gnu.org/licenses/].

import pytest

from telegram import (Message, Update, Chat, Bot, User, CallbackQuery, InlineQuery,
                      ChosenInlineResult, ShippingQuery, PreCheckoutQuery)
from telegram.ext import RegexHandler

message = Message(1, User(1, ''), None, Chat(1, ''), text='Text')

params = [
    {'callback_query': CallbackQuery(1, User(1, ''), 'chat', message=message)},
    {'inline_query': InlineQuery(1, User(1, ''), '', '')},
    {'chosen_inline_result': ChosenInlineResult('id', User(1, ''), '')},
    {'shipping_query': ShippingQuery('id', User(1, ''), '', None)},
    {'pre_checkout_query': PreCheckoutQuery('id', User(1, ''), '', 0, '')},
    {'callback_query': CallbackQuery(1, User(1, ''), 'chat')}
]

ids = ('callback_query', 'inline_query', 'chosen_inline_result',
       'shipping_query', 'pre_checkout_query', 'callback_query_without_message')


@pytest.fixture(scope='class', params=params, ids=ids)
    def test_persisting_no_user_no_chat(self, cdp):
        class OwnPersistence(BasePersistence):
            def __init__(self):
                super(OwnPersistence, self).__init__()
                self.store_user_data = True
                self.store_chat_data = True
                self.store_bot_data = True
                self.test_flag_bot_data = False
                self.test_flag_chat_data = False
                self.test_flag_user_data = False

            def update_bot_data(self, data):
                self.test_flag_bot_data = True

            def update_chat_data(self, chat_id, data):
                self.test_flag_chat_data = True

            def update_user_data(self, user_id, data):
                self.test_flag_user_data = True

            def update_conversation(self, name, key, new_state):
                pass

            def get_conversations(self, name):
                pass

            def get_user_data(self):
                pass

            def get_bot_data(self):
                pass

            def get_chat_data(self):
                pass

        def callback(update, context):
            pass

        handler = MessageHandler(Filters.all, callback)
        cdp.add_handler(handler)
        cdp.persistence = OwnPersistence()

        update = Update(1,
                        message=Message(1,
                                        None,
                                        None,
                                        from_user=User(1, '', False),
                                        text='Text'))
        cdp.process_update(update)
        assert cdp.persistence.test_flag_bot_data
        assert cdp.persistence.test_flag_user_data
        assert not cdp.persistence.test_flag_chat_data

        cdp.persistence.test_flag_bot_data = False
        cdp.persistence.test_flag_user_data = False
        cdp.persistence.test_flag_chat_data = False
        update = Update(1,
                        message=Message(1,
                                        None,
                                        Chat(1, ''),
                                        from_user=None,
                                        text='Text'))
        cdp.process_update(update)
        assert cdp.persistence.test_flag_bot_data
        assert not cdp.persistence.test_flag_user_data
        assert cdp.persistence.test_flag_chat_data
Beispiel #51
0
    def test_addConversationHandler(self):
        self._setup_updater('', messages=0)
        d = self.updater.dispatcher
        user = User(first_name="Misses Test", id=123)
        second_user = User(first_name="Mister Test", id=124)

        handler = ConversationHandler(entry_points=self.entry_points,
                                      states=self.states,
                                      fallbacks=self.fallbacks)
        d.add_handler(handler)
        queue = self.updater.start_polling(0.01)

        # User one, starts the state machine.
        message = Message(0,
                          user,
                          None,
                          self.group,
                          text="/start",
                          bot=self.bot)
        queue.put(Update(update_id=0, message=message))
        sleep(.1)
        self.assertTrue(self.current_state[user.id] == self.THIRSTY)

        # The user is thirsty and wants to brew coffee.
        message = Message(0,
                          user,
                          None,
                          self.group,
                          text="/brew",
                          bot=self.bot)
        queue.put(Update(update_id=0, message=message))
        sleep(.1)
        self.assertTrue(self.current_state[user.id] == self.BREWING)

        # Lets see if an invalid command makes sure, no state is changed.
        message = Message(0,
                          user,
                          None,
                          self.group,
                          text="/nothing",
                          bot=self.bot)
        queue.put(Update(update_id=0, message=message))
        sleep(.1)
        self.assertTrue(self.current_state[user.id] == self.BREWING)

        # Lets see if the state machine still works by pouring coffee.
        message = Message(0,
                          user,
                          None,
                          self.group,
                          text="/pourCoffee",
                          bot=self.bot)
        queue.put(Update(update_id=0, message=message))
        sleep(.1)
        self.assertTrue(self.current_state[user.id] == self.DRINKING)

        # Let's now verify that for another user, who did not start yet,
        # the state has not been changed.
        message = Message(0,
                          second_user,
                          None,
                          self.group,
                          text="/brew",
                          bot=self.bot)
        queue.put(Update(update_id=0, message=message))
        sleep(.1)
        self.assertRaises(KeyError, self._get_state, user_id=second_user.id)
    def test_error_while_persisting(self, cdp, monkeypatch):
        class OwnPersistence(BasePersistence):
            def __init__(self):
                super(OwnPersistence, self).__init__()
                self.store_user_data = True
                self.store_chat_data = True
                self.store_bot_data = True

            def update(self, data):
                raise Exception('PersistenceError')

            def update_bot_data(self, data):
                self.update(data)

            def update_chat_data(self, chat_id, data):
                self.update(data)

            def update_user_data(self, user_id, data):
                self.update(data)

            def get_chat_data(self):
                pass

            def get_bot_data(self):
                pass

            def get_user_data(self):
                pass

            def get_conversations(self, name):
                pass

            def update_conversation(self, name, key, new_state):
                pass

        def callback(update, context):
            pass

        test_flag = False

        def error(update, context):
            nonlocal test_flag
            test_flag = str(context.error) == 'PersistenceError'
            raise Exception('ErrorHandlingError')

        def logger(message):
            assert 'uncaught error was raised while handling' in message

        update = Update(1,
                        message=Message(1,
                                        None,
                                        Chat(1, ''),
                                        from_user=User(1, '', False),
                                        text='Text'))
        handler = MessageHandler(Filters.all, callback)
        cdp.add_handler(handler)
        cdp.add_error_handler(error)
        monkeypatch.setattr(cdp.logger, 'exception', logger)

        cdp.persistence = OwnPersistence()
        cdp.process_update(update)
        assert test_flag
Beispiel #53
0
def send_message(message: Message, chat_id: int) -> Union[MessageId, Message]:
    if REMOVE_TAG:
        return message.copy(chat_id)
    return message.forward(chat_id)
    def test_error_while_saving_chat_data(self, bot):
        increment = []

        class OwnPersistence(BasePersistence):
            def __init__(self):
                super().__init__()
                self.store_user_data = True
                self.store_chat_data = True
                self.store_bot_data = True

            def get_bot_data(self):
                return dict()

            def update_bot_data(self, data):
                raise Exception

            def get_chat_data(self):
                return defaultdict(dict)

            def update_chat_data(self, chat_id, data):
                raise Exception

            def get_user_data(self):
                return defaultdict(dict)

            def update_user_data(self, user_id, data):
                raise Exception

            def get_conversations(self, name):
                pass

            def update_conversation(self, name, key, new_state):
                pass

        def start1(b, u):
            pass

        def error(b, u, e):
            increment.append("error")

        # If updating a user_data or chat_data from a persistence object throws an error,
        # the error handler should catch it

        update = Update(1,
                        message=Message(1,
                                        None,
                                        Chat(1, "lala"),
                                        from_user=User(1, "Test", False),
                                        text='/start',
                                        entities=[
                                            MessageEntity(
                                                type=MessageEntity.BOT_COMMAND,
                                                offset=0,
                                                length=len('/start'))
                                        ],
                                        bot=bot))
        my_persistence = OwnPersistence()
        dp = Dispatcher(bot,
                        None,
                        persistence=my_persistence,
                        use_context=False)
        dp.add_handler(CommandHandler('start', start1))
        dp.add_error_handler(error)
        dp.process_update(update)
        assert increment == ["error", "error", "error"]
Beispiel #55
0
class TestGroupMemberScanner:

    from_user = User(1,'testUser', False)
    chat_instance = 'chat_instance'
    private_message = Message(3, None, Chat(4321234, 'private', username='******', first_name='botname'), from_user=User(5, 'bot', False, username='******'))
    group_message = Message(3, None, text='123', chat=Chat(1234321, 'group', username='******', first_name='botname', title='bot_group'), from_user=User(11223344, 'bot', False, username='******'))
    bot_message = Message(3, None, text='ok-123\nkk-1234\niok - 5\n', chat=Chat(1234321, 'group', username='******', first_name='botname', title='bot_group'), from_user=User(11223344, 'bot', False, username='******'), via_bot=User(BOT_ID, 'bot', True))

    @flaky(3, 1)
    def test_groupNotAdded(self, notAddedUpdate):
        massDelete("Users") 
        massDelete("TelegramGroups")
        massDelete("UserGroupRelational")
        massDelete("TelegramGroups") # Clear out the Telegram Groups table
        assert groupMemberScanner(notAddedUpdate, tempContext) == 'Group with id 1234321 not added' # Group has yet to be registered in the TelegramGroups table
        massDelete("TelegramGroups")
        massDelete("Users") 
        massDelete("UserGroupRelational")

    @flaky(3, 1)
    def test_userNotAdded(self, notAddedUpdate):
        massDelete("TelegramGroups")
        assert addGroup(('1234321', 'group')) == 'Group group 1234321 inserted' # Group has been added to the MySQL
        
        massDelete("Users") 
        groupMemberScanner(notAddedUpdate, tempContext)
        assert userAlreadyAdded(11223344) == True # User is added in the Users table
        assert userInGroup('11223344', '1234321') == True
        massDelete("Users") 
        massDelete("TelegramGroups")
        massDelete("UserGroupRelational")

    @flaky(3, 1)
    def test_userNotInGroup(self, notAddedUpdate):
        massDelete("UserGroupRelational")
        assert addGroup(('1234321', 'group')) == 'Group group 1234321 inserted'
        groupMemberScanner(notAddedUpdate, tempContext)
        assert userInGroup('11223344', '1234321') == True  # User and Group are related in the UserGroupRelational table
        massDelete("Users")
        massDelete("TelegramGroups")
        massDelete("UserGroupRelational")

    @flaky(3, 1)  
    def test_userStateSplitEvenly(self, notAddedUpdate):
        massDelete("UserGroupRelational")
        assert addGroup(('1234321', 'group')) == 'Group group 1234321 inserted'
        groupMemberScanner(notAddedUpdate, tempContext) # Initial
        assert updateUserStateSplitEvenly('11223344', '1234321') == "User 11223344 in Group 1234321 has state 'splitevenly'"
        assert updateUserTempAmount('11223344', '1234321', '123') == "User 11223344 in Group 1234321 has the temporary amount 123"
        assert addOrder(('temporderid123', '345', 'testOrderName', 123, '345', datetime.now(tz).replace(microsecond=0))) == "Order temporderid123 has been added"
        assert updateOrderIDToUserGroupRelational(11223344, 1234321, 'temporderid123') == "User 11223344 in Group 1234321 has OrderID temporderid123"
        assert groupMemberScanner(notAddedUpdate, tempContext) == "User 11223344 has state 'splitevenly'"
        massDelete("UserGroupRelational")
        massDelete("TelegramGroups")
        massDelete("Users")
        massDelete("Orders")

    @flaky(3, 1)
    def test_userStateSplitUnevenly(self, notAddedUpdate):
        massDelete("UserGroupRelational")
        massDelete("TelegramGroups")
        assert addGroup(('1234321', 'group')) == 'Group group 1234321 inserted'
        groupMemberScanner(notAddedUpdate, tempContext) # Initial
        assert updateUserStateSplitUnevenly('11223344', '1234321') == "User 11223344 in Group 1234321 has state 'splitunevenly'"
        assert addOrder(('4321', '1234321', 'ordertestname', '123', '11223344', datetime.now())) == "Order 4321 has been added"
        assert updateUserTempAmount('11223344', '1234321', '123') == "User 11223344 in Group 1234321 has the temporary amount 123"
        assert updateOrderIDToUserGroupRelational('11223344', '1234321', '4321') == "User 11223344 in Group 1234321 has OrderID 4321"
        assert groupMemberScanner(notAddedUpdate, tempContext) == "User 11223344 has state 'splitunevenly'"        
        massDelete("UserGroupRelational")
        massDelete("TelegramGroups")
        massDelete("Users")
        massDelete("Orders")
    
    @flaky(3, 1)
    def test_viabotCheck(self, viaBotUpdate):
        massDelete("UserGroupRelational")
        assert addGroup(('1234321', 'group')) == 'Group group 1234321 inserted'
        assert groupMemberScanner(viaBotUpdate, tempContext) == "Bot found %s" % BOT_ID # Initial
        massDelete("UserGroupRelational")
        massDelete("TelegramGroups")
        massDelete("Users")
class TestDispatcher:
    message_update = Update(1,
                            message=Message(1,
                                            None,
                                            Chat(1, ''),
                                            from_user=User(1, '', False),
                                            text='Text'))
    received = None
    count = 0

    @pytest.fixture(autouse=True, name='reset')
    def reset_fixture(self):
        self.reset()

    def reset(self):
        self.received = None
        self.count = 0

    def error_handler(self, bot, update, error):
        self.received = error.message

    def error_handler_context(self, update, context):
        self.received = context.error.message

    def error_handler_raise_error(self, bot, update, error):
        raise Exception('Failing bigly')

    def callback_increase_count(self, bot, update):
        self.count += 1

    def callback_set_count(self, count):
        def callback(bot, update):
            self.count = count

        return callback

    def callback_raise_error(self, bot, update):
        if isinstance(bot, Bot):
            raise TelegramError(update.message.text)
        raise TelegramError(bot.message.text)

    def callback_if_not_update_queue(self, bot, update, update_queue=None):
        if update_queue is not None:
            self.received = update.message

    def callback_context(self, update, context):
        if (isinstance(context, CallbackContext)
                and isinstance(context.bot, Bot)
                and isinstance(context.update_queue, Queue)
                and isinstance(context.job_queue, JobQueue)
                and isinstance(context.error, TelegramError)):
            self.received = context.error.message

    def test_one_context_per_update(self, cdp):
        def one(update, context):
            if update.message.text == 'test':
                context.my_flag = True

        def two(update, context):
            if update.message.text == 'test':
                if not hasattr(context, 'my_flag'):
                    pytest.fail()
            else:
                if hasattr(context, 'my_flag'):
                    pytest.fail()

        cdp.add_handler(MessageHandler(Filters.regex('test'), one), group=1)
        cdp.add_handler(MessageHandler(None, two), group=2)
        u = Update(1, Message(1, None, None, None, text='test'))
        cdp.process_update(u)
        u.message.text = 'something'
        cdp.process_update(u)

    def test_error_handler(self, dp):
        dp.add_error_handler(self.error_handler)
        error = TelegramError('Unauthorized.')
        dp.update_queue.put(error)
        sleep(.1)
        assert self.received == 'Unauthorized.'

        # Remove handler
        dp.remove_error_handler(self.error_handler)
        self.reset()

        dp.update_queue.put(error)
        sleep(.1)
        assert self.received is None

    def test_double_add_error_handler(self, dp, caplog):
        dp.add_error_handler(self.error_handler)
        with caplog.at_level(logging.DEBUG):
            dp.add_error_handler(self.error_handler)
            assert len(caplog.records) == 1
            assert caplog.records[-1].msg.startswith(
                'The callback is already registered')

    def test_construction_with_bad_persistence(self, caplog, bot):
        class my_per:
            def __init__(self):
                self.store_user_data = False
                self.store_chat_data = False
                self.store_bot_data = False

        with pytest.raises(
                TypeError,
                match=
                'persistence must be based on telegram.ext.BasePersistence'):
            Dispatcher(bot, None, persistence=my_per())

    def test_error_handler_that_raises_errors(self, dp):
        """
        Make sure that errors raised in error handlers don't break the main loop of the dispatcher
        """
        handler_raise_error = MessageHandler(Filters.all,
                                             self.callback_raise_error)
        handler_increase_count = MessageHandler(Filters.all,
                                                self.callback_increase_count)
        error = TelegramError('Unauthorized.')

        dp.add_error_handler(self.error_handler_raise_error)

        # From errors caused by handlers
        dp.add_handler(handler_raise_error)
        dp.update_queue.put(self.message_update)
        sleep(.1)

        # From errors in the update_queue
        dp.remove_handler(handler_raise_error)
        dp.add_handler(handler_increase_count)
        dp.update_queue.put(error)
        dp.update_queue.put(self.message_update)
        sleep(.1)

        assert self.count == 1

    def test_run_async_multiple(self, bot, dp, dp2):
        def get_dispatcher_name(q):
            q.put(current_thread().name)

        q1 = Queue()
        q2 = Queue()

        dp.run_async(get_dispatcher_name, q1)
        dp2.run_async(get_dispatcher_name, q2)

        sleep(.1)

        name1 = q1.get()
        name2 = q2.get()

        assert name1 != name2

    def test_multiple_run_async_decorator(self, dp, dp2):
        # Make sure we got two dispatchers and that they are not the same
        assert isinstance(dp, Dispatcher)
        assert isinstance(dp2, Dispatcher)
        assert dp is not dp2

        @run_async
        def must_raise_runtime_error():
            pass

        with pytest.raises(RuntimeError):
            must_raise_runtime_error()

    def test_run_async_with_args(self, dp):
        dp.add_handler(
            MessageHandler(Filters.all,
                           run_async(self.callback_if_not_update_queue),
                           pass_update_queue=True))

        dp.update_queue.put(self.message_update)
        sleep(.1)
        assert self.received == self.message_update.message

    def test_multiple_run_async_deprecation(self, dp):
        assert isinstance(dp, Dispatcher)

        @run_async
        def callback(update, context):
            pass

        dp.add_handler(MessageHandler(Filters.all, callback))

        with pytest.warns(TelegramDeprecationWarning,
                          match='@run_async decorator'):
            dp.process_update(self.message_update)

    def test_async_raises_dispatcher_handler_stop(self, dp, caplog):
        @run_async
        def callback(update, context):
            raise DispatcherHandlerStop()

        dp.add_handler(MessageHandler(Filters.all, callback))

        with caplog.at_level(logging.WARNING):
            dp.update_queue.put(self.message_update)
            sleep(.1)
            assert len(caplog.records) == 1
            assert caplog.records[-1].msg.startswith(
                'DispatcherHandlerStop is not supported '
                'with async functions')

    def test_async_raises_exception(self, dp, caplog):
        @run_async
        def callback(update, context):
            raise RuntimeError('async raising exception')

        dp.add_handler(MessageHandler(Filters.all, callback))

        with caplog.at_level(logging.WARNING):
            dp.update_queue.put(self.message_update)
            sleep(.1)
            assert len(caplog.records) == 1
            assert caplog.records[-1].msg.startswith(
                'A promise with deactivated error handling')

    def test_add_async_handler(self, dp):
        dp.add_handler(
            MessageHandler(Filters.all,
                           self.callback_if_not_update_queue,
                           pass_update_queue=True,
                           run_async=True))

        dp.update_queue.put(self.message_update)
        sleep(.1)
        assert self.received == self.message_update.message

    def test_run_async_no_error_handler(self, dp, caplog):
        def func():
            raise RuntimeError('Async Error')

        with caplog.at_level(logging.ERROR):
            dp.run_async(func)
            sleep(.1)
            assert len(caplog.records) == 1
            assert caplog.records[-1].msg.startswith(
                'No error handlers are registered')

    def test_async_handler_error_handler(self, dp):
        dp.add_handler(
            MessageHandler(Filters.all,
                           self.callback_raise_error,
                           run_async=True))
        dp.add_error_handler(self.error_handler)

        dp.update_queue.put(self.message_update)
        sleep(.1)
        assert self.received == self.message_update.message.text

    def test_async_handler_async_error_handler_context(self, cdp):
        cdp.add_handler(
            MessageHandler(Filters.all,
                           self.callback_raise_error,
                           run_async=True))
        cdp.add_error_handler(self.error_handler_context, run_async=True)

        cdp.update_queue.put(self.message_update)
        sleep(2)
        assert self.received == self.message_update.message.text

    def test_async_handler_error_handler_that_raises_error(self, dp, caplog):
        handler = MessageHandler(Filters.all,
                                 self.callback_raise_error,
                                 run_async=True)
        dp.add_handler(handler)
        dp.add_error_handler(self.error_handler_raise_error, run_async=False)

        with caplog.at_level(logging.ERROR):
            dp.update_queue.put(self.message_update)
            sleep(.1)
            assert len(caplog.records) == 1
            assert caplog.records[-1].msg.startswith(
                'An uncaught error was raised')

        # Make sure that the main loop still runs
        dp.remove_handler(handler)
        dp.add_handler(
            MessageHandler(Filters.all,
                           self.callback_increase_count,
                           run_async=True))
        dp.update_queue.put(self.message_update)
        sleep(.1)
        assert self.count == 1

    def test_async_handler_async_error_handler_that_raises_error(
            self, dp, caplog):
        handler = MessageHandler(Filters.all,
                                 self.callback_raise_error,
                                 run_async=True)
        dp.add_handler(handler)
        dp.add_error_handler(self.error_handler_raise_error, run_async=True)

        with caplog.at_level(logging.ERROR):
            dp.update_queue.put(self.message_update)
            sleep(.1)
            assert len(caplog.records) == 1
            assert caplog.records[-1].msg.startswith(
                'An uncaught error was raised')

        # Make sure that the main loop still runs
        dp.remove_handler(handler)
        dp.add_handler(
            MessageHandler(Filters.all,
                           self.callback_increase_count,
                           run_async=True))
        dp.update_queue.put(self.message_update)
        sleep(.1)
        assert self.count == 1

    def test_error_in_handler(self, dp):
        dp.add_handler(MessageHandler(Filters.all, self.callback_raise_error))
        dp.add_error_handler(self.error_handler)

        dp.update_queue.put(self.message_update)
        sleep(.1)
        assert self.received == self.message_update.message.text

    def test_add_remove_handler(self, dp):
        handler = MessageHandler(Filters.all, self.callback_increase_count)
        dp.add_handler(handler)
        dp.update_queue.put(self.message_update)
        sleep(.1)
        assert self.count == 1
        dp.remove_handler(handler)
        dp.update_queue.put(self.message_update)
        assert self.count == 1

    def test_add_remove_handler_non_default_group(self, dp):
        handler = MessageHandler(Filters.all, self.callback_increase_count)
        dp.add_handler(handler, group=2)
        with pytest.raises(KeyError):
            dp.remove_handler(handler)
        dp.remove_handler(handler, group=2)

    def test_error_start_twice(self, dp):
        assert dp.running
        dp.start()

    def test_handler_order_in_group(self, dp):
        dp.add_handler(
            MessageHandler(Filters.photo, self.callback_set_count(1)))
        dp.add_handler(MessageHandler(Filters.all, self.callback_set_count(2)))
        dp.add_handler(MessageHandler(Filters.text,
                                      self.callback_set_count(3)))
        dp.update_queue.put(self.message_update)
        sleep(.1)
        assert self.count == 2

    def test_groups(self, dp):
        dp.add_handler(
            MessageHandler(Filters.all, self.callback_increase_count))
        dp.add_handler(MessageHandler(Filters.all,
                                      self.callback_increase_count),
                       group=2)
        dp.add_handler(MessageHandler(Filters.all,
                                      self.callback_increase_count),
                       group=-1)

        dp.update_queue.put(self.message_update)
        sleep(.1)
        assert self.count == 3

    def test_add_handler_errors(self, dp):
        handler = 'not a handler'
        with pytest.raises(TypeError, match='handler is not an instance of'):
            dp.add_handler(handler)

        handler = MessageHandler(Filters.photo, self.callback_set_count(1))
        with pytest.raises(TypeError, match='group is not int'):
            dp.add_handler(handler, 'one')

    def test_flow_stop(self, dp, bot):
        passed = []

        def start1(b, u):
            passed.append('start1')
            raise DispatcherHandlerStop

        def start2(b, u):
            passed.append('start2')

        def start3(b, u):
            passed.append('start3')

        def error(b, u, e):
            passed.append('error')
            passed.append(e)

        update = Update(1,
                        message=Message(1,
                                        None,
                                        None,
                                        None,
                                        text='/start',
                                        entities=[
                                            MessageEntity(
                                                type=MessageEntity.BOT_COMMAND,
                                                offset=0,
                                                length=len('/start'))
                                        ],
                                        bot=bot))

        # If Stop raised handlers in other groups should not be called.
        passed = []
        dp.add_handler(CommandHandler('start', start1), 1)
        dp.add_handler(CommandHandler('start', start3), 1)
        dp.add_handler(CommandHandler('start', start2), 2)
        dp.process_update(update)
        assert passed == ['start1']

    def test_exception_in_handler(self, dp, bot):
        passed = []
        err = Exception('General exception')

        def start1(b, u):
            passed.append('start1')
            raise err

        def start2(b, u):
            passed.append('start2')

        def start3(b, u):
            passed.append('start3')

        def error(b, u, e):
            passed.append('error')
            passed.append(e)

        update = Update(1,
                        message=Message(1,
                                        None,
                                        None,
                                        None,
                                        text='/start',
                                        entities=[
                                            MessageEntity(
                                                type=MessageEntity.BOT_COMMAND,
                                                offset=0,
                                                length=len('/start'))
                                        ],
                                        bot=bot))

        # If an unhandled exception was caught, no further handlers from the same group should be
        # called. Also, the error handler should be called and receive the exception
        passed = []
        dp.add_handler(CommandHandler('start', start1), 1)
        dp.add_handler(CommandHandler('start', start2), 1)
        dp.add_handler(CommandHandler('start', start3), 2)
        dp.add_error_handler(error)
        dp.process_update(update)
        assert passed == ['start1', 'error', err, 'start3']

    def test_telegram_error_in_handler(self, dp, bot):
        passed = []
        err = TelegramError('Telegram error')

        def start1(b, u):
            passed.append('start1')
            raise err

        def start2(b, u):
            passed.append('start2')

        def start3(b, u):
            passed.append('start3')

        def error(b, u, e):
            passed.append('error')
            passed.append(e)

        update = Update(1,
                        message=Message(1,
                                        None,
                                        None,
                                        None,
                                        text='/start',
                                        entities=[
                                            MessageEntity(
                                                type=MessageEntity.BOT_COMMAND,
                                                offset=0,
                                                length=len('/start'))
                                        ],
                                        bot=bot))

        # If a TelegramException was caught, an error handler should be called and no further
        # handlers from the same group should be called.
        dp.add_handler(CommandHandler('start', start1), 1)
        dp.add_handler(CommandHandler('start', start2), 1)
        dp.add_handler(CommandHandler('start', start3), 2)
        dp.add_error_handler(error)
        dp.process_update(update)
        assert passed == ['start1', 'error', err, 'start3']
        assert passed[2] is err

    def test_error_while_saving_chat_data(self, bot):
        increment = []

        class OwnPersistence(BasePersistence):
            def __init__(self):
                super().__init__()
                self.store_user_data = True
                self.store_chat_data = True
                self.store_bot_data = True

            def get_bot_data(self):
                return dict()

            def update_bot_data(self, data):
                raise Exception

            def get_chat_data(self):
                return defaultdict(dict)

            def update_chat_data(self, chat_id, data):
                raise Exception

            def get_user_data(self):
                return defaultdict(dict)

            def update_user_data(self, user_id, data):
                raise Exception

            def get_conversations(self, name):
                pass

            def update_conversation(self, name, key, new_state):
                pass

        def start1(b, u):
            pass

        def error(b, u, e):
            increment.append("error")

        # If updating a user_data or chat_data from a persistence object throws an error,
        # the error handler should catch it

        update = Update(1,
                        message=Message(1,
                                        None,
                                        Chat(1, "lala"),
                                        from_user=User(1, "Test", False),
                                        text='/start',
                                        entities=[
                                            MessageEntity(
                                                type=MessageEntity.BOT_COMMAND,
                                                offset=0,
                                                length=len('/start'))
                                        ],
                                        bot=bot))
        my_persistence = OwnPersistence()
        dp = Dispatcher(bot,
                        None,
                        persistence=my_persistence,
                        use_context=False)
        dp.add_handler(CommandHandler('start', start1))
        dp.add_error_handler(error)
        dp.process_update(update)
        assert increment == ["error", "error", "error"]

    def test_flow_stop_in_error_handler(self, dp, bot):
        passed = []
        err = TelegramError('Telegram error')

        def start1(b, u):
            passed.append('start1')
            raise err

        def start2(b, u):
            passed.append('start2')

        def start3(b, u):
            passed.append('start3')

        def error(b, u, e):
            passed.append('error')
            passed.append(e)
            raise DispatcherHandlerStop

        update = Update(1,
                        message=Message(1,
                                        None,
                                        None,
                                        None,
                                        text='/start',
                                        entities=[
                                            MessageEntity(
                                                type=MessageEntity.BOT_COMMAND,
                                                offset=0,
                                                length=len('/start'))
                                        ],
                                        bot=bot))

        # If a TelegramException was caught, an error handler should be called and no further
        # handlers from the same group should be called.
        dp.add_handler(CommandHandler('start', start1), 1)
        dp.add_handler(CommandHandler('start', start2), 1)
        dp.add_handler(CommandHandler('start', start3), 2)
        dp.add_error_handler(error)
        dp.process_update(update)
        assert passed == ['start1', 'error', err]
        assert passed[2] is err

    def test_error_handler_context(self, cdp):
        cdp.add_error_handler(self.callback_context)

        error = TelegramError('Unauthorized.')
        cdp.update_queue.put(error)
        sleep(.1)
        assert self.received == 'Unauthorized.'

    def test_sensible_worker_thread_names(self, dp2):
        thread_names = [
            thread.name
            for thread in getattr(dp2, '_Dispatcher__async_threads')
        ]
        print(thread_names)
        for thread_name in thread_names:
            assert thread_name.startswith("Bot:{}:worker:".format(dp2.bot.id))

    def test_non_context_deprecation(self, dp):
        with pytest.warns(TelegramDeprecationWarning):
            Dispatcher(dp.bot,
                       dp.update_queue,
                       job_queue=dp.job_queue,
                       workers=0,
                       use_context=False)

    def test_error_while_persisting(self, cdp, monkeypatch):
        class OwnPersistence(BasePersistence):
            def __init__(self):
                super(OwnPersistence, self).__init__()
                self.store_user_data = True
                self.store_chat_data = True
                self.store_bot_data = True

            def update(self, data):
                raise Exception('PersistenceError')

            def update_bot_data(self, data):
                self.update(data)

            def update_chat_data(self, chat_id, data):
                self.update(data)

            def update_user_data(self, user_id, data):
                self.update(data)

            def get_chat_data(self):
                pass

            def get_bot_data(self):
                pass

            def get_user_data(self):
                pass

            def get_conversations(self, name):
                pass

            def update_conversation(self, name, key, new_state):
                pass

        def callback(update, context):
            pass

        test_flag = False

        def error(update, context):
            nonlocal test_flag
            test_flag = str(context.error) == 'PersistenceError'
            raise Exception('ErrorHandlingError')

        def logger(message):
            assert 'uncaught error was raised while handling' in message

        update = Update(1,
                        message=Message(1,
                                        None,
                                        Chat(1, ''),
                                        from_user=User(1, '', False),
                                        text='Text'))
        handler = MessageHandler(Filters.all, callback)
        cdp.add_handler(handler)
        cdp.add_error_handler(error)
        monkeypatch.setattr(cdp.logger, 'exception', logger)

        cdp.persistence = OwnPersistence()
        cdp.process_update(update)
        assert test_flag

    def test_persisting_no_user_no_chat(self, cdp):
        class OwnPersistence(BasePersistence):
            def __init__(self):
                super(OwnPersistence, self).__init__()
                self.store_user_data = True
                self.store_chat_data = True
                self.store_bot_data = True
                self.test_flag_bot_data = False
                self.test_flag_chat_data = False
                self.test_flag_user_data = False

            def update_bot_data(self, data):
                self.test_flag_bot_data = True

            def update_chat_data(self, chat_id, data):
                self.test_flag_chat_data = True

            def update_user_data(self, user_id, data):
                self.test_flag_user_data = True

            def update_conversation(self, name, key, new_state):
                pass

            def get_conversations(self, name):
                pass

            def get_user_data(self):
                pass

            def get_bot_data(self):
                pass

            def get_chat_data(self):
                pass

        def callback(update, context):
            pass

        handler = MessageHandler(Filters.all, callback)
        cdp.add_handler(handler)
        cdp.persistence = OwnPersistence()

        update = Update(1,
                        message=Message(1,
                                        None,
                                        None,
                                        from_user=User(1, '', False),
                                        text='Text'))
        cdp.process_update(update)
        assert cdp.persistence.test_flag_bot_data
        assert cdp.persistence.test_flag_user_data
        assert not cdp.persistence.test_flag_chat_data

        cdp.persistence.test_flag_bot_data = False
        cdp.persistence.test_flag_user_data = False
        cdp.persistence.test_flag_chat_data = False
        update = Update(1,
                        message=Message(1,
                                        None,
                                        Chat(1, ''),
                                        from_user=None,
                                        text='Text'))
        cdp.process_update(update)
        assert cdp.persistence.test_flag_bot_data
        assert not cdp.persistence.test_flag_user_data
        assert cdp.persistence.test_flag_chat_data
    def test_nested_conversation_handler(self, dp, bot, user1, user2):
        self.nested_states[self.DRINKING] = [
            ConversationHandler(entry_points=self.drinking_entry_points,
                                states=self.drinking_states,
                                fallbacks=self.drinking_fallbacks,
                                map_to_parent=self.drinking_map_to_parent)
        ]
        handler = ConversationHandler(entry_points=self.entry_points,
                                      states=self.nested_states,
                                      fallbacks=self.fallbacks)
        dp.add_handler(handler)

        # User one, starts the state machine.
        message = Message(0,
                          user1,
                          None,
                          self.group,
                          text='/start',
                          bot=bot,
                          entities=[
                              MessageEntity(type=MessageEntity.BOT_COMMAND,
                                            offset=0,
                                            length=len('/start'))
                          ])
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.THIRSTY

        # The user is thirsty and wants to brew coffee.
        message.text = '/brew'
        message.entities[0].length = len('/brew')
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.BREWING

        # Lets pour some coffee.
        message.text = '/pourCoffee'
        message.entities[0].length = len('/pourCoffee')
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.DRINKING

        # The user is holding the cup
        message.text = '/hold'
        message.entities[0].length = len('/hold')
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.HOLDING

        # The user is sipping coffee
        message.text = '/sip'
        message.entities[0].length = len('/sip')
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.SIPPING

        # The user is swallowing
        message.text = '/swallow'
        message.entities[0].length = len('/swallow')
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.SWALLOWING

        # The user is holding the cup again
        message.text = '/hold'
        message.entities[0].length = len('/hold')
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.HOLDING

        # The user wants to replenish the coffee supply
        message.text = '/replenish'
        message.entities[0].length = len('/replenish')
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.REPLENISHING
        assert handler.conversations[(0, user1.id)] == self.BREWING

        # The user wants to drink their coffee again
        message.text = '/pourCoffee'
        message.entities[0].length = len('/pourCoffee')
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.DRINKING

        # The user is now ready to start coding
        message.text = '/startCoding'
        message.entities[0].length = len('/startCoding')
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.CODING

        # The user decides it's time to drink again
        message.text = '/drinkMore'
        message.entities[0].length = len('/drinkMore')
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.DRINKING

        # The user is holding their cup
        message.text = '/hold'
        message.entities[0].length = len('/hold')
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.HOLDING

        # The user wants to end with the drinking and go back to coding
        message.text = '/end'
        message.entities[0].length = len('/end')
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.END
        assert handler.conversations[(0, user1.id)] == self.CODING

        # The user wants to drink once more
        message.text = '/drinkMore'
        message.entities[0].length = len('/drinkMore')
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.DRINKING

        # The user wants to stop altogether
        message.text = '/stop'
        message.entities[0].length = len('/stop')
        dp.process_update(Update(update_id=0, message=message))
        assert self.current_state[user1.id] == self.STOPPING
        assert handler.conversations.get((0, user1.id)) is None
Beispiel #58
0
def get_welcome_type(msg: Message):
    data_type = None
    content = None
    text = ""

    try:
        if msg.reply_to_message:
            if msg.reply_to_message.text:
                args = msg.reply_to_message.text
            else:
                args = msg.reply_to_message.caption
        else:
            args = msg.text.split(None, 1)  # use python's maxsplit to separate cmd and args
    except AttributeError:
        args = False

    if msg.reply_to_message and msg.reply_to_message.sticker:
        content = msg.reply_to_message.sticker.file_id
        text = None
        data_type = Types.STICKER

    elif msg.reply_to_message and msg.reply_to_message.document:
        content = msg.reply_to_message.document.file_id
        text = msg.reply_to_message.caption
        data_type = Types.DOCUMENT

    elif msg.reply_to_message and msg.reply_to_message.photo:
        content = msg.reply_to_message.photo[-1].file_id  # last elem = best quality
        text = msg.reply_to_message.caption
        data_type = Types.PHOTO

    elif msg.reply_to_message and msg.reply_to_message.audio:
        content = msg.reply_to_message.audio.file_id
        text = msg.reply_to_message.caption
        data_type = Types.AUDIO

    elif msg.reply_to_message and msg.reply_to_message.voice:
        content = msg.reply_to_message.voice.file_id
        text = msg.reply_to_message.caption
        data_type = Types.VOICE

    elif msg.reply_to_message and msg.reply_to_message.video:
        content = msg.reply_to_message.video.file_id
        text = msg.reply_to_message.caption
        data_type = Types.VIDEO

    elif msg.reply_to_message and msg.reply_to_message.video_note:
        content = msg.reply_to_message.video_note.file_id
        text = None
        data_type = Types.VIDEO_NOTE

    buttons = []
    # determine what the contents of the filter are - text, image, sticker, etc
    if args:
        if msg.reply_to_message:
            argumen = msg.reply_to_message.caption if msg.reply_to_message.caption else ""
            offset = 0 # offset is no need since target was in reply
            entities = msg.reply_to_message.parse_entities()
        else:
            argumen = args[1]
            offset = len(argumen) - len(msg.text)  # set correct offset relative to command + notename
            entities = msg.parse_entities()
        text, buttons = button_markdown_parser(argumen, entities=entities, offset=offset)

    if not data_type:
        if text and buttons:
            data_type = Types.BUTTON_TEXT
        elif text:
            data_type = Types.TEXT

    return text, data_type, content, buttons
Beispiel #59
0
def extract_user_and_text(message: Message,
                          args: List[str]) -> (Optional[int], Optional[str]):
    prev_message = message.reply_to_message
    split_text = message.text.split(None, 1)

    if len(split_text) < 2:
        return id_from_reply(message)  # only option possible

    text_to_parse = split_text[1]

    text = ""

    entities = list(message.parse_entities([MessageEntity.TEXT_MENTION]))
    if len(entities) > 0:
        ent = entities[0]
    else:
        ent = None

    # if entity offset matches (command end/text start) then all good
    if entities and ent and ent.offset == len(
            message.text) - len(text_to_parse):
        ent = entities[0]
        user_id = ent.user.id
        text = message.text[ent.offset + ent.length:]

    elif len(args) >= 1 and args[0][0] == '@':
        user = args[0]
        user_id = get_user_id(user)
        if not user_id:
            message.reply_text(
                "No idea who this user is. You'll be able to interact with them if "
                "you reply to that person's message instead, or forward one of that user's messages."
            )
            return None, None

        else:
            user_id = user_id
            res = message.text.split(None, 2)
            if len(res) >= 3:
                text = res[2]

    elif len(args) >= 1 and args[0].isdigit():
        user_id = int(args[0])
        res = message.text.split(None, 2)
        if len(res) >= 3:
            text = res[2]

    elif prev_message:
        user_id, text = id_from_reply(message)

    else:
        return None, None

    try:
        message.bot.get_chat(user_id)
    except BadRequest as excp:
        if excp.message in ("User_id_invalid", "Chat not found"):
            message.reply_text(
                "I don't seem to have interacted with this user before - please forward a message from "
                "them to give me control! (like a voodoo doll, I need a piece of them to be able "
                "to execute certain commands...)")
        else:
            LOGGER.exception("Exception %s on user %s", excp.message, user_id)

        return None, None

    return user_id, text
def message(bot):
    return Message(TestMessage.id_,
                   TestMessage.from_user,
                   TestMessage.date,
                   TestMessage.chat,
                   bot=bot)