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)
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)
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)
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)
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)
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)
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)
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)
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')
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')))
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
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
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)
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)
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
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
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()]
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)
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
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))
def update(): _update = Update(0) _update.message = Message(0, 0, datetime.utcnow(), Chat(0, 0)) return _update
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)
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
# # 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
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
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"]
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
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
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)