Refactor project structure and remove obsolete files

- Deleted the Makefile, `README_TESTING.md`, and several deployment scripts to streamline the project.
- Updated `.dockerignore` to exclude unnecessary development files.
- Adjusted database schema comments for clarity.
- Refactored metrics handling in middleware for improved command extraction and logging.
- Enhanced command mappings for buttons and callbacks in constants for better maintainability.
- Start refactor voice bot
This commit is contained in:
2025-09-01 00:54:10 +03:00
parent 2368af3d93
commit d128e54694
25 changed files with 1175 additions and 986 deletions

View File

@@ -343,7 +343,7 @@ async def test_metrics_handler(
await message.answer(
f"✅ Тестовые метрики записаны\n"
f"📊 Активных пользователей: {active_users}\n"
f"🔧 Проверьте Grafana дашборд"
f"🔧 Проверьте Prometheus метрики"
)
except Exception as e:

View File

@@ -0,0 +1,29 @@
"""Constants for admin handlers"""
from typing import Final, Dict
# Admin button texts
ADMIN_BUTTON_TEXTS: Final[Dict[str, str]] = {
"BAN_LIST": "Бан (Список)",
"BAN_BY_USERNAME": "Бан по нику",
"BAN_BY_ID": "Бан по ID",
"UNBAN_LIST": "Разбан (список)",
"RETURN_TO_BOT": "Вернуться в бота",
"CANCEL": "Отменить"
}
# Admin button to command mapping for metrics
ADMIN_BUTTON_COMMAND_MAPPING: Final[Dict[str, str]] = {
"Бан (Список)": "admin_ban_list",
"Бан по нику": "admin_ban_by_username",
"Бан по ID": "admin_ban_by_id",
"Разбан (список)": "admin_unban_list",
"Вернуться в бота": "admin_return_to_bot",
"Отменить": "admin_cancel"
}
# Admin commands
ADMIN_COMMANDS: Final[Dict[str, str]] = {
"ADMIN": "admin",
"TEST_METRICS": "test_metrics"
}

View File

@@ -1,3 +1,5 @@
from typing import Final, Dict
# Callback data constants
CALLBACK_PUBLISH = "publish"
CALLBACK_DECLINE = "decline"
@@ -27,3 +29,13 @@ MESSAGE_USER_BANNED_SPAM = "Ты заблокирован за спам. Дат
# Error messages
ERROR_BOT_BLOCKED = "Forbidden: bot was blocked by the user"
# Callback to command mapping for metrics
CALLBACK_COMMAND_MAPPING: Final[Dict[str, str]] = {
"publish": "publish",
"decline": "decline",
"ban": "ban",
"unlock": "unlock",
"return": "return",
"page": "page"
}

View File

@@ -20,6 +20,16 @@ BUTTON_TEXTS: Final[Dict[str, str]] = {
"CONNECT_ADMIN": "📩Связаться с админами"
}
# Button to command mapping for metrics
BUTTON_COMMAND_MAPPING: Final[Dict[str, str]] = {
"📢Предложить свой пост": "suggest_post",
"👋🏼Сказать пока!": "say_goodbye",
"Выйти из чата": "leave_chat",
"Вернуться в бота": "return_to_bot",
"🤪Хочу стикеры": "want_stickers",
"📩Связаться с админами": "connect_admin"
}
# Error messages
ERROR_MESSAGES: Final[Dict[str, str]] = {
"UNSUPPORTED_CONTENT": (

View File

@@ -3,7 +3,7 @@ Metrics middleware for aiogram 3.x.
Automatically collects metrics for message processing, command execution, and errors.
"""
from typing import Any, Awaitable, Callable, Dict
from typing import Any, Awaitable, Callable, Dict, Union, Optional
from aiogram import BaseMiddleware
from aiogram.types import TelegramObject, Message, CallbackQuery
from aiogram.enums import ChatType
@@ -11,6 +11,18 @@ import time
import logging
from ..utils.metrics import metrics
# Import button command mapping
try:
from ..handlers.private.constants import BUTTON_COMMAND_MAPPING
from ..handlers.callback.constants import CALLBACK_COMMAND_MAPPING
from ..handlers.admin.constants import ADMIN_BUTTON_COMMAND_MAPPING, ADMIN_COMMANDS
except ImportError:
# Fallback if constants not available
BUTTON_COMMAND_MAPPING = {}
CALLBACK_COMMAND_MAPPING = {}
ADMIN_BUTTON_COMMAND_MAPPING = {}
ADMIN_COMMANDS = {}
class MetricsMiddleware(BaseMiddleware):
"""Middleware for automatic metrics collection in aiogram handlers."""
@@ -35,23 +47,11 @@ class MetricsMiddleware(BaseMiddleware):
if isinstance(event, Message):
self.logger.info(f"📊 Processing Message event")
await self._record_message_metrics(event)
if event.text and event.text.startswith('/'):
command_info = {
'command': event.text.split()[0][1:], # Remove '/' and get command name
'user_type': "user" if event.from_user else "unknown",
'handler_type': "message_handler"
}
command_info = self._extract_command_info(event)
elif isinstance(event, CallbackQuery):
self.logger.info(f"📊 Processing CallbackQuery event")
await self._record_callback_metrics(event)
if event.data:
parts = event.data.split(':', 1)
if parts:
command_info = {
'command': parts[0],
'user_type': "user" if event.from_user else "unknown",
'handler_type': "callback_handler"
}
command_info = self._extract_callback_command_info(event)
else:
self.logger.info(f"📊 Processing unknown event type: {type(event).__name__}")
@@ -167,6 +167,62 @@ class MetricsMiddleware(BaseMiddleware):
async def _record_callback_metrics(self, callback: CallbackQuery):
"""Record callback metrics efficiently."""
metrics.record_message("callback_query", "callback", "callback_handler")
def _extract_command_info(self, message: Message) -> Optional[Dict[str, str]]:
"""Extract command information from message (commands or button clicks)."""
if not message.text:
return None
# Check if it's a slash command
if message.text.startswith('/'):
command_name = message.text.split()[0][1:] # Remove '/' and get command name
# Check if it's an admin command
if command_name in ADMIN_COMMANDS:
return {
'command': ADMIN_COMMANDS[command_name],
'user_type': "admin" if message.from_user else "unknown",
'handler_type': "admin_handler"
}
else:
return {
'command': command_name,
'user_type': "user" if message.from_user else "unknown",
'handler_type': "message_handler"
}
# Check if it's an admin button click
if message.text in ADMIN_BUTTON_COMMAND_MAPPING:
return {
'command': ADMIN_BUTTON_COMMAND_MAPPING[message.text],
'user_type': "admin" if message.from_user else "unknown",
'handler_type': "admin_button_handler"
}
# Check if it's a regular button click (text button)
if message.text in BUTTON_COMMAND_MAPPING:
return {
'command': BUTTON_COMMAND_MAPPING[message.text],
'user_type': "user" if message.from_user else "unknown",
'handler_type': "button_handler"
}
return None
def _extract_callback_command_info(self, callback: CallbackQuery) -> Optional[Dict[str, str]]:
"""Extract command information from callback query."""
if not callback.data:
return None
# Extract command from callback data
parts = callback.data.split(':', 1)
if parts and parts[0] in CALLBACK_COMMAND_MAPPING:
return {
'command': CALLBACK_COMMAND_MAPPING[parts[0]],
'user_type': "user" if callback.from_user else "unknown",
'handler_type': "callback_handler"
}
return None
class DatabaseMetricsMiddleware(BaseMiddleware):