style: reformat imports, whitespace and line breaks across project

This commit is contained in:
2026-07-30 16:18:15 +05:00
parent c3ad9a9918
commit ecc006287b
13 changed files with 118 additions and 101 deletions
+6 -1
View File
@@ -4,7 +4,12 @@ from contextlib import AbstractAsyncContextManager, asynccontextmanager
from pathlib import Path from pathlib import Path
from sqlalchemy import event from sqlalchemy import event
from sqlalchemy.ext.asyncio import AsyncAttrs, AsyncSession, async_sessionmaker, create_async_engine from sqlalchemy.ext.asyncio import (
AsyncAttrs,
AsyncSession,
async_sessionmaker,
create_async_engine,
)
from sqlalchemy.orm import DeclarativeBase from sqlalchemy.orm import DeclarativeBase
from tgbot.data.config import PATH_DATABASE from tgbot.data.config import PATH_DATABASE
+18 -14
View File
@@ -13,8 +13,12 @@ from tgbot.utils.const_functions import get_unix
class UserModel(Base): class UserModel(Base):
__tablename__ = "storage_users" __tablename__ = "storage_users"
increment: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) increment: Mapped[int] = mapped_column(
user_id: Mapped[int] = mapped_column(BigInteger, nullable=False, unique=True, index=True) Integer, primary_key=True, autoincrement=True
)
user_id: Mapped[int] = mapped_column(
BigInteger, nullable=False, unique=True, index=True
)
user_login: Mapped[str] = mapped_column(String(255), nullable=False, default="") user_login: Mapped[str] = mapped_column(String(255), nullable=False, default="")
user_name: Mapped[str] = mapped_column(String(255), nullable=False, default="") user_name: Mapped[str] = mapped_column(String(255), nullable=False, default="")
user_surname: Mapped[str] = mapped_column(String(255), nullable=False, default="") user_surname: Mapped[str] = mapped_column(String(255), nullable=False, default="")
@@ -35,12 +39,12 @@ class UsersRepository(BaseRepository[UserModel]):
# Для совместимости add ведет себя как upsert # Для совместимости add ведет себя как upsert
async def add( async def add(
self, self,
user_id: int, user_id: int,
user_login: str, user_login: str,
user_name: str, user_name: str,
user_surname: str, user_surname: str,
user_fullname: str, user_fullname: str,
) -> UserModel: ) -> UserModel:
return await self.upsert( return await self.upsert(
user_id=user_id, user_id=user_id,
@@ -52,12 +56,12 @@ class UsersRepository(BaseRepository[UserModel]):
# Создание пользователя или обновление его данных по user_id # Создание пользователя или обновление его данных по user_id
async def upsert( async def upsert(
self, self,
user_id: int, user_id: int,
user_login: str, user_login: str,
user_name: str, user_name: str,
user_surname: str, user_surname: str,
user_fullname: str, user_fullname: str,
) -> UserModel: ) -> UserModel:
statement = insert(UserModel).values( statement = insert(UserModel).values(
user_id=user_id, user_id=user_id,
+4 -4
View File
@@ -83,9 +83,7 @@ class BaseRepository(Generic[ModelTranslator]):
async with session_scope() as session: async with session_scope() as session:
await session.execute( await session.execute(
sqlalchemy_update(model) sqlalchemy_update(model).filter_by(**filters).values(**kwargs)
.filter_by(**filters)
.values(**kwargs)
) )
@@ -101,6 +99,8 @@ async def prepare_database() -> None:
try: try:
await SettingsRepository().ensure_default() await SettingsRepository().ensure_default()
except SQLAlchemyError as error: except SQLAlchemyError as error:
raise RuntimeError("База данных не готова. Запусти миграции командой: python migrate.py") from error raise RuntimeError(
"База данных не готова. Запусти миграции командой: python migrate.py"
) from error
bot_logger.info("База данных готова") bot_logger.info("База данных готова")
+20 -12
View File
@@ -19,7 +19,12 @@ class ThrottlingMiddleware(BaseMiddleware):
self.message_users = TTLCache(maxsize=10_000, ttl=600) self.message_users = TTLCache(maxsize=10_000, ttl=600)
self.callback_users = TTLCache(maxsize=10_000, ttl=600) self.callback_users = TTLCache(maxsize=10_000, ttl=600)
async def __call__(self, handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]], event: TelegramObject, data): async def __call__(
self,
handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]],
event: TelegramObject,
data,
):
# Если юзер спамит, постепенно увеличиваем паузу # Если юзер спамит, постепенно увеличиваем паузу
this_user: Optional[User] = data.get("event_from_user") this_user: Optional[User] = data.get("event_from_user")
@@ -38,28 +43,31 @@ class ThrottlingMiddleware(BaseMiddleware):
if user_key not in bucket: if user_key not in bucket:
bucket[user_key] = { bucket[user_key] = {
'last_throttled': now_time, "last_throttled": now_time,
'count_throttled': 0, "count_throttled": 0,
'now_rate': rate, "now_rate": rate,
} }
return await handler(event, data) return await handler(event, data)
else: else:
if now_time - bucket[user_key]['last_throttled'] >= bucket[user_key]['now_rate']: if (
now_time - bucket[user_key]["last_throttled"]
>= bucket[user_key]["now_rate"]
):
bucket.pop(user_key) bucket.pop(user_key)
return await handler(event, data) return await handler(event, data)
else: else:
bucket[user_key]['last_throttled'] = now_time bucket[user_key]["last_throttled"] = now_time
bucket[user_key]['count_throttled'] += 1 bucket[user_key]["count_throttled"] += 1
if bucket[user_key]['count_throttled'] == 1: if bucket[user_key]["count_throttled"] == 1:
bucket[user_key]['now_rate'] = rate + 2 bucket[user_key]["now_rate"] = rate + 2
await self._warn_user(event) await self._warn_user(event)
elif bucket[user_key]['count_throttled'] == 2: elif bucket[user_key]["count_throttled"] == 2:
bucket[user_key]['now_rate'] = rate + 3 bucket[user_key]["now_rate"] = rate + 3
else: else:
bucket[user_key]['now_rate'] = rate + 5 bucket[user_key]["now_rate"] = rate + 5
return None return None
+9 -5
View File
@@ -23,11 +23,15 @@ class ExistsUserMiddleware(BaseMiddleware):
user_surname = clear_html(this_user.last_name) user_surname = clear_html(this_user.last_name)
user_fullname = clear_html(this_user.first_name) user_fullname = clear_html(this_user.first_name)
if user_name is None: user_name = "" if user_name is None:
if user_surname is None: user_surname = "" user_name = ""
if user_fullname is None: user_fullname = "" if user_surname is None:
user_surname = ""
if user_fullname is None:
user_fullname = ""
if len(user_surname) >= 1: user_fullname += f" {user_surname}" if len(user_surname) >= 1:
user_fullname += f" {user_surname}"
user_data = ( user_data = (
user_login.lower(), user_login.lower(),
@@ -50,6 +54,6 @@ class ExistsUserMiddleware(BaseMiddleware):
else: else:
user = cached_user["user"] user = cached_user["user"]
data['User'] = user data["User"] = user
return await handler(event, data) return await handler(event, data)
+1
View File
@@ -15,6 +15,7 @@ def register_all_routers(dp: Dispatcher):
user_menu.router.message.filter(IsPrivate()) user_menu.router.message.filter(IsPrivate())
user_menu.router.callback_query.filter(IsPrivate()) user_menu.router.callback_query.filter(IsPrivate())
admin_menu.router.message.filter(IsPrivate(), IsAdmin()) admin_menu.router.message.filter(IsPrivate(), IsAdmin())
admin_menu.router.callback_query.filter(IsPrivate(), IsAdmin()) admin_menu.router.callback_query.filter(IsPrivate(), IsAdmin())
+19 -26
View File
@@ -22,33 +22,20 @@ SERVICE_LOG_FILES = (
# Кнопка админского меню # Кнопка админского меню
@router.message(F.text == 'Админ-меню') @router.message(F.text == "Админ-меню")
async def admin_button_inline(message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel): async def admin_button_inline(
message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel
):
await state.clear() await state.clear()
await message.answer( await message.answer("Инлайн-клавиатура админа", reply_markup=admin_finl())
"Инлайн-клавиатура админа",
reply_markup=admin_finl()
)
# Колбэк для демо-действия админа
@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("Админское действие выполнено")
# Колбэк с параметром из админской кнопки
@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"Выбран админский раздел: {get_data}", True)
# Отправка файла базы админам # Отправка файла базы админам
@router.message(Command(commands=['db', 'database'])) @router.message(Command(commands=["db", "database"]))
async def admin_database(message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel): async def admin_database(
message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel
):
await state.clear() await state.clear()
if not BOT_DATABASE_EXPORT: if not BOT_DATABASE_EXPORT:
@@ -66,8 +53,10 @@ async def admin_database(message: Message, bot: Bot, state: FSM, arSession: ARS,
# Отправка логов админам # Отправка логов админам
@router.message(Command(commands=['log', 'logs'])) @router.message(Command(commands=["log", "logs"]))
async def admin_log(message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel): async def admin_log(
message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel
):
await state.clear() await state.clear()
log_files = [] log_files = []
@@ -95,8 +84,12 @@ async def admin_log(message: Message, bot: Bot, state: FSM, arSession: ARS, User
# Очистка файлов логов # Очистка файлов логов
@router.message(Command(commands=['clear_log', 'clear_logs', 'log_clear', 'logs_clear'])) @router.message(
async def admin_logs_clear(message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel): 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() await state.clear()
log_files = [Path(PATH_LOGS), *SERVICE_LOG_FILES] log_files = [Path(PATH_LOGS), *SERVICE_LOG_FILES]
+3 -1
View File
@@ -21,7 +21,9 @@ router = Router(name=__name__)
class MessageNotModifiedHandler(ErrorHandler): class MessageNotModifiedHandler(ErrorHandler):
async def handle(self): async def handle(self):
if "message is not modified" in self.exception_message.lower(): if "message is not modified" in self.exception_message.lower():
bot_logger.debug("Telegram отклонил повторное редактирование сообщения без изменений") bot_logger.debug(
"Telegram отклонил повторное редактирование сообщения без изменений"
)
return True return True
raise self.event raise self.event
+15 -8
View File
@@ -10,27 +10,34 @@ router = Router(name=__name__)
# Колбэк для удаления текущего сообщения # Колбэк для удаления текущего сообщения
@router.callback_query(F.data == 'close_this') @router.callback_query(F.data == "close_this")
async def main_callback_close(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS, User: ModelUsers): async def main_callback_close(
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS, User: ModelUsers
):
await del_message(call.message) await del_message(call.message)
# Колбэк-заглушка для пустых кнопок # Колбэк-заглушка для пустых кнопок
@router.callback_query(F.data == '...') @router.callback_query(F.data == "...")
async def main_callback_answer(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS, User: ModelUsers): async def main_callback_answer(
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS, User: ModelUsers
):
await call.answer(cache_time=30) await call.answer(cache_time=30)
# Ответ на колбэк, который никто не обработал # Ответ на колбэк, который никто не обработал
@router.callback_query() @router.callback_query()
async def main_callback_missed(call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS, User: ModelUsers): async def main_callback_missed(
call: CallbackQuery, bot: Bot, state: FSM, arSession: ARS, User: ModelUsers
):
await call.answer(f"❗️ Неизвестный колбэк: {call.data}", True) await call.answer(f"❗️ Неизвестный колбэк: {call.data}", True)
# Ответ на неизвестные сообщения # Ответ на неизвестные сообщения
@router.message() @router.message()
async def main_message_missed(message: Message, bot: Bot, state: FSM, arSession: ARS, User: ModelUsers): async def main_message_missed(
message: Message, bot: Bot, state: FSM, arSession: ARS, User: ModelUsers
):
await message.answer( await message.answer(
"♦️ Неизвестная команда\n" "♦️ Неизвестная команда\n" "♦️ Введите /start",
"♦️ Введите /start",
) )
+5 -3
View File
@@ -12,9 +12,11 @@ router = Router(name=__name__)
# Главное меню пользователя # Главное меню пользователя
@router.message(F.text.in_(('menu', 'return', 'start'))) # @router.message(F.text.in_(("menu", "return", "start")))
@router.message(Command(commands=['start'])) # @router.message(Command(commands=["start"]))
async def main_start(message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel): async def main_start(
message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel
):
await state.clear() await state.clear()
await message.answer( await message.answer(
+9 -22
View File
@@ -12,36 +12,23 @@ router = Router(name=__name__)
# Кнопка пользовательского меню # Кнопка пользовательского меню
@router.message(F.text == 'Пользовательское меню') # @router.message(F.text == "Пользовательское меню")
async def user_button_inline(message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel): async def user_button_inline(
message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel
):
await state.clear() await state.clear()
await message.answer( await message.answer("Инлайн-клавиатура пользователя", reply_markup=user_finl())
"Инлайн-клавиатура пользователя",
reply_markup=user_finl()
)
# Команда возврата в меню # Команда возврата в меню
@router.message(Command(commands="menu")) # @router.message(Command(commands="menu"))
async def user_command_menu(message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel): async def user_command_menu(
message: Message, bot: Bot, state: FSM, arSession: ARS, User: UserModel
):
await state.clear() await state.clear()
await message.answer( await message.answer(
"Команда /menu открывает главное меню", "Команда /menu открывает главное меню",
reply_markup=menu_frep(message.from_user.id), reply_markup=menu_frep(message.from_user.id),
) )
# Колбэк для демо-действия
@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("Действие выполнено")
# Колбэк с параметром из пользовательской кнопки
@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"Выбран раздел: {get_data}", True)
+1 -1
View File
@@ -3,12 +3,12 @@ from typing import Optional
import aiohttp import aiohttp
# Пример использования в обработчике # Пример использования в обработчике
# session = await arSession.get_session() # session = await arSession.get_session()
# response = await session.get(...) # response = await session.get(...)
# response = await session.post(...) # response = await session.post(...)
# Асинхронная сессия для запросов # Асинхронная сессия для запросов
class AsyncRequestSession: class AsyncRequestSession:
def __init__(self, timeout: int = 30) -> None: def __init__(self, timeout: int = 30) -> None:
+8 -4
View File
@@ -8,13 +8,13 @@ from tgbot.utils.misc.bot_logging import bot_logger
# Команды для обычных пользователей # Команды для обычных пользователей
user_commands = [ user_commands = [
BotCommand(command="start", description="♻️ Перезапуск бота"), BotCommand(command="start", description="♻️ Перезапуск бота"),
BotCommand(command="menu", description="🌀 Получение клавиатуры"), # BotCommand(command="menu", description="🌀 Получение клавиатуры"),
] ]
# Команды для админов # Команды для админов
admin_commands = [ admin_commands = [
BotCommand(command="start", description="♻️ Перезапуск бота"), BotCommand(command="start", description="♻️ Перезапуск бота"),
BotCommand(command="menu", description="🌀 Получение клавиатуры"), # BotCommand(command="menu", description="🌀 Получение клавиатуры"),
BotCommand(command="log", description="🖨 Получить логи"), BotCommand(command="log", description="🖨 Получить логи"),
] ]
@@ -28,6 +28,10 @@ async def set_commands(bot: Bot):
for admin in get_admins(): for admin in get_admins():
try: try:
await bot.set_my_commands(admin_commands, scope=BotCommandScopeChat(chat_id=admin)) await bot.set_my_commands(
admin_commands, scope=BotCommandScopeChat(chat_id=admin)
)
except Exception: except Exception:
bot_logger.warning("Не удалось обновить команды для админа %s", admin, exc_info=True) bot_logger.warning(
"Не удалось обновить команды для админа %s", admin, exc_info=True
)