Telegram Bot InlineKeyboardButton click as an input to a messageHandler - python

Is it possible to have my InlineKeyboardButton callback function be the input to the next state? as if the user entered the text
for example if this is my callback:
async def button(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Parses the CallbackQuery and updates the message text."""
query = update.callback_query
await query.answer()
await update.message.reply_text(text=query.data)
return REPLY
and this is my conversation handler:
conv_handler = ConversationHandler(
entry_points=[CommandHandler('start', start)],
states={
REPLY: [
CallbackQueryHandler(button),
MessageHandler(
filters.TEXT & ~filters.COMMAND,
reply,
)
],
},
fallbacks=[CommandHandler("done", start)],
)
After clicking on an inline button, created at start function, and calling button callback, I would want to call the MessageHandler's reply function with an input I decide in the button callback
Thanks!

Related

How to display an image immediately in the aiogram chat?

#dp.message_handler(lambda message: message.text == "Python")
async def python(message: types.Message):
keyboard: InlineKeyboardMarkup = InlineKeyboardMarkup(resize_keyboard=True)
url_button_1: InlineKeyboardButton = InlineKeyboardButton(text=f"Road", url='https://***')
url_button_2: InlineKeyboardButton = InlineKeyboardButton(text=f"Tasks", url='https://***')
url_button_3: InlineKeyboardButton = InlineKeyboardButton(text=f"Books", url='https://***')
url_button_4: InlineKeyboardButton = InlineKeyboardButton(text=f"Text", url='https://***')
keyboard.add(url_button_1)
keyboard.add(url_button_2)
keyboard.add(url_button_3)
keyboard.add(url_button_4)
await message.answer(text=f"Select the necessary sources", reply_markup=keyboard)
How do I make sure that by clicking on any of these buttons, a picture is immediately displayed to the user in the chat?
With this option, you still need to click on the link, which works longer:
url_button_2: InlineKeyboardButton = InlineKeyboardButton(text=f"Tasks", url='https://***')

Why doesn't FSM(state) work with channel_post_handler?

When you click on the button, the bot sends a message asking you to specify the name(I'm sending the name in response) by writing message_data (for example), then the post handler in the channel should be called via state, but this does not happen (the code does not send the last print "test handler"). If you use it without state, everything works, just as if you use it in the bot itself via message_handler, everything works too. Why doesn't it work and how can I use FSM for messages in the channel, because I need to save several consecutive messages from there when I press the button.
#dp.callback_query_handler(text='test_video')
async def test_video(call: types.CallbackQuery, state: FSMContext):
message_data = await bot.send_message(chat_id=call.message.chat.id, text='OK now send me the title', reply_markup= ikb_back)
async with state.proxy() as data:
data['message_data'] = message_data
print("test set") # sends
await astate.Admin_State.test_video.name.set()
#dp.channel_post_handler(state=astate.Admin_State.test_video.name)
async def print_test_video(message: types.Message, state: FSMContext):
print("test handler") # does not send

How to add a WebApp button in a bot

how can I display such a button through the code in not through #BotFather
I use aiogram
Now I have default commands like
/start & /help
async def set_default_commands(dp):
await dp.bot.set_my_commands(
[
types.BotCommand("start", "Старт бота"),
types.BotCommand("help", "Помощь"),
]
)

Python Telegram Bot InlineKeyboard : ask for user confirmation

The user interacts with my Telegram bot using an Inline Keyboard. Some buttons execute functions that are sensitive and I would like to ask the user's confirmation before proceeding.
For example : in the main menu, the user chooses between two buttons Option 1 and Option 2. If clicked, the sensitive functions do_action_1 and do_action_2 are executed respectively.
A minimal working example is below :
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, CallbackContext
def start(update: Update, context: CallbackContext) -> None:
update.message.reply_text('Please choose:',
reply_markup = keyboard_main_menu())
def main_menu(update: Update, context: CallbackContext) -> None:
""" Displays the main menu keyboard when called. """
query = update.callback_query
query.answer()
query.edit_message_text(text = 'Please choose an option:',
reply_markup = keyboard_main_menu())
def keyboard_main_menu():
""" Creates the main menu keyboard """
keyboard = [
[InlineKeyboardButton("Option 1", callback_data='1'),
InlineKeyboardButton("Option 2", callback_data='2'),],
]
return InlineKeyboardMarkup(keyboard)
def do_action_1(update: Update, context: CallbackContext) -> None:
keyboard = [[InlineKeyboardButton("Main menu", callback_data='main')]]
reply_markup = InlineKeyboardMarkup(keyboard)
query = update.callback_query
query.answer()
query.edit_message_text(text=f"Selected option {query.data}\n"
f"Executed action 1.",
reply_markup=reply_markup)
def do_action_2(update: Update, context: CallbackContext) -> None:
keyboard = [[InlineKeyboardButton("Main menu", callback_data='main')]]
reply_markup = InlineKeyboardMarkup(keyboard)
query = update.callback_query
query.answer()
query.edit_message_text(text=f"Selected option {query.data}\n"
f"Executed action 2.",
reply_markup=reply_markup)
def main() -> None:
"""Run the bot."""
updater = Updater("TOKEN")
updater.dispatcher.add_handler(CommandHandler('start', start))
updater.dispatcher.add_handler(CallbackQueryHandler(main_menu, pattern='main'))
updater.dispatcher.add_handler(CallbackQueryHandler(do_action_1, pattern='1'))
updater.dispatcher.add_handler(CallbackQueryHandler(do_action_2, pattern='2'))
# Start the Bot
updater.start_polling()
print('started')
if __name__ == '__main__':
main()
Now, I would like to insert an intermediate step after clicking Option 1 or Option 2, displaying a keyboard "Are you sure ?" with two buttons Yes and No. Clicking Yes executes do_action_1 or do_action_2 based on the user's choice at the previous keyboard. Clicking No would bring the user back to the main menu.
How can I do that ?
You can display a keyboard with the options YES and NO and handle the input like you handled the input for the other buttons. To keep track of which action to take when the user presses YES, you can either encode that action in the callback_data or store it temporarily. See also this wiki page an Storing Data.
Disclaimer: I'm currently the maintainer of python-telegram-bot
Thanks to #CallMeStag's answer, I managed to get a mwe :
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, CallbackContext
def start(update: Update, context: CallbackContext) -> None:
"""Sends a message with three inline buttons attached."""
update.message.reply_text('Please choose:',
reply_markup = keyboard_main_menu())
def main_menu(update: Update, context: CallbackContext) -> None:
""" Displays the main menu keyboard when called. """
query = update.callback_query
query.answer()
query.edit_message_text(text = 'Please choose:',
reply_markup = keyboard_main_menu())
def keyboard_main_menu():
""" Creates the main menu keyboard """
keyboard = [
[InlineKeyboardButton("Option 1", callback_data='1'),
InlineKeyboardButton("Option 2", callback_data='2'),],
]
return InlineKeyboardMarkup(keyboard)
def confirm(update: Update, context: CallbackContext) -> None:
"""Parses the CallbackQuery and updates the message text."""
query = update.callback_query
query.answer()
keyboard = [
[InlineKeyboardButton("Yes", callback_data=f'YES{query.data}'),
InlineKeyboardButton("No", callback_data='main'),],
]
reply_markup = InlineKeyboardMarkup(keyboard)
query.edit_message_text(text=f"Selected option {query.data}."
f"Are you sure ? ",
reply_markup=reply_markup)
def do_action_1(update: Update, context: CallbackContext) -> None:
keyboard = [[InlineKeyboardButton("Main menu", callback_data='main')]]
reply_markup = InlineKeyboardMarkup(keyboard)
query = update.callback_query
query.answer()
query.edit_message_text(text=f"Selected option {query.data}\n"
f"Executed action 1.",
reply_markup=reply_markup)
def do_action_2(update: Update, context: CallbackContext) -> None:
keyboard = [[InlineKeyboardButton("Main menu", callback_data='main')]]
reply_markup = InlineKeyboardMarkup(keyboard)
query = update.callback_query
query.answer()
query.edit_message_text(text=f"Selected option {query.data}\n"
f"Executed action 2.",
reply_markup=reply_markup)
def main() -> None:
"""Run the bot."""
# Create the Updater and pass it your bot's token.
updater = Updater("TOKEN")
updater.dispatcher.add_handler(CommandHandler('start', start))
updater.dispatcher.add_handler(CallbackQueryHandler(main_menu, pattern='main'))
updater.dispatcher.add_handler(CallbackQueryHandler(confirm, pattern='^(|1|2)$'))
updater.dispatcher.add_handler(CallbackQueryHandler(do_action_1, pattern='YES1'))
updater.dispatcher.add_handler(CallbackQueryHandler(do_action_2, pattern='YES2'))
# Start the Bot
updater.start_polling()
print('started')
if __name__ == '__main__':
main()
The bot now correctly asks for the user's confirmation before executing do_action_1 and do_action_2. Thanks a lot !

Can you trigger a command from another in telegram bot?

Is it possible to force one command handler to run another in the same way as if the user did it him/herself, the example below is taken from the repo over at github for ``python-telegram-bot```
The goal is to trigger the /help command when the user chooses a any button from start
"""
Basic example for a bot that uses inline keyboards. For an in-depth explanation, check out
https://git.io/JOmFw.
"""
import logging
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, CallbackContext
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
)
logger = logging.getLogger(__name__)
def start(update: Update, context: CallbackContext) -> None:
"""Sends a message with three inline buttons attached."""
keyboard = [
[
InlineKeyboardButton("Option 1", callback_data='1'),
InlineKeyboardButton("Option 2", callback_data='2'),
],
[InlineKeyboardButton("Option 3", callback_data='3')],
]
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text('Please choose:', reply_markup=reply_markup)
def button(update: Update, context: CallbackContext) -> None:
"""Parses the CallbackQuery and updates the message text."""
query = update.callback_query
# CallbackQueries need to be answered, even if no notification to the user is needed
# Some clients may have trouble otherwise. See https://core.telegram.org/bots/api#callbackquery
query.answer()
query.edit_message_text(text=f"Selected option: {query.data}")
def help_command(update: Update, context: CallbackContext) -> None:
"""Displays info on how to use the bot."""
update.message.reply_text("Use /start to test this bot.")
def main() -> None:
"""Run the bot."""
# Create the Updater and pass it your bot's token.
updater = Updater("TOKEN")
updater.dispatcher.add_handler(CommandHandler('start', start))
updater.dispatcher.add_handler(CallbackQueryHandler(button))
updater.dispatcher.add_handler(CommandHandler('help', help_command))
# Start the Bot
updater.start_polling()
# Run the bot until the user presses Ctrl-C or the process receives SIGINT,
# SIGTERM or SIGABRT
updater.idle()
if __name__ == '__main__':
main()
I looked everywhere and search but no one seems to have a clear and straight forward explanation if this is doable or not
Yes, you can directly call another function with the update and context from the function the program is in. To demonstrate I added a line in your button function. Also mind the rewrites necessary in help_command since it wants to reply to a message. There is no message when this function is called from button:
def button(update: Update, context: CallbackContext) -> None:
"""Parses the CallbackQuery and updates the message text."""
query = update.callback_query
# CallbackQueries need to be answered, even if no notification to the user is needed
# Some clients may have trouble otherwise. See https://core.telegram.org/bots/api#callbackquery
query.answer()
query.edit_message_text(text=f"Selected option: {query.data}")
help_command(update, context)
def help_command(update: Update, context: CallbackContext) -> None:
"""Displays info on how to use the bot."""
# update.message.reply_text("Use /start to test this bot.")
context.bot.send_message(update.effective_user.id, "Use /start to test this bot.")
If for some reason you'd insist on using the reply_text function, you could rewrite help_command like this:
def help_command(update: Update, context: CallbackContext) -> None:
"""Displays info on how to use the bot."""
if hasattr(update.message, "reply_text"):
update.message.reply_text("Use /start to test this bot.")
else:
context.bot.send_message(update.effective_user.id, "Use /start to test this bot.")
Hope this helps.

Categories

Resources