Футбольный телеграм бот на Python (2/4): Функциональность бота
Во второй части серии статей по написанию телеграм бота на python, мы добавим функциональность. Бот будет приветствовать новых юзеров, предлагать выбрать и сохранять лиги. Добавим возможность получить результаты по выбранным лигам.
«Рыба» кода бота
Сразу запишем функции в «bot.py», которые понадобятся. Предварительно удалите test_message :
# fonlinebot/app/bot.py # . dp.middleware.setup(LoggingMiddleware()) @dp.message_handler(commands=['start']) async def start_handler(message: types.Message): """Обработка команды start. Вывод текста и меню""" . @dp.message_handler(commands=['help']) async def help_handler(message: types.Message): """Обработка команды help. Вывод текста и меню""" . @dp.callback_query_handler(lambda c: c.data == 'main_window') async def show_main_window(callback_query: types.CallbackQuery): """Главный экран""" . @dp.message_handler(lambda message: message.text == msg.btn_online) @dp.message_handler(commands=['online']) async def get_results(message: types.Message): """Обработка команды online и кнопки Онлайн. Запрос матчей. Вывод результатов""" . @dp.callback_query_handler(lambda c: c.data.startswith('update_results')) async def update_results(): """Обновление сообщения результатов""" . @dp.message_handler(lambda message: message.text == msg.btn_config) async def get_config(message: types.Message): """Обработка кнопки Настройки. Проверка выбора лиг. Вывод меню изменений настроек""" . @dp.callback_query_handler(lambda c: c.data.startswith('edit_config')) async def set_or_update_config(user_id: str): """Получение или обновление выбранных лиг""" . @dp.callback_query_handler(lambda c: c.data[:6] in ['del_le', 'add_le']) async def update_leagues_info(callback_query: types.CallbackQuery): """Добавление/удаление лиги из кеша, обновление сообщения""" . @dp.callback_query_handler(lambda c: c.data == 'save_config') async def save_config(callback_query: types.CallbackQuery): """Сохранение пользователя в базу данных""" . @dp.callback_query_handler(lambda c: c.data == 'delete_config') async def delete_config(user_id: str): """Удаление пользователя из базы данных""" . @dp.message_handler() async def unknown_message(message: types.Message): """Ответ на любое неожидаемое сообщение""" . async def on_shutdown(dp): # .Это не окончательная версия, я мог что-то упустить. В процессе добавим недостающие.
Каждая функция обернута декоратором, так мы общаемся с Телегармом:
- @dp.message_handler(commands=['start']) — декоратор ожидает сообщения-команды (которые начинаются с / ). В этом примере он ожидает команду /start .
- @dp.callback_query_handler(lambda c: c.data == 'main_window') — ожидает callback и принимает lambda-функцию для его фильтрации. Callback отправляется inline-кнопками. В примере мы ожидаем callback со значением 'main_window' .
- @dp.message_handler(lambda message: message.text == msg.btn_config) — этот декоратор похож на предыдущий, но ожидает сообщение от пользователя. В примере мы будем обрабатывать сообщение с текстом из msg.btn_config .
Итак. Пользователь нажимает команду старт, получает приветственное сообщение. В нем мы предлагаем выбрать 3 лиги и мониторить результаты по ним. Получить результаты можно командой или кнопкой меню. Так же мы даем возможность изменить выбранные соревнования или удалить свои данные из бота.
Добавление команд в бота
Изначально команды не настроены. Пользователи могут вводить их, но специально меню нет. Для добавления нужно снова написать https://t.me/botfather команду /setcommands . Выберите своего бота и добавьте этот текст:
start - Запуск и перезапуск бота
help - Возможности бота
online - Результаты матчей
В ответ получите «Success! Command list updated. /help». Теперь можно перейти в своего бота и проверить:
Ответы на команды
Взаимодействие с ботом начинается с команды /start . Нужно поприветствовать и предложить следующий шаг. Эта команда будет возвращать текст с клавиатурой. Точно так же работает и /help .
Добавим обработку этих команд в «bot.py», обновите start_handler help_handler :
# fonlinebot/app/bot.py # . from config import TOKEN, YEAR, MINUTE import app.service as s # . @dp.message_handler(commands=['start']) async def start_handler(message: types.Message): """Обработка команды start. Вывод текста и меню""" # проверка, есть ли пользователь в базе user_league_ids = await s.get_league_ids(message.from_user.id) if not user_league_ids: await message.answer(msg.start_new_user) # добавление id сообщения настроек cache.setex(f"last_msg_", YEAR, message.message_id+2) await set_or_update_config(user_id=message.from_user.id) else: await message.answer(msg.start_current_user, reply_markup=s.MAIN_KB) @dp.message_handler(commands=['help']) async def help_handler(message: types.Message): """Обработка команды help. Вывод текста и меню""" await message.answer(msg.help, reply_markup=s.MAIN_KB) # .Я добавил импорт import app.service as s . В этом модуле клавиатура и функция проверки пользователя. start_handler проверяет есть ли пользователь в кеше или базе данных, и отправляет ему соответствующий текст.
Перед отправкой текста для выбора лиг, я сохранил его будущий id. Получил номер последнего сообщения (это сама команда «start») и добавил 2 пункта: +1 за наш ответ на команду и +1 за само сообщения выбора лиг. Зная id сообщения, его можно редактирвать.
Теперь напишем клавиатуру и get_league_ids в модуль «service».
# fonlinebot/app/service.py from aiogram.types import ReplyKeyboardMarkup, KeyboardButton, \ InlineKeyboardMarkup, InlineKeyboardButton from emoji import emojize from config import BOT_LEAGUES, BOT_LEAGUE_FLAGS from database import cache, database as db from app.dialogs import msg MAIN_KB = ReplyKeyboardMarkup( resize_keyboard=True, one_time_keyboard=True ).row( KeyboardButton(msg.btn_online), KeyboardButton(msg.btn_config) ) async def get_league_ids(user_id: str) -> list: """Функция получает id лиг пользователя в базе данных""" leagues = cache.lrange(f"u", 0, -1) if leagues is None: leagues = await db.select_users(user_id) if leagues is not None: leagues = leagues.split(',') [cache.lpush(f"u", lg_id) for lg_id in leagues] else: return [] return leagues
MAIN_KB — основная клавиатура, как на скриншоте выше. Разберем подробнее:
- ReplyKeyboardMarkup — объект, который создает клавиатуру.
- Параметр resize_keyboard=True уменьшает ее размер.
- А с one_time_keyboard=True клавиатура будет скрываться, после использования.
- .row — метод для группировки кнопок в строку.
- KeyboardButton(msg.btn_online) и KeyboardButton(msg.btn_config) — кнопки с заданным текстом.
Осталось только добавить текста сообщений в dialogs. Вставьте этот код в класс Messages .
# fonlinebot/app/dialogs.py # . start_new_user: str = "Привет. Я могу сообщать тебе результаты матчей online." start_current_user: str = "Привет. С возвращением! " \ "Используй команды или меню внизу для продолжения." help: str = """ Этот бот получает результаты матчей за последние 48 часов. Включая режим LIVE. - Что бы выбрать/изменить лиги нажмите "Настройки". - Для проверки результатов нажмите "Онлайн". Бот создан в учебных целях, для сайта pythonru.com """Выбор, изменение и удаление лиг
Сначала внесем правки в наши вспомогательные модули.
В «dababase» в класс Database добавим новый метод insert_or_update_users .
# fonlinebot/database.py #. async def insert_or_update_users(self, user_id: int, leagues: str): user_leagues = await self.select_users(user_id) if user_leagues is not None: await self.update_users(user_id, leagues) else: await self.insert_users(user_id, leagues) #.В настройки добавим переменные метрик времени: