diff --git a/main.py b/main.py index c017a53..9dfb390 100644 --- a/main.py +++ b/main.py @@ -7,6 +7,7 @@ from olgram.settings import TORTOISE_ORM import olgram.commands.bot import olgram.commands.bots import olgram.commands.start +import olgram.commands.menu async def init_database(): diff --git a/olgram/commands/bot.py b/olgram/commands/bot.py index e0e8a4a..3771990 100644 --- a/olgram/commands/bot.py +++ b/olgram/commands/bot.py @@ -21,48 +21,6 @@ select_bot_chat = CallbackData('chat_select', 'bot_id', 'chat_id') select_bot_chat_personal = CallbackData('chat_select_personal', 'bot_id') -def check_bot_owner(handler): - """ - Этот декоратор запрещает пользователям вызывать callback's (inline кнопки) для ботов, которыми они не владеют - """ - async def wrapped(call: types.CallbackQuery, callback_data: dict, state: FSMContext): - bot_id = callback_data["bot_id"] - bot = await Bot.get_or_none(id=bot_id) - if not bot or (await bot.owner).telegram_id != call.from_user.id: - await call.answer("У вас нет прав на этого бота", show_alert=True) - return - - return await handler(bot, call, callback_data, state) - return wrapped - - -@dp.callback_query_handler(select_bot.filter(), state="*") -@check_bot_owner -async def select_bot_callback(bot: Bot, call: types.CallbackQuery, callback_data: dict, state: FSMContext): - """ - Пользователь выбрал бота для редактирования - """ - await try_delete_message(call.message) - - keyboard = types.InlineKeyboardMarkup(row_width=2) - keyboard.insert(types.InlineKeyboardButton(text="Текст", - callback_data=bot_operation.new(bot_id=bot.id, operation="text"))) - keyboard.insert(types.InlineKeyboardButton(text="Чат", - callback_data=bot_operation.new(bot_id=bot.id, operation="chat"))) - keyboard.insert(types.InlineKeyboardButton(text="Удалить бот", - callback_data=bot_operation.new(bot_id=bot.id, operation="delete"))) - keyboard.insert(types.InlineKeyboardButton(text="<<Вернуться к списку ботов", - callback_data=bot_operation.new(bot_id=bot.id, operation="back"))) - - await AioBot.get_current().send_message(call.message.chat.id, dedent(f""" - Управление ботом @{bot.name}. - - Если у вас возникли вопросы по настройке бота, то посмотрите нашу справку /help. - """), reply_markup=keyboard) - - -@dp.callback_query_handler(bot_operation.filter(operation="delete"), state="*") -@check_bot_owner async def delete_bot_callback(bot: Bot, call: types.CallbackQuery, callback_data: dict, state: FSMContext): """ Кнопка "удалить" для бота @@ -72,37 +30,8 @@ async def delete_bot_callback(bot: Bot, call: types.CallbackQuery, callback_data await try_delete_message(call.message) -@dp.callback_query_handler(bot_operation.filter(operation="chat"), state="*") -@check_bot_owner -async def chats_bot_callback(bot: Bot, call: types.CallbackQuery, callback_data: dict, state: FSMContext): - """ - Кнопка "чаты" для бота - """ - await try_delete_message(call.message) - - keyboard = types.InlineKeyboardMarkup(row_width=2) - - chats = await bot.group_chats.all() - - if not chats: - return await AioBot.get_current().send_message(call.message.chat.id, dedent(f""" - Этот бот не добавлен в чаты, поэтому все сообщения будут приходить вам в бот. - Чтобы подключить чат — просто добавьте бот @{bot.name} в чат. - """), reply_markup=keyboard) - - for chat in chats: - keyboard.insert(types.InlineKeyboardButton(text=chat.name, - callback_data=select_bot_chat.new(bot_id=bot.id, chat_id=chat.id))) - keyboard.insert(types.InlineKeyboardButton(text="Личные сообщения", - callback_data=select_bot_chat_personal.new(bot_id=bot.id))) - await AioBot.get_current().send_message(call.message.chat.id, dedent(f""" - В этом разделе вы можете привязать бота @{bot.name} к чату. - Выберите чат, куда бот будет пересылать сообщения. - """), reply_markup=keyboard) -@dp.callback_query_handler(select_bot_chat.filter(), state="*") -@check_bot_owner async def chat_selected_callback(bot: Bot, call: types.CallbackQuery, callback_data: dict, state: FSMContext): """ Пользователь выбрал групповой чат для бота @@ -117,8 +46,6 @@ async def chat_selected_callback(bot: Bot, call: types.CallbackQuery, callback_d await call.answer(f"Выбран чат {chat.name}") -@dp.callback_query_handler(select_bot_chat_personal.filter(), state="*") -@check_bot_owner async def chat_selected_personal_callback(bot: Bot, call: types.CallbackQuery, callback_data: dict, state: FSMContext): """ Пользователь выбрал личный чат для бота @@ -128,8 +55,6 @@ async def chat_selected_personal_callback(bot: Bot, call: types.CallbackQuery, c await call.answer(f"Выбран личный чат") -@dp.callback_query_handler(bot_operation.filter(operation="text"), state="*") -@check_bot_owner async def text_bot_callback(bot: Bot, call: types.CallbackQuery, callback_data: dict, state: FSMContext): """ Кнопка "текст" для бота diff --git a/olgram/commands/bots.py b/olgram/commands/bots.py index 67d1fa2..7176571 100644 --- a/olgram/commands/bots.py +++ b/olgram/commands/bots.py @@ -8,9 +8,9 @@ from tortoise.exceptions import IntegrityError import re from textwrap import dedent -from .bot import select_bot from olgram.models.models import Bot, User from olgram.settings import OlgramSettings +from olgram.commands.menu import send_bots_menu from olgram.router import dp @@ -22,21 +22,7 @@ async def my_bots(message: types.Message, state: FSMContext): """ Команда /mybots (список ботов) """ - user = await User.get_or_none(telegram_id=message.from_user.id) - bots = await Bot.filter(owner=user) - if not bots: - await message.answer(dedent(""" - У вас нет добавленных ботов. - - Отправьте команду /addbot, чтобы добавить бот. - """)) - return - - keyboard = types.InlineKeyboardMarkup(row_width=2) - for bot in bots: - keyboard.insert(types.InlineKeyboardButton(text="@" + bot.name, callback_data=select_bot.new(bot_id=bot.id))) - - await message.answer("Ваши боты", reply_markup=keyboard) + return await send_bots_menu(message.chat.id, message.from_user.id) @dp.message_handler(commands=["addbot"], state="*") diff --git a/olgram/commands/menu.py b/olgram/commands/menu.py new file mode 100644 index 0000000..b2ed7d0 --- /dev/null +++ b/olgram/commands/menu.py @@ -0,0 +1,172 @@ +from olgram.router import dp + +from aiogram import types, Bot as AioBot +from olgram.models.models import Bot, User +from aiogram.dispatcher import FSMContext +from aiogram.utils.callback_data import CallbackData +from textwrap import dedent + + +menu_callback = CallbackData('menu', 'level', 'bot_id', 'operation', 'chat') + +empty = "0" + + +async def send_bots_menu(chat_id: int, user_id: int): + """ + Отправить пользователю список ботов + :return: + """ + user = await User.get_or_none(telegram_id=user_id) + bots = await Bot.filter(owner=user) + if not bots: + await AioBot.get_current().send_message(chat_id, dedent(""" + У вас нет добавленных ботов. + + Отправьте команду /addbot, чтобы добавить бот. + """)) + return + + keyboard = types.InlineKeyboardMarkup(row_width=2) + for bot in bots: + keyboard.insert( + types.InlineKeyboardButton(text="@" + bot.name, + callback_data=menu_callback.new(level=1, bot_id=bot.id, operation=empty, + chat=empty)) + ) + + await AioBot.get_current().send_message(chat_id, "Ваши боты", reply_markup=keyboard) + + +async def send_chats_menu(bot: Bot, call: types.CallbackQuery): + keyboard = types.InlineKeyboardMarkup(row_width=2) + + chats = await bot.group_chats.all() + + for chat in chats: + keyboard.insert( + types.InlineKeyboardButton(text=chat.name, + callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="chat", + chat=chat.id)) + ) + if chats: + keyboard.insert( + types.InlineKeyboardButton(text="Личные сообщения", + callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="chat", + chat="personal")) + ) + keyboard.insert( + types.InlineKeyboardButton(text="<< Назад", + callback_data=menu_callback.new(level=1, bot_id=bot.id, operation=empty, + chat=empty)) + ) + + if not chats: + text = dedent(f""" + Этот бот не добавлен в чаты, поэтому все сообщения будут приходить вам в бот. + Чтобы подключить чат — просто добавьте бот @{bot.name} в чат. + """) + else: + text = dedent(f""" + В этом разделе вы можете привязать бота @{bot.name} к чату. + Выберите чат, куда бот будет пересылать сообщения. + """) + + await AioBot.get_current().send_message(call.message.chat.id, text, reply_markup=keyboard) + + +async def send_bot_menu(bot: Bot, call: types.CallbackQuery): + keyboard = types.InlineKeyboardMarkup(row_width=2) + keyboard.insert( + types.InlineKeyboardButton(text="Текст", + callback_data=menu_callback.new(level=2, bot_id=bot.id, operation="text", chat=empty)) + ) + keyboard.insert( + types.InlineKeyboardButton(text="Чат", + callback_data=menu_callback.new(level=2, bot_id=bot.id, operation="chat", chat=empty)) + ) + keyboard.insert( + types.InlineKeyboardButton(text="Удалить бот", + callback_data=menu_callback.new(level=2, bot_id=bot.id, operation="delete", chat=empty)) + ) + keyboard.insert( + types.InlineKeyboardButton(text="<< Назад", + callback_data=menu_callback.new(level=0, bot_id=empty, operation=empty, chat=empty)) + ) + + await AioBot.get_current().send_message(call.message.chat.id, dedent(f""" + Управление ботом @{bot.name}. + + Если у вас возникли вопросы по настройке бота, то посмотрите нашу справку /help. + """), reply_markup=keyboard) + + +async def send_bot_delete_menu(bot: Bot, call: types.CallbackQuery): + keyboard = types.InlineKeyboardMarkup(row_width=2) + keyboard.insert( + types.InlineKeyboardButton(text="Да, удалить бот", + callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="delete_yes", + chat=empty)) + ) + keyboard.insert( + types.InlineKeyboardButton(text="<< Назад", + callback_data=menu_callback.new(level=1, bot_id=bot.id, operation=empty, chat=empty)) + ) + + await AioBot.get_current().send_message(call.message.chat.id, dedent(f""" + Вы уверены, что хотите удалить бота @{bot.name}? + """), reply_markup=keyboard) + + +async def send_bot_text_menu(bot: Bot, call: types.CallbackQuery): + keyboard = types.InlineKeyboardMarkup(row_width=2) + keyboard.insert( + types.InlineKeyboardButton(text="Сбросить текст", + callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="reset_text", + chat=empty)) + ) + keyboard.insert( + types.InlineKeyboardButton(text="<< Назад", + callback_data=menu_callback.new(level=1, bot_id=bot.id, operation=empty, chat=empty)) + ) + + text = dedent(""" + Сейчас вы редактируете текст, который отправляется после того, как пользователь отправит вашему боту + команду /start + + Текущий текст: + ``` + {0} + ``` + Отправьте сообщение, чтобы изменить текст. + """) + text = text.format(bot.start_text) + await AioBot.get_current().send_message(call.message.chat.id, text, reply_markup=keyboard, parse_mode="markdown") + + +@dp.callback_query_handler(menu_callback.filter(), state="*") +async def callback(call: types.CallbackQuery, callback_data: dict, state: FSMContext): + await call.answer() + + level = callback_data.get("level") + + if level == "0": + return await send_bots_menu(call.message.chat.id, call.from_user.id) + + bot_id = callback_data.get("bot_id") + bot = await Bot.get_or_none(id=bot_id) + if not bot or (await bot.owner).telegram_id != call.from_user.id: + await call.answer("У вас нет прав на этого бота", show_alert=True) + return + + if level == "1": + return await send_bot_menu(bot, call) + + operation = callback_data.get("operation") + if level == "2": + if operation == "chat": + return await send_chats_menu(bot, call) + if operation == "delete": + return await send_bot_delete_menu(bot, call) + if operation == "text": + return await send_bot_text_menu(bot, call)