Улучшение обработки пользователей и middleware с возвратом данных

- Модифицирована функция upsert_user для возврата полных данных пользователя
- Обновлен UserMiddleware для сохранения данных пользователя в контексте
- Расширена функциональность register_middleware с поддержкой опционального исключения middleware
- Добавлена типизация и улучшена обработка middleware
This commit is contained in:
izzzzzi
2025-02-25 02:46:59 +05:00
parent b08040f46b
commit 968c258029
3 changed files with 76 additions and 17 deletions
+13 -2
View File
@@ -1081,7 +1081,7 @@ async def upsert_user(
language_code: str = None,
is_bot: bool = False,
session: Any = None,
):
) -> dict:
"""
Обновляет или вставляет информацию о пользователе в базу данных.
@@ -1094,6 +1094,9 @@ async def upsert_user(
is_bot (bool, optional): Флаг, указывающий является ли пользователь ботом
session (Any, optional): Существующая сессия базы данных
Returns:
dict: Словарь с информацией о пользователе после обновления/вставки
Raises:
Exception: В случае ошибки при работе с базой данных
"""
@@ -1110,7 +1113,8 @@ async def upsert_user(
close_conn = True
logger.info(f"Установлено новое подключение к базе данных для обновления пользователя {tg_id}")
await conn.execute(
# Выполняем вставку/обновление и сразу получаем обновленные данные
user_data = await conn.fetchrow(
"""
INSERT INTO users (tg_id, username, first_name, last_name, language_code, is_bot, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $6, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
@@ -1122,6 +1126,9 @@ async def upsert_user(
language_code = COALESCE(EXCLUDED.language_code, users.language_code),
is_bot = EXCLUDED.is_bot,
updated_at = CURRENT_TIMESTAMP
RETURNING
id, tg_id, username, first_name, last_name, language_code,
is_bot, created_at, updated_at
""",
tg_id,
username,
@@ -1130,7 +1137,11 @@ async def upsert_user(
language_code,
is_bot,
)
logger.debug(f"Успешно обновлена информация о пользователе {tg_id}")
# Преобразуем результат в словарь
return dict(user_data)
except Exception as e:
logger.error(f"Ошибка при обновлении информации о пользователе {tg_id}: {e}")
raise
+49 -12
View File
@@ -1,6 +1,7 @@
from typing import Any
from typing import Any, Iterable, Optional, Type, Union
from aiogram import Dispatcher
from aiogram.dispatcher.middlewares.base import BaseMiddleware
from .admin import AdminMiddleware
from .loggings import LoggingMiddleware
@@ -9,16 +10,52 @@ from .throttling import ThrottlingMiddleware
from .user import UserMiddleware
def register_middleware(dispatcher: Dispatcher) -> None:
middlewares = [
AdminMiddleware(),
SessionMiddleware(),
LoggingMiddleware(),
ThrottlingMiddleware(),
UserMiddleware(),
def register_middleware(
dispatcher: Dispatcher,
middlewares: Optional[Iterable[Union[BaseMiddleware, Type[BaseMiddleware]]]] = None,
exclude: Optional[Iterable[str]] = None,
) -> None:
"""Регистрирует middleware в диспетчере.
Args:
dispatcher: Экземпляр диспетчера Aiogram
middlewares: Опциональный список middleware для регистрации.
Если не указан, регистрируются все стандартные middleware.
exclude: Опциональный список имен middleware, которые нужно исключить из регистрации.
Применяется только если middlewares не указан.
"""
# Если middleware не указаны, используем стандартный набор
if middlewares is None:
# Словарь всех доступных middleware
available_middlewares = {
"admin": AdminMiddleware(),
"session": SessionMiddleware(),
"logging": LoggingMiddleware(),
"throttling": ThrottlingMiddleware(),
"user": UserMiddleware(),
}
# Фильтруем middleware по списку исключений
exclude_set = set(exclude or [])
middlewares = [
middleware
for name, middleware in available_middlewares.items()
if name not in exclude_set
]
# Регистрируем middleware для всех типов обработчиков
handlers = [
dispatcher.message,
dispatcher.callback_query,
dispatcher.inline_query,
# Можно добавить другие типы обработчиков при необходимости
]
# Регистрируем каждый middleware для каждого типа обработчика
for middleware in middlewares:
dispatcher.message.outer_middleware(middleware)
dispatcher.callback_query.outer_middleware(middleware)
dispatcher.inline_query.outer_middleware(middleware)
# Если передан класс, а не экземпляр, создаем экземпляр
if isinstance(middleware, type):
middleware = middleware()
for handler in handlers:
handler.outer_middleware(middleware)
+14 -3
View File
@@ -25,7 +25,11 @@ class UserMiddleware(BaseMiddleware):
if user := data.get("event_from_user"):
# Получаем сессию из контекста, если она есть
session = data.get("session")
await self._process_user(user, session)
# Обрабатываем пользователя и получаем его данные из БД
db_user = await self._process_user(user, session)
# Добавляем данные пользователя из БД в контекст
if db_user:
data["user"] = db_user
except Exception as e:
# Логируем ошибку, но не прерываем обработку события
logger.error(f"Ошибка при обработке пользователя: {e}")
@@ -33,16 +37,20 @@ class UserMiddleware(BaseMiddleware):
# Продолжаем обработку события в любом случае
return await handler(event, data)
async def _process_user(self, user: User, session: Any = None) -> None:
async def _process_user(self, user: User, session: Any = None) -> dict:
"""
Обрабатывает информацию о пользователе и сохраняет её в базу данных.
Args:
user (User): Объект пользователя Telegram
session (Any, optional): Сессия базы данных, если доступна
Returns:
dict: Словарь с информацией о пользователе из базы данных
"""
logger.debug(f"Обработка пользователя: {user.id}")
await upsert_user(
# Получаем данные пользователя из БД после вставки/обновления
user_data = await upsert_user(
tg_id=user.id,
username=user.username,
first_name=user.first_name,
@@ -51,3 +59,6 @@ class UserMiddleware(BaseMiddleware):
is_bot=user.is_bot,
session=session, # Передаем сессию, если она есть
)
logger.debug(f"Получены данные пользователя из БД: {user.id}")
return user_data