chore: run lint and prettifier
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user