Вывод календаря пользователю вместо ручного ввода даты
Есть телеграм-бот, написанный на pyTelegramBotAPI
. Ниже я привел два метода (убрав запросы, чтобы сократить) где пользователь после авторизации может получить результаты или протокол. Для этого после авторизации пользователю требуется ввести дату. Сейчас он это делает вручную, но я хочу чтобы вместо ручного ввода пользователю выводился полноценный календарь с текущим месяцем и датами, а также возможностью листать месяцы, чтобы он выбрал дату из календаря, а не вводил вручную. Как такое можно реализовать?
Не хочется пока что переходить на более сложные библиотеки для ботов типа aiogram, по возможности на библиотеке pyTelegramBotAPI
хочу реализовать т.к. бот уже работает.
##################################### АУТЕНТИФИКАЦИЯ ПАЦИЕНТА. НАЧАЛО #####################################
# Функция аутентификации по логину и паролю
def authenticate_user(message, next_step):
chat_id = message.chat.id
user = message.from_user
if message.text == 'Отмена':
handle_cancel(chat_id)
return
login = message.text.strip()
msg = bot.send_message(message.chat.id, "Введите ваш пароль:", reply_markup=get_cancel_keyboard())
bot.register_next_step_handler(msg, lambda m: process_password(m, login, next_step, user))
def process_password(message, login, next_step, user):
chat_id = message.chat.id
if message.text == 'Отмена':
handle_cancel(chat_id)
return
password = message.text.strip()
try:
with pool.acquire() as connection:
with connection.cursor() as cursor:
query = """ЗАПРОС"""
cursor.execute(query, {'login': login.upper(), 'password': password.upper()})
result = cursor.fetchone()
if result:
patientid = result[0]
next_step(chat_id, patientid, user)
else:
msg = bot.send_message(message.chat.id, f"Неправильные данные. Пожалуйста, попробуйте снова. {LOGIN_TEXT}", reply_markup=get_cancel_keyboard())
bot.register_next_step_handler(msg, lambda m: authenticate_user(m, next_step))
except Exception as e:
log_error(user, e, "process_password")
bot.send_message(message.chat.id, "Произошла ошибка при обработке вашего запроса.")
##################################### АУТЕНТИФИКАЦИЯ ПАЦИЕНТА. КОНЕЦ #####################################
##################################### ОБРАБОТКА /results #####################################
# Обработчик команды /results
@bot.message_handler(commands=['results'])
def handle_results(message):
bot.send_message(message.chat.id, LOGIN_TEXT, reply_markup=get_cancel_keyboard())
bot.register_next_step_handler(message, lambda m: authenticate_user(m, ask_res_date))
def ask_res_date(chat_id, patientid, user):
msg = bot.send_message(chat_id, "Введите дату (в формате ДД.ММ.ГГГГ):", reply_markup=get_cancel_keyboard())
bot.register_next_step_handler(msg, lambda m: get_results(m, patientid, user))
def get_results(message, patientid, user):
chat_id = message.chat.id
if message.text == 'Отмена':
handle_cancel(chat_id)
return
try:
res_date = datetime.strptime(message.text.strip(), '%d.%m.%Y').date()
with pool.acquire() as connection:
with connection.cursor() as cursor:
query = """ЗАПРОС"""
cursor.execute(query, {'patientid': patientid, 'res_date': res_date})
results = cursor.fetchall()
if results:
bot.send_message(message.chat.id, "Ваши результаты формируются...")
data = []
for row in results:
data.append({
//данные
})
//отправка пользователю
# Удаляем клавиатуру после вывода данных
bot.send_message(chat_id, f"Результаты сформированы.", reply_markup=types.ReplyKeyboardRemove())
else:
bot.send_message(chat_id, f"Готовых результатов не найдено.", reply_markup=types.ReplyKeyboardRemove())
bot.register_next_step_handler(msg, lambda m: get_results(m, patientid, user))
except ValueError as e:
log_error(user, e, "get_results")
msg = bot.send_message(chat_id, "Неправильный формат даты. Пожалуйста, введите дату в формате ДД.ММ.ГГГ:", reply_markup=get_cancel_keyboard())
bot.register_next_step_handler(msg, lambda m: get_results(m, patientid, user))
except Exception as e:
log_error(user, e, "get_results")
bot.send_message(chat_id, "Произошла ошибка при обработке вашего запроса.", reply_markup=get_cancel_keyboard())
##################################### /protocols #####################################
# Обработчик команды /protocols
@bot.message_handler(commands=['protocols'])
def handle_protocols(message):
bot.send_message(message.chat.id, LOGIN_TEXT, reply_markup=get_cancel_keyboard())
bot.register_next_step_handler(message, lambda m: authenticate_user(m, ask_protocol_date))
def ask_protocol_date(chat_id, patientid, user):
msg = bot.send_message(chat_id, "Введите дату (в формате ДД.ММ.ГГГГ):", reply_markup=get_cancel_keyboard())
bot.register_next_step_handler(msg, lambda m: get_prots(m, patientid, user))
def get_prots(message, patientid, user):
chat_id = message.chat.id
if message.text == 'Отмена':
handle_cancel(chat_id)
return
try:
prot_date = datetime.strptime(message.text.strip(), '%d.%m.%Y').date()
with pool.acquire() as connection:
with connection.cursor() as cursor:
query = """ЗАПРС"""
cursor.execute(query, {'patientid': patientid, 'prot_date': prot_date})
results = cursor.fetchall()
pdf_files = []
if results:
bot.send_message(message.chat.id, "Ваши данные формируются...")
for row in results:
if row[8]: # Проверяем, есть ли значение в поле 'fr'
data = {
//данные
}
//Отправка пользователю
# Удаляем клавиатуру после вывода данных
bot.send_message(chat_id, f"Данные сформированы.", reply_markup=types.ReplyKeyboardRemove())
else:
bot.send_message(chat_id, f"Данные не найдены.", reply_markup=types.ReplyKeyboardRemove())
msg = bot.send_message(message.chat.id, "Введите дату (в формате ДД.ММ.ГГГГ):", reply_markup=get_cancel_keyboard())
bot.register_next_step_handler(msg, lambda m: get_prots(m, patientid, user))
except ValueError as e:
log_error(user, e, "get_prots")
msg = bot.send_message(chat_id, "Неправильный формат даты. Пожалуйста, введите дату в формате ДД.ММ.ГГГ:", reply_markup=get_cancel_keyboard())
bot.register_next_step_handler(msg, lambda m: get_prots(m, patientid, user))
except Exception as e:
log_error(user, e, "get_prots")
bot.send_message(chat_id, "Произошла ошибка при обработке вашего запроса.", reply_markup=get_cancel_keyboard())
# Функция для создания кнопок
def get_cancel_keyboard():
keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True)
cancel_button = types.KeyboardButton("Отмена")
keyboard.add(cancel_button)
return keyboard
# Общая команда для отмены действий
def handle_cancel(chat_id):
bot.send_message(chat_id, "Действие отменено", reply_markup=types.ReplyKeyboardRemove())
if __name__ == '__main__':
main()
Ответы (2 шт):
Чисто в теории вам надо выводить сообщение бота в котором будет "календарь" на месяц. И каждый день - это ссылка, которая будет командой для бота, что это выбранная дата. По этой команде бота делает то, что он обычно делается когда пользователь указывает дату вручную.
Плюс две ссылки с командами для переключения месяца (вперед и назад). По этой команде выводится еще одно сообщение бота, с календарем на указанный месяц. Предыдущее сообщение с календарем можно стирать, а можно оставить. Тут как вам удобней.
Чисто в теории все должно работать. Но вот реализация этого всего не очень простая.
В телеграме нет возможности ввода даты календарём, соответственно то что вы хотите сделать, невозможно реализовать "из коробки".
Уже предлагали вариант с командами. Из других могу предположить, что можно такое реализовать инлайн кнопками или с помощью стороннего приложения (с приложениями сам не работал, но, вроде они поддерживают колбэки). С добавлением внутреннего браузера появился вариант, например открывать в браузере ваш календарь, и при взаимодействии с ним, например копировать команду с датой в буфер обмена.