Reputation: 31
I want the bot to handle "/add" command in a certain way. I would like to save three inputs from the user (title , text , comments)
@bot.message_handler(commands=['add'])
def add_to_database(message):
msg = bot.reply_to(message, """\
We are glad that you are helping us to grow please provide us with the following:-
title of article (the head of the article)
""")
the problem is when a user sends "/add" it becomes the message variable for the function , and so I wanna update this variable to the next message that will be sent by the user , I tried something like
title = updater.message.text
I want the user to send title of an article and that becomes the variable title, next we ask for the article and store it in another value all in plain text, and so on.
But I got an error like
title = updater.message.text
AttributeError: 'Updater' object has no attribute 'message'
Upvotes: 2
Views: 5490
Reputation: 142641
It is minimal example which uses ConversationHandler
to get title
, text
, and comments
in separated messages
You start conversation using command /add
.
Function add()
sends message to user with information what to do and it returns value TITLE
to inform bot that next message has to get function get_title()
.
Function get_title()
gets text and keep it in global dictionary as title
, and it returns value TEXT
to inform bot that next message has to get function get_text()
.
Function get_text()
gets text and keep it in global dictionary as text
, and it returns value COMMENTS
to inform bot that next message has to get function get_comments()
.
Function get_comments()
gets text and keep it in global dictionary as comments
, and it display all data from dictionary (but it could save it in database). It returns ConversationHandler.END
to inform bot that it is end of conversation. It could return COMMENTS
to get more comments but it would have to keep comments as list in dictionary. And it would need some command to stop getting comments and then save all data.
Base on example code conversationbot.py from documentation
from telegram.ext import Updater, CommandHandler, ConversationHandler, MessageHandler, Filters
TOKEN = 'YOUR_TOKEN'
updater = Updater(token=TOKEN, use_context=True)
dispatcher = updater.dispatcher
# --- structure for data ---
data = {'title': "", 'text': "", 'comments': ""}
# --- states use in conversation ---
TITLE = 1
TEXT = 2
COMMENTS = 3
# --- functions use in conversation ---
# Command Handler which starts conversation
def add(update, context):
global data # to assign new dictionary to external/global variable
# create new empty dictionary
data = {'title': "", 'text': "", 'comments': ""}
update.message.reply_text("add title, text, comments in separated messages\n\nnow write title")
# next state in conversation
return TITLE
def get_title(update, context):
data['title'] = update.message.text
update.message.reply_text(f"title: {update.message.text}\n\nnow write text")
# next state in conversation
return TEXT
def get_text(update, context):
data['text'] = update.message.text
update.message.reply_text(f"text: {update.message.text}\n\nnow write comments")
# next state in conversation
return COMMENTS
def get_comments(update, context):
data['comments'] = update.message.text
update.message.reply_text(f"comments: {update.message.text}")
msg = """I got all data
title: {}
text: {}
comments: {}""".format(data['title'], data['text'], data['comments'])
update.message.reply_text(msg)
# end of conversation
return ConversationHandler.END
def cancel(update, context):
update.message.reply_text('canceled')
# end of conversation
return ConversationHandler.END
# --- create conversation ---
my_conversation_handler = ConversationHandler(
entry_points=[CommandHandler('add', add)],
states={
TITLE: [
CommandHandler('cancel', cancel), # has to be before MessageHandler to catch `/cancel` as command, not as `title`
MessageHandler(Filters.text, get_title)
],
TEXT: [
CommandHandler('cancel', cancel), # has to be before MessageHandler to catch `/cancel` as command, not as `text`
MessageHandler(Filters.text, get_text)
],
COMMENTS: [
CommandHandler('cancel', cancel), # has to be before MessageHandler to catch `/cancel` as command, not as `comments`
MessageHandler(Filters.text, get_comments)
],
},
fallbacks=[CommandHandler('cancel', cancel)]
)
dispatcher.add_handler(my_conversation_handler)
# --- run bot ---
updater.start_polling()
print('Running... [Press Ctrl+C to stop]')
updater.idle()
print('Stoping...')
updater.stop()
EDIT: something similar with telebot
. I use global variable state
and message_handler which catchs unknow messages
import telebot
TOKEN = 'TOKEN'
bot = telebot.TeleBot(TOKEN)
#print(bot.get_me())
# --- structure for data ---
data = {'title': "", 'text': "", 'comments': ""}
# --- states use in conversation ---
state = None
TITLE = 1
TEXT = 2
COMMENTS = 3
@bot.message_handler(commands=['add'])
def test(message):
global state
global data
data = {'title': "", 'text': "", 'comments': ""}
bot.send_message(message.chat.id, 'add title, text, comments in separated messages\n\nnow write title')
state = TITLE
@bot.message_handler()
def unknown(message):
global state
if state == TITLE:
data['title'] = message.text
bot.send_message(message.chat.id, f"title: {message.text}\n\nnow write text")
state = TEXT
elif state == TEXT:
data['text'] = message.text
bot.send_message(message.chat.id, f"text: {message.text}\n\nnow write comments")
state = COMMENTS
elif state == COMMENTS:
data['comments'] = message.text
bot.send_message(message.chat.id, f"comments: {message.text}")
msg = """I got all data
title: {}
text: {}
comments: {}""".format(data['title'], data['text'], data['comments'])
bot.send_message(message.chat.id, msg)
state = None
#else:
# print('unknown message')
# bot.send_message(msg.chat.id, 'unknown message')
@bot.message_handler(commands=['cancel'])
def test(message):
global state
bot.send_message(message.chat.id, 'canceled')
state = None
bot.polling()
EDIT: simpler version
import telebot
TOKEN = 'TOKEN'
bot = telebot.TeleBot(TOKEN)
# --- structure for data ---
data = {'title': "", 'text': "", 'comments': ""}
# --- states use in conversation ---
bot.state = None # create own value `.state` in `bot` - so I don't have to use `global state`. Similar way I could create and use `bot.data`
TITLE = 1
TEXT = 2
COMMENTS = 3
@bot.message_handler(commands=['add'])
def test(message):
global data
data = {'title': "", 'text': "", 'comments': ""}
bot.send_message(message.chat.id, 'add title, text, comments in separated messages\n\nnow write title')
bot.state = TITLE
# it has to be before functions which check `bot.state`
@bot.message_handler(commands=['cancel'])
def test(message):
bot.send_message(message.chat.id, 'canceled')
bot.state = None
@bot.message_handler(func=lambda msg:bot.state==TITLE)
def get_title(message):
data['title'] = message.text
bot.send_message(message.chat.id, f"title: {message.text}\n\nnow write text")
bot.state = TEXT
@bot.message_handler(func=lambda msg:bot.state==TEXT)
def get_title(message):
data['text'] = message.text
bot.send_message(message.chat.id, f"text: {message.text}\n\nnow write comments")
bot.state = COMMENTS
@bot.message_handler(func=lambda msg:bot.state==COMMENTS)
def get_title(message):
data['comments'] = message.text
bot.send_message(message.chat.id, f"comments: {message.text}")
msg = """I got all data
title: {}
text: {}
comments: {}""".format(data['title'], data['text'], data['comments'])
bot.send_message(message.chat.id, msg)
bot.state = None
bot.polling()
Upvotes: 2