Serge-M
Serge-M

Reputation: 29

How to trigger a conversation handler with the bot reply? [Telegram Bot] [Python] [python-telegram-bot]

The logic is the following:

I used these examples as my starting point:

My code is this one:

from telegram import (
    Bot,
    Update,
    InlineKeyboardMarkup,
    InlineKeyboardButton,
)
from telegram.ext import (
    Updater,
    CommandHandler,
    MessageHandler,
    Filters,
    CallbackContext,
    CallbackQueryHandler,
    ConversationHandler,
)


def startCommand(update: Update, context: CallbackContext):
    keyboardMarkup = InlineKeyboardMarkup(
        [[InlineKeyboardButton('Share File 1', callback_data='sharingFile1')]]
    )
    update.message.reply_text(f'Howdy, {update.effective_user.first_name}.\nThis is the Main Menu.',
                              reply_markup=keyboardMarkup)


def convGetGMailAddr(update: Update, context: CallbackContext):
    update.message.reply_text('Waiting for your gmail address.\n\nSend /end and I\'ll stop waiting.')
    return convEmailAddr


def convMismatch(update: Update, context: CallbackContext):
    text = f"""Sorry, I don't understand this gmail address.
Please, send me your gmail address again.\n\nSend /end and I\'ll stop waiting.
"""
    update.message.reply_text(text)
    return convEmailAddr


def convGiveLink(update: Update, context: CallbackContext):
    link = 'https://docs.google.com/spreadsheets/d/1ZP1xZ0WaH8w2yaQTSx99gafNZWawQabcdVW5DSngavQ'
    update.message.reply_text(f'Thank you! Here\'s your link to the shared file:\n{link}')
    return ConversationHandler.END


def convEnd(update: Update, context: CallbackContext):
    update.message.reply_text('I\'ve stopped waiting.\n\nSend /start to go to the Main Menu.')
    return ConversationHandler.END


def sharingFileHandler(update: Update, context: CallbackContext):
    if update.callback_query.data == 'sharingFile1':
        update.callback_query.edit_message_text(
            update.effective_message.text,
            reply_markup=InlineKeyboardMarkup([])
        )
        conv_sharing = ConversationHandler(
            entry_points=[MessageHandler(Filters.regex('.*[File 1]*.*'), convGetGMailAddr)],
            states={
                convEmailAddr: [
                    MessageHandler(~Filters.regex('.*@gmail.com$') & ~Filters.command, convMismatch),
                    MessageHandler(Filters.regex('.*@gmail.com$'), convGiveLink),
                ],
            },
            fallbacks=[CommandHandler('end', convEnd)],
        )
        disp.add_handler(conv_sharing)
        bot.send_message(update.effective_chat.id, 'I\'ll share the File 1 with you.')


bot_token = 'abcd1234'
bot = Bot(bot_token)
updater = Updater(bot_token, use_context=True)
convEmailAddr = ''

disp = updater.dispatcher
disp.add_handler(CommandHandler('start', startCommand))
disp.add_handler(CallbackQueryHandler(sharingFileHandler))

updater.start_polling(drop_pending_updates=True)
updater.idle()

The issue is that the bot doesn't read it's own reply in the function sharingFileHandler to start the conversation handler. The entry point of the conversation is posting the string "File 1" and when I send something like "asdklhasdlkh file 1 asdaskldha" then everything works fine.

Another question is is it possible for the bot to listen to email addresses only inside of the conversation? Right now the function convGetGMailAddr starts at any moment.


Update 1 (2021-10-20)

Based on the CallMeStag's answer I changed my code.
Deleted the function convGetGMailAddr and modified the function sharingFileHandler:

def sharingFileHandler(update: Update, context: CallbackContext):
    if update.callback_query.data == 'sharingFile1':
        update.callback_query.edit_message_text(
            update.effective_message.text,
            reply_markup=InlineKeyboardMarkup([])
        )
        text = f"""I\'ll share the File 1 with you to your Google account.
Please, send me your gmail address.\n\nSend /end and I\'ll stop waiting."""
        bot.send_message(update.effective_chat.id, text)
        return convEmailAddr


bot_token = '1234abcd'
bot = Bot(bot_token)
updater = Updater(bot_token, use_context=True)
convEmailAddr = ''

disp = updater.dispatcher
disp.add_handler(CommandHandler('start', startCommand))
conv_sharing = ConversationHandler(
    entry_points=[CallbackQueryHandler(sharingFileHandler)],
    states={
        convEmailAddr: [
            MessageHandler(~Filters.regex('.*@gmail.com$') & ~Filters.command, convMismatch),
            MessageHandler(Filters.regex('.*@gmail.com$'), convGiveLink),
        ],
    },
    fallbacks=[CommandHandler('end', convEnd)],
)
disp.add_handler(conv_sharing)

updater.start_polling(drop_pending_updates=True)
updater.idle()

Now my bot does exactly what I want and it stopped doing what I wanted it to stop doing. 🙂
Thank you, CallMeStag!

Upvotes: 2

Views: 6743

Answers (1)

CallMeStag
CallMeStag

Reputation: 7030

You're building a new conversationhandler & adding it to the dispatcher every time sharingFileHandler is called. that's surely not what you want. You should instead build it only once and add it to the dispatcher also only once right where you add the other handlers (at the very end of your snippet).

You should then make CallbackQueryHandler(sharingFileHandler) the entry point of that conversation. this will automatically solve your second problem.


Disclaimer: I'm currently the maintainer of python-telegram-bot.

Upvotes: 6

Related Questions