From c59ccf190819bca9a339c24fa3f9947e3b2482fb Mon Sep 17 00:00:00 2001 From: "o.vodianov" Date: Sun, 10 Aug 2025 23:28:28 +0400 Subject: [PATCH] change callback aueries and handlers sequence --- src/core/config.py | 1 + src/core/logging.py | 5 ++- src/docbot/handlers/admins/verify_handler.py | 1 + .../handlers/doctors/add_payments_method.py | 14 +++---- .../handlers/doctors/register_handler.py | 3 +- .../handlers/patients/consultation_handler.py | 37 +++++++++--------- .../handlers/patients/send_form_handler.py | 7 ++-- src/docbot/handlers/start_handler.py | 11 +++--- src/docbot/handlers/utils/cancel_handler.py | 7 +++- src/docbot/handlers/utils/help.py | 39 ++++++++++--------- src/docbot/handlers/utils/unknown.py | 2 +- src/docbot/main.py | 28 ++++++------- 12 files changed, 84 insertions(+), 71 deletions(-) diff --git a/src/core/config.py b/src/core/config.py index f5f78fd..1998685 100644 --- a/src/core/config.py +++ b/src/core/config.py @@ -7,6 +7,7 @@ class Settings(BaseSettings): BOT_TOKEN: str DATABASE_URL: str ADMIN_API_KEY: str + LOGGING_LEVEL: str settings = Settings() diff --git a/src/core/logging.py b/src/core/logging.py index 13c513c..7304dae 100644 --- a/src/core/logging.py +++ b/src/core/logging.py @@ -11,9 +11,10 @@ def setup_logging(): Конфигурирует консольный и файловый логгеры с ротацией. """ # Получаем уровень логирования из настроек, по умолчанию INFO - level_name = settings.log_level.upper() if hasattr(settings, 'log_level') else 'INFO' + level_name = settings.LOGGING_LEVEL if hasattr(settings, 'LOGGING_LEVEL') else 'INFO' log_level = getattr(logging, level_name, logging.INFO) + # Форматтер для всех хэндлеров formatter = logging.Formatter( fmt="%(asctime)s %(levelname)s [%(name)s] %(message)s", @@ -53,4 +54,4 @@ def setup_logging(): setup_logging() # Получаем logger для текущего модуля -logger = logging.getLogger(__name__) \ No newline at end of file +logger = logging.getLogger(__name__) diff --git a/src/docbot/handlers/admins/verify_handler.py b/src/docbot/handlers/admins/verify_handler.py index 49c90e5..3f9c5a8 100644 --- a/src/docbot/handlers/admins/verify_handler.py +++ b/src/docbot/handlers/admins/verify_handler.py @@ -174,4 +174,5 @@ def get_verify_handler(): ], }, fallbacks=[], + allow_reentry=True, ) diff --git a/src/docbot/handlers/doctors/add_payments_method.py b/src/docbot/handlers/doctors/add_payments_method.py index d422caf..851038c 100644 --- a/src/docbot/handlers/doctors/add_payments_method.py +++ b/src/docbot/handlers/doctors/add_payments_method.py @@ -5,11 +5,11 @@ from telegram.ext import ( CommandHandler, MessageHandler, filters, + CallbackQueryHandler ) from docbot.handlers.utils.cancel_handler import get_cancel_handler from docbot.services.doctors_service import add_payment_link -from docbot.handlers.utils.utils import cleanup_session from core.enums.dialog_helpers import ConfirmationMessage from core.logging import logger from core.utils import is_valid_url @@ -28,11 +28,11 @@ async def send_info(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: [ InlineKeyboardButton( ConfirmationMessage.PROCEED.value, - callback_data="accepted" + callback_data="pay:accepted" ), InlineKeyboardButton( ConfirmationMessage.DECLINE.value, - callback_data="declined" + callback_data="pay:declined" ), ] ] @@ -51,7 +51,7 @@ async def send_info(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: async def ask_payment_link(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: user_id = context.user_data['user_id'] - await update.message.reply_text( + await update.callback_query.message.reply_text( text="Введите адрес вашей платёжной ссылки, пожалуйста." ) logger.info(f"Ask user {user_id} to enter their payment link.") @@ -67,7 +67,7 @@ async def ask_payment_system_api(update: Update, context: ContextTypes.DEFAULT_T if is_valid_url(payment_link): logger.info(f"Payment link {payment_link} provided by user {user_id} is valid.") await update.message.reply_text( - text="Введите API ключ, который указан у вас личном кабинете плтёжной системы, пожалуйста." + text="Введите API ключ, который указан у вас личном кабинете платёжной системы, пожалуйста." ) return ASK_PAYMENT_SYSTEM_API else: @@ -106,8 +106,7 @@ def get_add_payment_method_handler() -> ConversationHandler: entry_points=[add_payment_method()], states={ ASK_PAYMENT_LINK: [ - MessageHandler(filters.TEXT & ~filters.COMMAND, - ask_payment_link) + CallbackQueryHandler(ask_payment_link, pattern="^(pay:accepted)$") ], ASK_PAYMENT_SYSTEM_API: [ MessageHandler(filters.TEXT & ~filters.COMMAND, @@ -121,4 +120,5 @@ def get_add_payment_method_handler() -> ConversationHandler: fallbacks=[get_cancel_handler()], name="add_payment_method", persistent=True, + allow_reentry=True, ) diff --git a/src/docbot/handlers/doctors/register_handler.py b/src/docbot/handlers/doctors/register_handler.py index 906a5f6..243d72d 100644 --- a/src/docbot/handlers/doctors/register_handler.py +++ b/src/docbot/handlers/doctors/register_handler.py @@ -212,5 +212,6 @@ def get_register_doctor_first_stage_handler() -> ConversationHandler: }, fallbacks=[get_cancel_handler()], name="register_doctor_conversation_first_stage", # для тестов/логирования - persistent=True, # если используете хранение состояний + persistent=True, + allow_reentry=True, # если используете хранение состояний ) diff --git a/src/docbot/handlers/patients/consultation_handler.py b/src/docbot/handlers/patients/consultation_handler.py index df6c2a3..14c99cc 100644 --- a/src/docbot/handlers/patients/consultation_handler.py +++ b/src/docbot/handlers/patients/consultation_handler.py @@ -43,11 +43,11 @@ keyboard = [ [ InlineKeyboardButton( "Записаться на консультацию", - callback_data="proceed_with_consultation" + callback_data="consult:proceed_with_consultation" ), InlineKeyboardButton( "Частые вопросы", - callback_data="frequent_questions" + callback_data="consult:frequent_questions" ), ] ] @@ -58,11 +58,11 @@ async def accept_personal_data_agreement(update: Update, context: ContextTypes.D [ InlineKeyboardButton( ConfirmationMessage.PROCEED.value, - callback_data="accepted" + callback_data="consult:accepted" ), InlineKeyboardButton( ConfirmationMessage.DECLINE.value, - callback_data="declined" + callback_data="consult:declined" ), ] ] @@ -94,7 +94,7 @@ async def receive_patient_aceptance(update: Update, context: ContextTypes.DEFAUL user_data = context.user_data await update.callback_query.answer() - if update.callback_query.data == "accepted": + if update.callback_query.data == "consult:accepted": user_data['accepted'] = True user_id = user_data['telegram_id'] await create_patient(telegram_id=user_id, terms_acceptance=True) # Создаем пациента в БД @@ -118,11 +118,11 @@ async def choose_consultation_type(update: Update, context: ContextTypes.DEFAULT [ InlineKeyboardButton( "Первичная консультация", - callback_data="initial_reception" + callback_data="consult:initial_reception" ), InlineKeyboardButton( "Повторная консультация", - callback_data="readmission" + callback_data="consult:readmission" ), ] ] @@ -181,7 +181,7 @@ async def receive_patient_phone(update: Update, context: ContextTypes.DEFAULT_TY [ InlineKeyboardButton( "Изменить", - callback_data="back" + callback_data="consult:back" ), ] ] @@ -199,7 +199,7 @@ async def receive_patient_phone(update: Update, context: ContextTypes.DEFAULT_TY [ InlineKeyboardButton( "Изменить", - callback_data="back" + callback_data="consult:back" ), ] ] @@ -251,11 +251,11 @@ async def receive_consultation_date(update: Update, context: ContextTypes.DEFAUL [ InlineKeyboardButton( "Изменить", - callback_data="back" + callback_data="consult:back" ), InlineKeyboardButton( "Продолжить", - callback_data="proceed" + callback_data="consult:proceed" ), ] ] @@ -304,23 +304,24 @@ def get_consultation_handler() -> ConversationHandler: return ConversationHandler( entry_points=[consultation_handler()], states={ - SEND_ACKNOWLEDGEMENT_INFO: [CallbackQueryHandler(receive_patient_aceptance)], - PROCEED_WITH_CONSULTATION: [CallbackQueryHandler(choose_consultation_type)], - SELECT_CONSULTATION_TYPE: [CallbackQueryHandler(enter_patient_phone)], + SEND_ACKNOWLEDGEMENT_INFO: [CallbackQueryHandler(receive_patient_aceptance, pattern=r"^consult:(accepted|declined)$")], + PROCEED_WITH_CONSULTATION: [CallbackQueryHandler(choose_consultation_type, pattern=r"^consult:proceed$")], + SELECT_CONSULTATION_TYPE: [CallbackQueryHandler(enter_patient_phone, pattern=r"^consult:(initial_reception|readmission)$")], ENTER_PATIENT_PHONE: [MessageHandler(filters=filters.TEXT & ~filters.COMMAND, callback=receive_patient_phone)], ENTER_DOCTOR_NUMBER: [ MessageHandler(filters.TEXT & ~filters.COMMAND, receive_doctor_number), - CallbackQueryHandler(enter_patient_phone, pattern="^" + "back" + "$") + CallbackQueryHandler(enter_patient_phone, pattern="^consult:back$") ], ENTER_CONSULTATION_DATE: [MessageHandler(filters=filters.TEXT & ~filters.COMMAND, callback=receive_consultation_date)], PAY_CONSULTATION: [ - CallbackQueryHandler(pay_consultation, pattern="^" + "proceed" + "$"), - CallbackQueryHandler(receive_doctor_number, pattern="^" + "back" + "$") + CallbackQueryHandler(pay_consultation, pattern="^consult:proceed$"), + CallbackQueryHandler(receive_doctor_number, pattern="^consult:back$") ], - ERROR_PHONE_NUMBER: [CallbackQueryHandler(enter_patient_phone, pattern="^" + "back" + "$")], + ERROR_PHONE_NUMBER: [CallbackQueryHandler(enter_patient_phone, pattern="^consult:back$")], STOPPING: [get_start_handler()], }, fallbacks=[get_cancel_handler()], name="consultation_dialog", persistent=True, + allow_reentry=True, ) diff --git a/src/docbot/handlers/patients/send_form_handler.py b/src/docbot/handlers/patients/send_form_handler.py index f2c6599..98c2e10 100644 --- a/src/docbot/handlers/patients/send_form_handler.py +++ b/src/docbot/handlers/patients/send_form_handler.py @@ -64,6 +64,7 @@ def get_send_form_handler() -> ConversationHandler: ], }, fallbacks=[get_cancel_handler()], - name="send_form_conversation", # для тестов/логирования - persistent=True, # если используете хранение состояний - ) \ No newline at end of file + name="send_form_conversation", + persistent=True, + allow_reentry=True, + ) diff --git a/src/docbot/handlers/start_handler.py b/src/docbot/handlers/start_handler.py index 4a0b2d7..6d869e0 100644 --- a/src/docbot/handlers/start_handler.py +++ b/src/docbot/handlers/start_handler.py @@ -1,6 +1,6 @@ from telegram import Update +from telegram.constants import ParseMode from telegram.ext import ContextTypes, CommandHandler -from core.logging import logger async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: @@ -8,12 +8,13 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: Отправляет приветствие и краткую инструкцию по работе с ботом. """ text = ( - "👋 Добро пожаловать в DocBot!\n\n" - "Используйте команду /consultation, чтобы произвести запись на консультацию, если вы пациент.\n" - "Используйте команду /register, если вы врач и у вас есть реферальный код." + "👋 Добро пожаловать в DocBot!\n" + "Используйте команду /consultation, чтобы произвести запись на консультацию, если вы пациент.\n\n" + "Используйте команду /register, если вы врач и у вас есть реферальный код.\n\n" + "Используйте команду /help, чтобы увидеть список доступных вам команд." ) - await context.bot.send_message(chat_id=update.effective_chat.id, text=text) + await context.bot.send_message(chat_id=update.effective_chat.id, text=text, parse_mode=ParseMode.HTML) def get_start_handler() -> CommandHandler: diff --git a/src/docbot/handlers/utils/cancel_handler.py b/src/docbot/handlers/utils/cancel_handler.py index d733d3f..5b2078c 100644 --- a/src/docbot/handlers/utils/cancel_handler.py +++ b/src/docbot/handlers/utils/cancel_handler.py @@ -1,4 +1,4 @@ -from telegram import Update +from telegram import Update, ReplyKeyboardRemove from telegram.ext import ( ContextTypes, ConversationHandler, @@ -7,7 +7,10 @@ from telegram.ext import ( async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: - await update.message.reply_text("❌ Отменено.") + await update.message.reply_text( + "❌ Отменено.", + reply_markup=ReplyKeyboardRemove() + ) return ConversationHandler.END diff --git a/src/docbot/handlers/utils/help.py b/src/docbot/handlers/utils/help.py index bd51843..d8dab50 100644 --- a/src/docbot/handlers/utils/help.py +++ b/src/docbot/handlers/utils/help.py @@ -1,5 +1,8 @@ -from telegram import Update, ReplyKeyboardMarkup, ReplyKeyboardRemove -from telegram.ext import ContextTypes, CommandHandler +from telegram import Update +from telegram.ext import ( + ContextTypes, CommandHandler, ConversationHandler +) +from telegram.constants import ParseMode from docbot.services.admins_service import get_admin_info from docbot.services.doctors_service import get_doctor @@ -25,30 +28,30 @@ async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No ) # (При необходимости в будущем можно добавить другие admin-команды) await update.message.reply_text(text, parse_mode="Markdown") - return # 2) Проверим, зарегистрирован ли врач - if await get_doctor(user_id): + elif await get_doctor(user_id): text = ( - "👨‍⚕️ *Меню доктора*:\n\n" + "👨‍⚕️ Меню доктора:\n" + "/start Запустить бота\n" + "/payment_methods Настроить платёжные способы\n" + "/help Показать это меню\n" + ) + + await update.message.reply_text(text, parse_mode=ParseMode.HTML) + + # 3) Иначе — это пациент (незарегистрированный/обычный пользователь) + else: + text = ( + "👤 *Меню пациента*:\n\n" "/start ‒ Запустить бота\n" - "/sessions ‒ Посмотреть список пациентов (или текущих сессий)\n" + "/get_form ‒ Получить ссылку на форму анкеты для заполнения" + "/send_form ‒ Отправить ссылку на заполненную анкету\n" "/help ‒ Показать это меню\n" ) await update.message.reply_text(text, parse_mode="Markdown") - return - - # 3) Иначе — это пациент (незарегистрированный/обычный пользователь) - text = ( - "👤 *Меню пациента*:\n\n" - "/start ‒ Запустить бота\n" - "/get_form ‒ Получить ссылку на форму анкеты для заполнения" - "/send_form ‒ Отправить ссылку на заполненную анкету\n" - "/help ‒ Показать это меню\n" - ) - - await update.message.reply_text(text, parse_mode="Markdown") + return ConversationHandler.END def get_help_handler() -> CommandHandler: diff --git a/src/docbot/handlers/utils/unknown.py b/src/docbot/handlers/utils/unknown.py index 753817f..6f1bc77 100644 --- a/src/docbot/handlers/utils/unknown.py +++ b/src/docbot/handlers/utils/unknown.py @@ -15,4 +15,4 @@ async def unknown_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> def get_unknown_handler() -> MessageHandler: """Фабрика для регистрации в Application.""" - return MessageHandler(filters.COMMAND, unknown_command) \ No newline at end of file + return MessageHandler(filters.COMMAND, unknown_command) diff --git a/src/docbot/main.py b/src/docbot/main.py index d544fc1..dfd41cc 100644 --- a/src/docbot/main.py +++ b/src/docbot/main.py @@ -26,21 +26,21 @@ def main(): .concurrent_updates(concurrent_updates=False) .build() ) - app.add_handler(get_start_handler(), group=0) - app.add_handler(get_cancel_handler(), group=0) - app.add_handler(get_help_handler(), group=0) - app.add_handler(get_consultation_handler(), group=1) - app.add_handler(get_send_form_handler(), group=2) - app.add_handler(get_doctors_handler(), group=3) - app.add_handler(get_register_doctor_first_stage_handler(), group=1) - app.add_handler(get_referral_handlers(), group=3) - app.add_handler(get_verify_handler(), group=3) - app.add_handler(get_unknown_handler(), group=0) - app.add_handler(get_add_payment_method_handler(), group=1) - app.add_error_handler(get_start_handler()) - app.add_handlers - logger.debug("Все хэндлеры зарегистрированы, запускаем polling") + app.add_handler(get_start_handler()) + app.add_handler(get_cancel_handler()) + app.add_handler(get_help_handler()) + app.add_handler(get_consultation_handler()) + app.add_handler(get_send_form_handler()) + app.add_handler(get_doctors_handler()) + app.add_handler(get_register_doctor_first_stage_handler()) + app.add_handler(get_referral_handlers()) + app.add_handler(get_verify_handler()) + app.add_handler(get_add_payment_method_handler()) + + app.add_handler(get_unknown_handler()) + + logger.info("Все хэндлеры зарегистрированы, запускаем polling") app.run_polling()