Template
mirror of
https://github.com/djimboy/djimbo_template_aio3.git
synced 2026-08-26 23:17:43 +00:00
Update aiogram 3 template
This commit is contained in:
+20
-17
@@ -1,30 +1,33 @@
|
||||
# - *- coding: utf- 8 - *-
|
||||
from aiogram import Dispatcher, F
|
||||
from aiogram import Dispatcher
|
||||
|
||||
from tgbot.routers import main_errors, main_missed, main_start
|
||||
from tgbot.routers.admin import admin_menu
|
||||
from tgbot.routers.user import user_menu
|
||||
from tgbot.utils.misc.bot_filters import IsAdmin
|
||||
from tgbot.utils.misc.bot_filters import IsAdmin, IsPrivate
|
||||
|
||||
|
||||
# Register all routers
|
||||
# Подключение всех роутеров
|
||||
def register_all_routers(dp: Dispatcher):
|
||||
# Connect filters
|
||||
main_errors.router.message.filter(F.chat.type == "private")
|
||||
main_start.router.message.filter(F.chat.type == "private")
|
||||
# Общие фильтры для приватных чатов
|
||||
main_errors.router.message.filter(IsPrivate())
|
||||
main_start.router.message.filter(IsPrivate())
|
||||
|
||||
user_menu.router.message.filter(F.chat.type == "private")
|
||||
admin_menu.router.message.filter(F.chat.type == "private", IsAdmin())
|
||||
user_menu.router.message.filter(IsPrivate())
|
||||
user_menu.router.callback_query.filter(IsPrivate())
|
||||
admin_menu.router.message.filter(IsPrivate(), IsAdmin())
|
||||
admin_menu.router.callback_query.filter(IsPrivate(), IsAdmin())
|
||||
|
||||
main_missed.router.message.filter(F.chat.type == "private")
|
||||
main_missed.router.message.filter(IsPrivate())
|
||||
main_missed.router.callback_query.filter(IsPrivate())
|
||||
|
||||
# Connect needed routers
|
||||
dp.include_router(main_errors.router) # Router - error
|
||||
dp.include_router(main_start.router) # Router - main
|
||||
# Базовые роутеры, которые нужны всегда
|
||||
dp.include_router(main_errors.router) # Ошибки
|
||||
dp.include_router(main_start.router) # Старт и главное меню
|
||||
|
||||
# Connect usebles routers (users и admins)
|
||||
dp.include_router(user_menu.router) # Router - user
|
||||
dp.include_router(admin_menu.router) # Router - admin
|
||||
# Роутеры для пользователей и админов
|
||||
dp.include_router(user_menu.router) # Пользовательские обработчики
|
||||
dp.include_router(admin_menu.router) # Админские обработчики
|
||||
|
||||
# Connect needed routers
|
||||
dp.include_router(main_missed.router) # Router - missed handlers
|
||||
# Обработка всего, что не поймали выше
|
||||
dp.include_router(main_missed.router) # Пропущенные сообщения и колбэки
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# - *- coding: utf- 8 - *-
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import aiofiles
|
||||
from aiogram import Router, Bot, F
|
||||
@@ -7,87 +7,105 @@ from aiogram.filters import Command
|
||||
from aiogram.types import FSInputFile, Message, CallbackQuery
|
||||
from aiogram.utils.media_group import MediaGroupBuilder
|
||||
|
||||
from tgbot.data.config import PATH_DATABASE, PATH_LOGS
|
||||
from tgbot.database.db_users import BaseModel as UserModel
|
||||
from tgbot.data.config import BOT_DATABASE_EXPORT, PATH_DATABASE, PATH_LOGS
|
||||
from tgbot.database.db_users import UserModel
|
||||
from tgbot.keyboards.inline_main import admin_finl
|
||||
from tgbot.utils.const_functions import get_date
|
||||
from tgbot.utils.misc.bot_models import FSM, ARS
|
||||
|
||||
router = Router(name=__name__)
|
||||
LOGS_DIR = Path(PATH_LOGS).parent
|
||||
SERVICE_LOG_FILES = (
|
||||
LOGS_DIR / "sv_log_err.log",
|
||||
LOGS_DIR / "sv_log_out.log",
|
||||
)
|
||||
|
||||
|
||||
# Message - Admin button
|
||||
@router.message(F.text == 'Admin button')
|
||||
# Кнопка админского меню
|
||||
@router.message(F.text == 'Админ-меню')
|
||||
async def admin_button_inline(message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel):
|
||||
await state.clear()
|
||||
|
||||
await message.answer(
|
||||
"Inline admin keyboards",
|
||||
"Инлайн-клавиатура админа",
|
||||
reply_markup=admin_finl()
|
||||
)
|
||||
|
||||
|
||||
# Callback - Admin X
|
||||
# Колбэк для демо-действия админа
|
||||
@router.callback_query(F.data == 'admin_inline_x')
|
||||
async def admin_callback_inline_x(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS, User: UserModel):
|
||||
await call.answer(f"Click Admin X")
|
||||
await call.answer("Админское действие выполнено")
|
||||
|
||||
|
||||
# Callback - Admin
|
||||
# Колбэк с параметром из админской кнопки
|
||||
@router.callback_query(F.data.startswith('admin_inline:'))
|
||||
async def admin_callback_inline(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS, User: UserModel):
|
||||
get_data = call.data.split(":")[1]
|
||||
|
||||
await call.answer(f"Click Admin - {get_data}", True)
|
||||
await call.answer(f"Выбран админский раздел: {get_data}", True)
|
||||
|
||||
|
||||
# Get Database file
|
||||
# Отправка файла базы админам
|
||||
@router.message(Command(commands=['db', 'database']))
|
||||
async def admin_database(message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel):
|
||||
await state.clear()
|
||||
|
||||
if not BOT_DATABASE_EXPORT:
|
||||
await message.answer("<b>📦 Экспорт базы данных отключён в настройках</b>")
|
||||
return
|
||||
|
||||
if not Path(PATH_DATABASE).is_file():
|
||||
await message.answer("<b>📦 Файл базы данных не найден</b>")
|
||||
return
|
||||
|
||||
await message.answer_document(
|
||||
FSInputFile(PATH_DATABASE),
|
||||
caption=f"<b>📦 #BACKUP | <code>{get_date()}</code></b>",
|
||||
caption=f"<b>📦 #БЭКАП | <code>{get_date()}</code></b>",
|
||||
)
|
||||
|
||||
|
||||
# Get Logs file
|
||||
# Отправка логов админам
|
||||
@router.message(Command(commands=['log', 'logs']))
|
||||
async def admin_log(message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel):
|
||||
await state.clear()
|
||||
|
||||
media_group = MediaGroupBuilder(
|
||||
caption=f"<b>🖨 #LOGS | <code>{get_date(full=False)}</code></b>",
|
||||
)
|
||||
log_files = []
|
||||
|
||||
if os.path.isfile(PATH_LOGS):
|
||||
media_group.add_document(media=FSInputFile(PATH_LOGS))
|
||||
if Path(PATH_LOGS).is_file():
|
||||
log_files.append(PATH_LOGS)
|
||||
|
||||
if os.path.isfile("tgbot/data/sv_log_err.log"):
|
||||
media_group.add_document(media=FSInputFile("tgbot/data/sv_log_err.log"))
|
||||
for log_file in SERVICE_LOG_FILES:
|
||||
if log_file.is_file():
|
||||
log_files.append(str(log_file))
|
||||
|
||||
if os.path.isfile("tgbot/data/sv_log_out.log"):
|
||||
media_group.add_document(media=FSInputFile("tgbot/data/sv_log_out.log"))
|
||||
caption = f"<b>🖨 #ЛОГИ | <code>{get_date(full=False)}</code></b>"
|
||||
|
||||
await message.answer_media_group(media=media_group.build())
|
||||
if len(log_files) == 0:
|
||||
await message.answer("<b>🖨 Логи не найдены</b>")
|
||||
elif len(log_files) == 1:
|
||||
await message.answer_document(FSInputFile(log_files[0]), caption=caption)
|
||||
else:
|
||||
media_group = MediaGroupBuilder(caption=caption)
|
||||
|
||||
for log_file in log_files:
|
||||
media_group.add_document(media=FSInputFile(log_file))
|
||||
|
||||
await message.answer_media_group(media=media_group.build())
|
||||
|
||||
|
||||
# Clear logs file
|
||||
# Очистка файлов логов
|
||||
@router.message(Command(commands=['clear_log', 'clear_logs', 'log_clear', 'logs_clear']))
|
||||
async def admin_logs_clear(message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel):
|
||||
await state.clear()
|
||||
|
||||
if os.path.isfile(PATH_LOGS):
|
||||
async with aiofiles.open(PATH_LOGS, "w") as file:
|
||||
await file.write(f"{get_date()} | LOGS WAS CLEAR")
|
||||
log_files = [Path(PATH_LOGS), *SERVICE_LOG_FILES]
|
||||
|
||||
if os.path.isfile("tgbot/data/sv_log_err.log"):
|
||||
async with aiofiles.open("tgbot/data/sv_log_err.log", "w") as file:
|
||||
await file.write(f"{get_date()} | LOGS WAS CLEAR")
|
||||
for log_file in log_files:
|
||||
if not log_file.is_file():
|
||||
continue
|
||||
|
||||
if os.path.isfile("tgbot/data/sv_log_out.log"):
|
||||
async with aiofiles.open("tgbot/data/sv_log_out.log", "w") as file:
|
||||
await file.write(f"{get_date()} | LOGS WAS CLEAR")
|
||||
async with aiofiles.open(log_file, "w", encoding="utf-8") as file:
|
||||
await file.write(f"{get_date()} | ЛОГИ ОЧИЩЕНЫ")
|
||||
|
||||
await message.answer("<b>🖨 The logs have been cleared</b>")
|
||||
await message.answer("<b>🖨 Логи очищены</b>")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# - *- coding: utf- 8 - *-
|
||||
from aiogram import Router
|
||||
from aiogram.filters import ExceptionMessageFilter
|
||||
from aiogram.exceptions import TelegramBadRequest
|
||||
from aiogram.filters import ExceptionTypeFilter
|
||||
from aiogram.handlers import ErrorHandler
|
||||
|
||||
from tgbot.utils.misc.bot_logging import bot_logger
|
||||
@@ -8,22 +9,19 @@ from tgbot.utils.misc.bot_logging import bot_logger
|
||||
router = Router(name=__name__)
|
||||
|
||||
|
||||
# Error with block forbidden user
|
||||
# Ошибка при отправке сообщения пользователю, который заблокировал бота
|
||||
# @router.errors(ExceptionTypeFilter(TelegramForbiddenError))
|
||||
# class MyHandler(ErrorHandler):
|
||||
# class ForbiddenErrorHandler(ErrorHandler):
|
||||
# async def handle(self):
|
||||
# ...
|
||||
|
||||
|
||||
# Error with edit duplicate message
|
||||
@router.errors(ExceptionMessageFilter(
|
||||
"Bad Request: message is not modified: specified new message content and reply markup are exactly the same as a current content and reply markup of the message")
|
||||
)
|
||||
class MyHandler(ErrorHandler):
|
||||
# Безопасно игнорируем повторное редактирование сообщения без изменений
|
||||
@router.errors(ExceptionTypeFilter(TelegramBadRequest))
|
||||
class MessageNotModifiedHandler(ErrorHandler):
|
||||
async def handle(self):
|
||||
bot_logger.exception(
|
||||
f"====================\n"
|
||||
f"Exception name: {self.exception_name}\n"
|
||||
f"Exception message: {self.exception_message}\n"
|
||||
f"===================="
|
||||
)
|
||||
if "message is not modified" in self.exception_message.lower():
|
||||
bot_logger.debug("Telegram отклонил повторное редактирование сообщения без изменений")
|
||||
return True
|
||||
|
||||
raise self.event
|
||||
|
||||
@@ -9,28 +9,28 @@ from tgbot.utils.misc.bot_models import FSM, ARS
|
||||
router = Router(name=__name__)
|
||||
|
||||
|
||||
# Callback with delete message
|
||||
# Колбэк для удаления текущего сообщения
|
||||
@router.callback_query(F.data == 'close_this')
|
||||
async def main_callback_close(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS, User: ModelUsers):
|
||||
await del_message(call.message)
|
||||
|
||||
|
||||
# Callback with processing miss button
|
||||
# Колбэк-заглушка для пустых кнопок
|
||||
@router.callback_query(F.data == '...')
|
||||
async def main_callback_answer(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS, User: ModelUsers):
|
||||
await call.answer(cache_time=30)
|
||||
|
||||
|
||||
# Callback with processing miss callback data
|
||||
# Ответ на колбэк, который никто не обработал
|
||||
@router.callback_query()
|
||||
async def main_callback_missed(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS, User: ModelUsers):
|
||||
await call.answer(f"❗️ Miss callback: {call.data}", True)
|
||||
await call.answer(f"❗️ Неизвестный колбэк: {call.data}", True)
|
||||
|
||||
|
||||
# Processing all unknowns callback datas
|
||||
# Ответ на неизвестные сообщения
|
||||
@router.message()
|
||||
async def main_message_missed(message: Message, bot: Bot, state: FSM, arSession: ARS, User: ModelUsers):
|
||||
await message.answer(
|
||||
"♦️ Unknown command.\n"
|
||||
"♦️ Enter /start",
|
||||
"♦️ Неизвестная команда\n"
|
||||
"♦️ Введите /start",
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@ from aiogram import Router, Bot, F
|
||||
from aiogram.filters import Command
|
||||
from aiogram.types import Message
|
||||
|
||||
from tgbot.database.db_users import BaseModel as UserModel
|
||||
from tgbot.database.db_users import UserModel
|
||||
from tgbot.keyboards.reply_main import menu_frep
|
||||
from tgbot.utils.const_functions import ded
|
||||
from tgbot.utils.misc.bot_models import FSM, ARS
|
||||
@@ -11,7 +11,7 @@ from tgbot.utils.misc.bot_models import FSM, ARS
|
||||
router = Router(name=__name__)
|
||||
|
||||
|
||||
# Main menu
|
||||
# Главное меню пользователя
|
||||
@router.message(F.text.in_(('menu', 'return', 'start')))
|
||||
@router.message(Command(commands=['start']))
|
||||
async def main_start(message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel):
|
||||
@@ -19,8 +19,8 @@ async def main_start(message: Message, bot: Bot, state: FSM, arSession: ARS, Use
|
||||
|
||||
await message.answer(
|
||||
ded(f"""
|
||||
🔸 Hello, {User.user_name}
|
||||
🔸 Enter /start or /menu
|
||||
🔸 Привет, {User.user_name}
|
||||
🔸 Введи /start или /menu
|
||||
"""),
|
||||
reply_markup=menu_frep(message.from_user.id),
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@ from aiogram import Router, Bot, F
|
||||
from aiogram.filters import Command
|
||||
from aiogram.types import Message, CallbackQuery
|
||||
|
||||
from tgbot.database.db_users import BaseModel as UserModel
|
||||
from tgbot.database.db_users import UserModel
|
||||
from tgbot.keyboards.inline_main import user_finl
|
||||
from tgbot.keyboards.reply_main import menu_frep
|
||||
from tgbot.utils.misc.bot_models import FSM, ARS
|
||||
@@ -11,37 +11,37 @@ from tgbot.utils.misc.bot_models import FSM, ARS
|
||||
router = Router(name=__name__)
|
||||
|
||||
|
||||
# Message - User button
|
||||
@router.message(F.text == 'User button')
|
||||
# Кнопка пользовательского меню
|
||||
@router.message(F.text == 'Пользовательское меню')
|
||||
async def user_button_inline(message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel):
|
||||
await state.clear()
|
||||
|
||||
await message.answer(
|
||||
"Inline user keyboards",
|
||||
"Инлайн-клавиатура пользователя",
|
||||
reply_markup=user_finl()
|
||||
)
|
||||
|
||||
|
||||
# Command - /menu
|
||||
# Команда возврата в меню
|
||||
@router.message(Command(commands="menu"))
|
||||
async def user_command_menu(message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel):
|
||||
await state.clear()
|
||||
|
||||
await message.answer(
|
||||
"Enter command - /menu",
|
||||
"Команда /menu открывает главное меню",
|
||||
reply_markup=menu_frep(message.from_user.id),
|
||||
)
|
||||
|
||||
|
||||
# Callback - User X
|
||||
# Колбэк для демо-действия
|
||||
@router.callback_query(F.data == 'user_inline_x')
|
||||
async def user_callback_inline_x(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS, User: UserModel):
|
||||
await call.answer(f"Click User X")
|
||||
await call.answer("Действие выполнено")
|
||||
|
||||
|
||||
# Callback - User
|
||||
# Колбэк с параметром из пользовательской кнопки
|
||||
@router.callback_query(F.data.startswith('user_inline:'))
|
||||
async def user_callback_inline(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS, User: UserModel):
|
||||
get_data = call.data.split(":")[1]
|
||||
|
||||
await call.answer(f"Click User - {get_data}", True)
|
||||
await call.answer(f"Выбран раздел: {get_data}", True)
|
||||
|
||||
Reference in New Issue
Block a user