fix quality code

This commit is contained in:
2026-02-01 23:03:23 +03:00
parent 731e68a597
commit f8962225ee
106 changed files with 8456 additions and 5810 deletions

View File

@@ -6,27 +6,24 @@ from .constants import ERROR_MESSAGES, FSM_STATES
from .decorators import error_handler
from .exceptions import NoReplyToMessageError, UserNotFoundError
from .group_handlers import GroupHandlers, create_group_handlers, group_router
# Local imports - services
from .services import AdminReplyService, DatabaseProtocol
__all__ = [
# Main components
'group_router',
'create_group_handlers',
'GroupHandlers',
"group_router",
"create_group_handlers",
"GroupHandlers",
# Services
'AdminReplyService',
'DatabaseProtocol',
"AdminReplyService",
"DatabaseProtocol",
# Constants
'FSM_STATES',
'ERROR_MESSAGES',
"FSM_STATES",
"ERROR_MESSAGES",
# Exceptions
'NoReplyToMessageError',
'UserNotFoundError',
"NoReplyToMessageError",
"UserNotFoundError",
# Utilities
'error_handler'
"error_handler",
]

View File

@@ -3,12 +3,10 @@
from typing import Dict, Final
# FSM States
FSM_STATES: Final[Dict[str, str]] = {
"CHAT": "CHAT"
}
FSM_STATES: Final[Dict[str, str]] = {"CHAT": "CHAT"}
# Error messages
ERROR_MESSAGES: Final[Dict[str, str]] = {
"NO_REPLY_TO_MESSAGE": "Блять, выдели сообщение!",
"USER_NOT_FOUND": "Не могу найти кому ответить в базе, проебали сообщение."
"USER_NOT_FOUND": "Не могу найти кому ответить в базе, проебали сообщение.",
}

View File

@@ -6,12 +6,14 @@ from typing import Any, Callable
# Third-party imports
from aiogram import types
# Local imports
from logs.custom_logger import logger
def error_handler(func: Callable[..., Any]) -> Callable[..., Any]:
"""Decorator for centralized error handling"""
async def wrapper(*args: Any, **kwargs: Any) -> Any:
try:
return await func(*args, **kwargs)
@@ -19,18 +21,23 @@ def error_handler(func: Callable[..., Any]) -> Callable[..., Any]:
logger.error(f"Error in {func.__name__}: {str(e)}")
# Try to send error to logs if possible
try:
message = next((arg for arg in args if isinstance(arg, types.Message)), None)
if message and hasattr(message, 'bot'):
from helper_bot.utils.base_dependency_factory import \
get_global_instance
message = next(
(arg for arg in args if isinstance(arg, types.Message)), None
)
if message and hasattr(message, "bot"):
from helper_bot.utils.base_dependency_factory import (
get_global_instance,
)
bdf = get_global_instance()
important_logs = bdf.settings['Telegram']['important_logs']
important_logs = bdf.settings["Telegram"]["important_logs"]
await message.bot.send_message(
chat_id=important_logs,
text=f"Произошла ошибка в {func.__name__}: {str(e)}\n\nTraceback:\n{traceback.format_exc()}"
text=f"Произошла ошибка в {func.__name__}: {str(e)}\n\nTraceback:\n{traceback.format_exc()}",
)
except Exception:
# If we can't log the error, at least it was logged to logger
pass
raise
return wrapper

View File

@@ -3,9 +3,11 @@
class NoReplyToMessageError(Exception):
"""Raised when admin tries to reply without selecting a message"""
pass
class UserNotFoundError(Exception):
"""Raised when user is not found in database for the given message_id"""
pass

View File

