refactor: extract common handler logic into decorators
- Add @answer_callback for auto-answering callback queries - Add @with_user_and_session for injecting user/session - Add @require_state for state validation - Reduce handlers.py from ~850 to ~540 lines
This commit is contained in:
76
src/decorators.py
Normal file
76
src/decorators.py
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
from functools import wraps
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
from telegram import Update
|
||||||
|
from telegram.ext import ContextTypes
|
||||||
|
|
||||||
|
from src.database import (
|
||||||
|
User,
|
||||||
|
UserSession,
|
||||||
|
UserState,
|
||||||
|
get_or_create_user,
|
||||||
|
get_user_session,
|
||||||
|
)
|
||||||
|
|
||||||
|
INVALID_STATE_TEXT = "❌ Некорректное действие. Используйте /start для начала."
|
||||||
|
|
||||||
|
|
||||||
|
def answer_callback(func: Callable) -> Callable:
|
||||||
|
"""Автоматически отвечает на callback query."""
|
||||||
|
|
||||||
|
@wraps(func)
|
||||||
|
async def wrapper(
|
||||||
|
update: Update, context: ContextTypes.DEFAULT_TYPE, *args, **kwargs
|
||||||
|
):
|
||||||
|
if update.callback_query:
|
||||||
|
await update.callback_query.answer()
|
||||||
|
return await func(update, context, *args, **kwargs)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def with_user_and_session(func: Callable) -> Callable:
|
||||||
|
"""Добавляет user и session в kwargs."""
|
||||||
|
|
||||||
|
@wraps(func)
|
||||||
|
async def wrapper(
|
||||||
|
update: Update, context: ContextTypes.DEFAULT_TYPE, *args, **kwargs
|
||||||
|
):
|
||||||
|
user = get_or_create_user(update.effective_user.id)
|
||||||
|
session = get_user_session(user.id)
|
||||||
|
return await func(update, context, *args, user=user, session=session, **kwargs)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def require_state(*states: UserState):
|
||||||
|
"""Проверяет, что сессия в одном из указанных состояний."""
|
||||||
|
|
||||||
|
def decorator(func: Callable) -> Callable:
|
||||||
|
@wraps(func)
|
||||||
|
async def wrapper(
|
||||||
|
update: Update,
|
||||||
|
context: ContextTypes.DEFAULT_TYPE,
|
||||||
|
*args,
|
||||||
|
user: User,
|
||||||
|
session: UserSession | None,
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
|
if not session or session.state not in states:
|
||||||
|
if update.callback_query:
|
||||||
|
await update.callback_query.edit_message_text(INVALID_STATE_TEXT)
|
||||||
|
elif update.message:
|
||||||
|
await update.message.reply_text(INVALID_STATE_TEXT)
|
||||||
|
return
|
||||||
|
return await func(
|
||||||
|
update, context, *args, user=user, session=session, **kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def require_states(*states: UserState):
|
||||||
|
"""Алиас для require_state с несколькими состояниями."""
|
||||||
|
return require_state(*states)
|
||||||
1034
src/handlers.py
1034
src/handlers.py
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user