chore: run lint and prettifier

This commit is contained in:
3252a8
2026-05-12 21:54:12 +03:00
parent f31540afdb
commit 11187487b4
174 changed files with 12383 additions and 6688 deletions
+16 -18
View File
@@ -1,24 +1,26 @@
import logging
from typing import Callable, Dict, Any, Awaitable, Optional
from datetime import datetime, timezone
from typing import Any, Awaitable, Callable, Dict, Optional
from aiogram import BaseMiddleware
from aiogram.types import Update, User, Message, CallbackQuery
from aiogram.types import CallbackQuery, Message, Update, User
from sqlalchemy.ext.asyncio import AsyncSession
from db.dal import message_log_dal, user_dal
from config.settings import Settings
from db.dal import message_log_dal, user_dal
class ActionLoggerMiddleware(BaseMiddleware):
def __init__(self, settings: Settings):
super().__init__()
self.settings = settings
async def __call__(self, handler: Callable[[Update, Dict[str, Any]],
Awaitable[Any]], event: Update,
data: Dict[str, Any]) -> Any:
async def __call__(
self,
handler: Callable[[Update, Dict[str, Any]], Awaitable[Any]],
event: Update,
data: Dict[str, Any],
) -> Any:
result = await handler(event, data)
@@ -44,8 +46,7 @@ class ActionLoggerMiddleware(BaseMiddleware):
raw_update_snippet = None
try:
raw_update_snippet = event.model_dump_json(exclude_none=True,
indent=None)[:1000]
raw_update_snippet = event.model_dump_json(exclude_none=True, indent=None)[:1000]
except AttributeError:
raw_update_snippet = str(event)[:1000]
except Exception:
@@ -57,7 +58,7 @@ class ActionLoggerMiddleware(BaseMiddleware):
msg: Message = event.message
if msg.text:
content = msg.text
if msg.text.startswith('/'):
if msg.text.startswith("/"):
current_event_type = f"command:{msg.text.split()[0]}"
else:
@@ -66,12 +67,10 @@ class ActionLoggerMiddleware(BaseMiddleware):
elif event.callback_query:
cb: CallbackQuery = event.callback_query
content = cb.data
action_part = cb.data.split(
":")[0] if cb.data and ":" in cb.data else cb.data
action_part = cb.data.split(":")[0] if cb.data and ":" in cb.data else cb.data
current_event_type = f"callback:{action_part}"
if user_id or current_event_type not in ["update"]:
log_user_id_for_db = user_id
if user_id:
user_exists = await user_dal.get_user_by_id(session, user_id)
@@ -90,15 +89,14 @@ class ActionLoggerMiddleware(BaseMiddleware):
"raw_update_preview": raw_update_snippet,
"is_admin_event": is_admin_event_flag,
"target_user_id": target_user_id_for_log,
"timestamp": datetime.now(timezone.utc)
"timestamp": datetime.now(timezone.utc),
}
try:
await message_log_dal.create_message_log_no_commit(
session, log_payload)
await message_log_dal.create_message_log_no_commit(session, log_payload)
except Exception as e_log:
logging.error(
f"ActionLoggerMiddleware: Failed to add log to session for user {user_id}, type {current_event_type}: {e_log}",
exc_info=True)
exc_info=True,
)
return result
+41 -30
View File
@@ -1,28 +1,34 @@
import logging
from typing import Callable, Dict, Any, Awaitable, Optional, Union
from typing import Any, Awaitable, Callable, Dict, Optional, Union
from aiogram import BaseMiddleware, Bot
from aiogram.types import Message, CallbackQuery, User, Update, InlineKeyboardMarkup
from aiogram.exceptions import (
AiogramError,
TelegramAPIError,
TelegramForbiddenError,
)
from aiogram.types import CallbackQuery, InlineKeyboardMarkup, Message, Update, User
from sqlalchemy.ext.asyncio import AsyncSession
from aiogram.exceptions import TelegramAPIError, TelegramForbiddenError, TelegramBadRequest, AiogramError
from config.settings import Settings
from db.dal import user_dal
from .i18n import JsonI18n
from ..keyboards.inline.user_keyboards import get_user_banned_keyboard
from .i18n import JsonI18n
class BanCheckMiddleware(BaseMiddleware):
def __init__(self, settings: Settings, i18n_instance: JsonI18n):
super().__init__()
self.settings = settings
self.i18n_main_instance = i18n_instance
async def __call__(self, handler: Callable[[Update, Dict[str, Any]],
Awaitable[Any]], event: Update,
data: Dict[str, Any]) -> Any:
async def __call__(
self,
handler: Callable[[Update, Dict[str, Any]], Awaitable[Any]],
event: Update,
data: Dict[str, Any],
) -> Any:
session: AsyncSession = data["session"]
event_user: Optional[User] = data.get("event_from_user")
bot_instance: Bot = data["bot"]
@@ -34,12 +40,11 @@ class BanCheckMiddleware(BaseMiddleware):
return await handler(event, data)
try:
db_user_model = await user_dal.get_user_by_id(
session, event_user.id)
db_user_model = await user_dal.get_user_by_id(session, event_user.id)
except Exception as e_db:
logging.error(
f"BanCheckMiddleware: DB error fetching user {event_user.id}: {e_db}",
exc_info=True)
f"BanCheckMiddleware: DB error fetching user {event_user.id}: {e_db}", exc_info=True
)
return await handler(event, data)
if db_user_model and db_user_model.is_banned:
@@ -49,9 +54,11 @@ class BanCheckMiddleware(BaseMiddleware):
i18n_data_from_event = data.get("i18n_data", {})
current_lang = i18n_data_from_event.get(
"current_language", self.settings.DEFAULT_LANGUAGE)
"current_language", self.settings.DEFAULT_LANGUAGE
)
i18n_to_use: Optional[JsonI18n] = i18n_data_from_event.get(
"i18n_instance", self.i18n_main_instance)
"i18n_instance", self.i18n_main_instance
)
ban_message_text = "You are banned. Please contact support."
keyboard: Optional[InlineKeyboardMarkup] = None
@@ -59,52 +66,56 @@ class BanCheckMiddleware(BaseMiddleware):
if i18n_to_use:
_ = lambda k, **kw: i18n_to_use.gettext(current_lang, k, **kw)
ban_message_text = _("user_is_banned")
keyboard = get_user_banned_keyboard(self.settings.SUPPORT_LINK,
current_lang, i18n_to_use)
keyboard = get_user_banned_keyboard(
self.settings.SUPPORT_LINK, current_lang, i18n_to_use
)
elif self.settings.SUPPORT_LINK:
from aiogram.utils.keyboard import InlineKeyboardBuilder
builder = InlineKeyboardBuilder()
builder.button(text="Support", url=self.settings.SUPPORT_LINK)
keyboard = builder.as_markup()
actual_event_object: Optional[Union[Message, CallbackQuery]] = None
if event.message: actual_event_object = event.message
if event.message:
actual_event_object = event.message
elif event.callback_query:
actual_event_object = event.callback_query
try:
if isinstance(actual_event_object, Message):
await actual_event_object.answer(ban_message_text,
reply_markup=keyboard)
await actual_event_object.answer(ban_message_text, reply_markup=keyboard)
elif isinstance(actual_event_object, CallbackQuery):
await actual_event_object.answer(ban_message_text,
show_alert=True)
await actual_event_object.answer(ban_message_text, show_alert=True)
if actual_event_object.message:
try:
await actual_event_object.message.edit_text(
ban_message_text, reply_markup=keyboard)
ban_message_text, reply_markup=keyboard
)
except (TelegramAPIError, AiogramError):
await bot_instance.send_message(
actual_event_object.from_user.id,
ban_message_text,
reply_markup=keyboard)
reply_markup=keyboard,
)
else:
await bot_instance.send_message(
actual_event_object.from_user.id,
ban_message_text,
reply_markup=keyboard)
reply_markup=keyboard,
)
else:
await bot_instance.send_message(event_user.id,
ban_message_text,
reply_markup=keyboard)
await bot_instance.send_message(
event_user.id, ban_message_text, reply_markup=keyboard
)
logging.info(f"Ban notification sent to user {event_user.id}.")
except TelegramForbiddenError:
logging.warning(
f"BanCheck: Bot is blocked by user {event_user.id}.")
logging.warning(f"BanCheck: Bot is blocked by user {event_user.id}.")
except Exception as e_send:
logging.error(
f"BanCheck: Failed to notify banned user {event_user.id}: {type(e_send).__name__} - {e_send}",
exc_info=True)
exc_info=True,
)
return
return await handler(event, data)
+4 -10
View File
@@ -9,10 +9,10 @@ from aiogram.types import (
)
from sqlalchemy.ext.asyncio import AsyncSession
from bot.keyboards.inline.user_keyboards import get_channel_subscription_keyboard
from bot.middlewares.i18n import JsonI18n
from config.settings import Settings
from db.dal import user_dal
from bot.middlewares.i18n import JsonI18n
from bot.keyboards.inline.user_keyboards import get_channel_subscription_keyboard
class ChannelSubscriptionMiddleware(BaseMiddleware):
@@ -50,11 +50,7 @@ class ChannelSubscriptionMiddleware(BaseMiddleware):
# Allow /start to reach the handler so the check can be re-run.
message_object: Optional[Message] = event.message
if (
message_object
and message_object.text
and message_object.text.startswith("/start")
):
if message_object and message_object.text and message_object.text.startswith("/start"):
return await handler(event, data)
session: AsyncSession = data["session"]
@@ -79,9 +75,7 @@ class ChannelSubscriptionMiddleware(BaseMiddleware):
return await handler(event, data)
i18n_payload: Dict[str, Any] = data.get("i18n_data", {})
current_lang: str = i18n_payload.get(
"current_language", self.settings.DEFAULT_LANGUAGE
)
current_lang: str = i18n_payload.get("current_language", self.settings.DEFAULT_LANGUAGE)
i18n_instance: Optional[JsonI18n] = i18n_payload.get(
"i18n_instance", self.i18n_main_instance
)
+3 -9
View File
@@ -1,5 +1,5 @@
import logging
from typing import Callable, Dict, Any, Awaitable
from typing import Any, Awaitable, Callable, Dict
from aiogram import BaseMiddleware
from aiogram.types import Update
@@ -7,7 +7,6 @@ from sqlalchemy.orm import sessionmaker
class DBSessionMiddleware(BaseMiddleware):
def __init__(self, async_session_factory: sessionmaker):
super().__init__()
self.async_session_factory = async_session_factory
@@ -20,9 +19,7 @@ class DBSessionMiddleware(BaseMiddleware):
) -> Any:
if self.async_session_factory is None:
logging.critical("DBSessionMiddleware: async_session_factory is None!")
raise RuntimeError(
"async_session_factory not provided to DBSessionMiddleware"
)
raise RuntimeError("async_session_factory not provided to DBSessionMiddleware")
async with self.async_session_factory() as session:
data["session"] = session
@@ -33,8 +30,5 @@ class DBSessionMiddleware(BaseMiddleware):
return result
except Exception:
await session.rollback()
logging.error(
"DBSessionMiddleware: Exception caused rollback.", exc_info=True
)
logging.error("DBSessionMiddleware: Exception caused rollback.", exc_info=True)
raise
+34 -43
View File
@@ -1,18 +1,17 @@
import logging
import json
import logging
import os
from typing import Any, Awaitable, Callable, Dict, Optional
from aiogram import BaseMiddleware
from aiogram.types import User, Update
from aiogram.types import Update, User
from sqlalchemy.ext.asyncio import AsyncSession
from db.dal import user_dal
from config.settings import Settings
from db.dal import user_dal
class JsonI18n:
def __init__(self, path: str, default: str = "en", domain: str = "bot"):
self.domain = domain
self.path = path
@@ -25,8 +24,7 @@ class JsonI18n:
def _load_locales(self):
if not os.path.isdir(self.path):
logging.error(
f"Locales path not found or not a directory: {self.path}")
logging.error(f"Locales path not found or not a directory: {self.path}")
return
for item in os.listdir(self.path):
if item.endswith(".json"):
@@ -42,7 +40,8 @@ class JsonI18n:
except Exception as e_load:
logging.error(
f"Error loading locale {lang_code} from {file_path}: {e_load}",
exc_info=True)
exc_info=True,
)
def gettext(self, lang_code: Optional[str], key: str, **kwargs) -> str:
# Determine effective language with robust fallback
@@ -50,15 +49,15 @@ class JsonI18n:
effective_lang_code = lang_code
elif self.default_lang in self.locales_data:
effective_lang_code = self.default_lang
elif 'en' in self.locales_data:
effective_lang_code = 'en'
elif "en" in self.locales_data:
effective_lang_code = "en"
else:
effective_lang_code = lang_code or self.default_lang
lang_data = self.locales_data.get(effective_lang_code)
if lang_data is None:
# Try explicit fallback to English if available
fallback_data = self.locales_data.get('en')
fallback_data = self.locales_data.get("en")
if fallback_data is not None:
text = fallback_data.get(key)
if text is not None:
@@ -74,8 +73,7 @@ class JsonI18n:
text = lang_data.get(key)
if text is None:
if effective_lang_code != self.default_lang:
default_lang_data = self.locales_data.get(
self.default_lang, {})
default_lang_data = self.locales_data.get(self.default_lang, {})
text = default_lang_data.get(key)
if text is None:
@@ -93,44 +91,40 @@ class JsonI18n:
except Exception as e_general_format:
logging.error(
f"General error formatting i18n key '{key}' (lang: {effective_lang_code}): {e_general_format}. Original text: '{text}'",
exc_info=True)
exc_info=True,
)
return text
_i18n_instance_singleton: Optional[JsonI18n] = None
def get_i18n_instance(path: str = "locales",
default: str = "en",
domain: str = "bot") -> JsonI18n:
def get_i18n_instance(path: str = "locales", default: str = "en", domain: str = "bot") -> JsonI18n:
global _i18n_instance_singleton
if _i18n_instance_singleton is None:
if not os.path.exists(path) or not os.path.isdir(path):
logging.error(
f"CRITICAL: Locales directory '{path}' not found. i18n will not work correctly."
)
_i18n_instance_singleton = JsonI18n(path=path,
default=default,
domain=domain)
_i18n_instance_singleton = JsonI18n(path=path, default=default, domain=domain)
else:
_i18n_instance_singleton = JsonI18n(path=path,
default=default,
domain=domain)
_i18n_instance_singleton = JsonI18n(path=path, default=default, domain=domain)
return _i18n_instance_singleton
class I18nMiddleware(BaseMiddleware):
def __init__(self, i18n: JsonI18n, settings: Settings):
super().__init__()
self.i18n = i18n
self.settings = settings
async def __call__(self, handler: Callable[[Update, Dict[str, Any]],
Awaitable[Any]], event: Update,
data: Dict[str, Any]) -> Any:
async def __call__(
self,
handler: Callable[[Update, Dict[str, Any]], Awaitable[Any]],
event: Update,
data: Dict[str, Any],
) -> Any:
session: AsyncSession = data["session"]
event_user: Optional[User] = data.get("event_from_user")
@@ -138,33 +132,30 @@ class I18nMiddleware(BaseMiddleware):
if event_user:
try:
user_db_model = await user_dal.get_user_by_id(
session, event_user.id)
if user_db_model and user_db_model.language_code and user_db_model.language_code in self.i18n.locales_data:
user_db_model = await user_dal.get_user_by_id(session, event_user.id)
if (
user_db_model
and user_db_model.language_code
and user_db_model.language_code in self.i18n.locales_data
):
current_language = user_db_model.language_code
elif event_user.language_code:
lang_prefix = event_user.language_code.split(
'-')[0].lower()
lang_prefix = event_user.language_code.split("-")[0].lower()
if lang_prefix in self.i18n.locales_data:
current_language = lang_prefix
elif event_user.language_code.lower(
) in self.i18n.locales_data:
elif event_user.language_code.lower() in self.i18n.locales_data:
current_language = event_user.language_code.lower()
except Exception as e_db_lang:
logging.error(
f"I18nMiddleware: Error fetching user lang from DB for {event_user.id}: {e_db_lang}. Falling back.",
exc_info=True)
exc_info=True,
)
if event_user.language_code:
lang_prefix = event_user.language_code.split(
'-')[0].lower()
lang_prefix = event_user.language_code.split("-")[0].lower()
if lang_prefix in self.i18n.locales_data:
current_language = lang_prefix
elif event_user.language_code.lower(
) in self.i18n.locales_data:
elif event_user.language_code.lower() in self.i18n.locales_data:
current_language = event_user.language_code.lower()
data["i18n_data"] = {
"i18n_instance": self.i18n,
"current_language": current_language
}
data["i18n_data"] = {"i18n_instance": self.i18n, "current_language": current_language}
return await handler(event, data)
+14 -11
View File
@@ -1,16 +1,16 @@
import logging
from typing import Callable, Dict, Any, Awaitable, Optional
from typing import Any, Awaitable, Callable, Dict, Optional
from aiogram import BaseMiddleware
from aiogram.types import Update, User as TgUser
from aiogram.types import Update
from aiogram.types import User as TgUser
from sqlalchemy.ext.asyncio import AsyncSession
from bot.utils.text_sanitizer import sanitize_display_name, sanitize_username, username_for_display
from db.dal import user_dal
from bot.utils.text_sanitizer import sanitize_username, sanitize_display_name, username_for_display
class ProfileSyncMiddleware(BaseMiddleware):
async def __call__(
self,
handler: Callable[[Update, Dict[str, Any]], Awaitable[Any]],
@@ -50,12 +50,16 @@ class ProfileSyncMiddleware(BaseMiddleware):
try:
panel_service = data.get("panel_service")
if panel_service and db_user.panel_user_uuid:
description_text = "\n".join([
db_user.email or "",
username_for_display(tg_user.username, with_at=False) if sanitized_username is not None else "",
sanitized_first_name or "",
sanitized_last_name or "",
]).strip()
description_text = "\n".join(
[
db_user.email or "",
username_for_display(tg_user.username, with_at=False)
if sanitized_username is not None
else "",
sanitized_first_name or "",
sanitized_last_name or "",
]
).strip()
panel_payload = {
"description": description_text,
"telegramId": tg_user.id,
@@ -77,4 +81,3 @@ class ProfileSyncMiddleware(BaseMiddleware):
)
return await handler(event, data)