@@ -3,11 +3,14 @@
# Third-party imports
from aiogram import Router, types
from aiogram.fsm.context import FSMContext
# Local imports - filters
from database.async_db import AsyncBotDB
from helper_bot.filters.main import ChatTypeFilter
# Local imports - metrics
from helper_bot.utils.metrics import metrics, track_errors, track_time
# Local imports - utilities
from logs.custom_logger import logger
@@ -20,25 +23,24 @@ from .services import AdminReplyService
class GroupHandlers:
"""Main handler class for group messages"""
def __init__(self, db: AsyncBotDB, keyboard_markup: types.ReplyKeyboardMarkup):
self.db = db
self.keyboard_markup = keyboard_markup
self.admin_reply_service = AdminReplyService(db)
# Create router
self.router = Router()
# Register handlers
self._register_handlers()
def _register_handlers(self):
"""Register all message handlers"""
self.router.message.register(
self.handle_message,
ChatTypeFilter(chat_type=["group", "supergroup"])
self.handle_message, ChatTypeFilter(chat_type=["group", "supergroup"])
)
@error_handler
@track_errors("group_handlers", "handle_message")
@track_time("handle_message", "group_handlers")
@@ -46,44 +48,46 @@ class GroupHandlers:
"""Handle admin reply to user through group chat"""
logger.info(
f'Получено сообщение в группе {message.chat.title} (ID: {message.chat.id}) '
f"Получено сообщение в группе {message.chat.title} (ID: {message.chat.id}) "
f'от пользователя {message.from_user.full_name} (ID: {message.from_user.id}): "{message.text}"'
)
# Check if message is a reply
if not message.reply_to_message:
await message.answer(ERROR_MESSAGES["NO_REPLY_TO_MESSAGE"])
logger.warning(
f'В группе {message.chat.title} (ID: {message.chat.id}) '
f'админ не выделил сообщение для ответа.'
f"В группе {message.chat.title} (ID: {message.chat.id}) "
f"админ не выделил сообщение для ответа."
)
return
message_id = message.reply_to_message.message_id
reply_text = message.text
try:
# Get user ID for reply
chat_id = await self.admin_reply_service.get_user_id_for_reply(message_id)
# Send reply to user
await self.admin_reply_service.send_reply_to_user(
chat_id, message, reply_text, self.keyboard_markup
)
# Set state
await state.set_state(FSM_STATES["CHAT"])
except UserNotFoundError:
await message.answer(ERROR_MESSAGES["USER_NOT_FOUND"])
logger.error(
f'Ошибка при поиске пользователя в базе для ответа на сообщение: {reply_text} '
f'в группе {message.chat.title} (ID сообщения: {message.message_id})'
f"Ошибка при поиске пользователя в базе для ответа на сообщение: {reply_text} "
f"в группе {message.chat.title} (ID сообщения: {message.message_id})"
)
# Factory function to create handlers with dependencies
def create_group_handlers(db: AsyncBotDB, keyboard_markup: types.ReplyKeyboardMarkup) -> GroupHandlers:
def create_group_handlers(
db: AsyncBotDB, keyboard_markup: types.ReplyKeyboardMarkup
) -> GroupHandlers:
"""Create group handlers instance with dependencies"""
return GroupHandlers(db, keyboard_markup)
@@ -91,21 +95,23 @@ def create_group_handlers(db: AsyncBotDB, keyboard_markup: types.ReplyKeyboardMa
# Legacy router for backward compatibility
group_router = Router()
# Initialize with global dependencies (for backward compatibility)
def init_legacy_router():
"""Initialize legacy router with global dependencies"""
global group_router
from helper_bot.keyboards.keyboards import get_reply_keyboard_leave_chat
from helper_bot.utils.base_dependency_factory import get_global_instance
bdf = get_global_instance()
#TODO: поменять архитектуру и подключить правильный BotDB
# TODO: поменять архитектуру и подключить правильный BotDB
db = bdf.get_db()
keyboard_markup = get_reply_keyboard_leave_chat()
handlers = create_group_handlers(db, keyboard_markup)
group_router = handlers.router
# Initialize legacy router
init_legacy_router()

View File

@@ -5,8 +5,10 @@ from typing import Optional, Protocol
# Third-party imports
from aiogram import types
# Local imports
from helper_bot.utils.helper_func import send_text_message
# Local imports - metrics
from helper_bot.utils.metrics import db_query_time, track_errors, track_time
from logs.custom_logger import logger
@@ -16,29 +18,32 @@ from .exceptions import NoReplyToMessageError, UserNotFoundError
class DatabaseProtocol(Protocol):
"""Protocol for database operations"""
async def get_user_by_message_id(self, message_id: int) -> Optional[int]: ...
async def add_message(self, message_text: str, user_id: int, message_id: int, date: int = None): ...
async def add_message(
self, message_text: str, user_id: int, message_id: int, date: int = None
): ...
class AdminReplyService:
"""Service for admin reply operations"""
def __init__(self, db: DatabaseProtocol) -> None:
self.db = db
@track_time("get_user_id_for_reply", "admin_reply_service")
@track_errors("admin_reply_service", "get_user_id_for_reply")
@db_query_time("get_user_id_for_reply", "users", "select")
async def get_user_id_for_reply(self, message_id: int) -> int:
"""
Get user ID for reply by message ID.
Args:
message_id: ID of the message to reply to
Returns:
User ID for the reply
Raises:
UserNotFoundError: If user is not found in database
"""
@@ -46,19 +51,19 @@ class AdminReplyService:
if user_id is None:
raise UserNotFoundError(f"User not found for message_id: {message_id}")
return user_id
@track_time("send_reply_to_user", "admin_reply_service")
@track_errors("admin_reply_service", "send_reply_to_user")
async def send_reply_to_user(
self,
chat_id: int,
message: types.Message,
reply_text: str,
markup: types.ReplyKeyboardMarkup
self,
chat_id: int,
message: types.Message,
reply_text: str,
markup: types.ReplyKeyboardMarkup,
) -> None:
"""
Send reply to user.
Args:
chat_id: User's chat ID
message: Original message from admin