diff --git a/README.md b/README.md index 33933bd..ed9a439 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ make backup E=test # на домашнем сервере: ./scripts/clickho ## Версионирование -- Единый источник версии — `common/version.py` (`__version__`), текущая — `0.5.0`. +- Единый источник версии — `common/version.py` (`__version__`), текущая — `0.5.1`. - Схема — SemVer-подобная (`MAJOR.MINOR.PATCH`); git-тег = `v` + версия (`v0.1`). - Docker-образы тегируются версией (Блок 2), события ClickHouse получают `bot_version` (Блок 3). - Выпуск: изменить `common/version.py` → коммит → аннотированный тег `vX.Y` → `git push --tags`. diff --git a/bot/handlers/member_events.py b/bot/handlers/member_events.py index c80c92d..e11c11d 100644 --- a/bot/handlers/member_events.py +++ b/bot/handlers/member_events.py @@ -98,6 +98,9 @@ async def _send_fallback_welcome(event: ChatMemberUpdated, user: User) -> None: @router.chat_member(ChatMemberUpdatedFilter(member_status_changed=LEAVE_TRANSITION)) async def goodbye_handler(event: ChatMemberUpdated) -> None: """Пользователь вышел или был исключён — удалить данные именно его.""" + if event.chat.id != get_settings().chat_id: + return + leaver = event.old_chat_member.user if leaver.is_bot: return diff --git a/bot/handlers/shop.py b/bot/handlers/shop.py index a249be9..b7126be 100644 --- a/bot/handlers/shop.py +++ b/bot/handlers/shop.py @@ -11,6 +11,7 @@ from aiogram.types import CallbackQuery, Message from bot.keyboards import get_keyboard_donat, get_keyboard_main, get_keyboard_title from bot.services import access from bot.services import shop as shop_service +from common.config import get_settings from common.texts import system from common.texts.render import render from common.texts.store import get_text @@ -41,6 +42,15 @@ async def _render_chapter(chapter: str) -> tuple[str, object] | None: @router.callback_query() async def callbacks_handler(callback: CallbackQuery) -> None: + settings = get_settings() + if ( + callback.message is not None + and callback.message.chat.type != "private" + and callback.message.chat.id != settings.chat_id + ): + await callback.answer() + return + answer_text = "" args = (callback.data or "").split("_") action = args[0] if args else "" diff --git a/bot/services/access.py b/bot/services/access.py index b29d31c..f4fc643 100644 --- a/bot/services/access.py +++ b/bot/services/access.py @@ -25,6 +25,12 @@ _ALLOWED_STATUSES = { ChatMemberStatus.RESTRICTED, } + +def is_allowed_chat(chat_id: int, chat_type: str, main_chat_id: int) -> bool: + """Личные чаты и основной чат; чужие группы/каналы игнорируются полностью.""" + return chat_type == "private" or chat_id == main_chat_id + + #: TTL-кеш членства, чтобы не дёргать get_chat_member на каждое сообщение. _MEMBERSHIP_TTL = 300.0 _membership_cache: dict[int, tuple[float, bool]] = {} @@ -50,6 +56,10 @@ async def check_user(message: Message) -> bool: if user is None: return False + # Сообщения из посторонних групп не обрабатываем и не шлём по ним уведомления. + if not is_allowed_chat(message.chat.id, message.chat.type, settings.chat_id): + return False + if user.id in settings.admin_ids or await _is_member(message.bot, user.id): await users_service.register_from_message(message) remember_user(user.id, user.username) diff --git a/common/version.py b/common/version.py index d64ee27..32eafd1 100644 --- a/common/version.py +++ b/common/version.py @@ -7,4 +7,4 @@ from __future__ import annotations -__version__ = "0.5.0" +__version__ = "0.5.1" diff --git a/tests/test_access_chat.py b/tests/test_access_chat.py new file mode 100644 index 0000000..76fd8c0 --- /dev/null +++ b/tests/test_access_chat.py @@ -0,0 +1,23 @@ +"""Тесты фильтра чатов: бот игнорирует чужие группы.""" + +from __future__ import annotations + +from bot.services.access import is_allowed_chat + + +def test_private_chat_is_allowed() -> None: + assert is_allowed_chat(123, "private", 100) is True + + +def test_main_chat_is_allowed() -> None: + assert is_allowed_chat(100, "supergroup", 100) is True + assert is_allowed_chat(100, "group", 100) is True + + +def test_foreign_group_is_ignored() -> None: + assert is_allowed_chat(200, "supergroup", 100) is False + assert is_allowed_chat(200, "group", 100) is False + + +def test_foreign_channel_is_ignored() -> None: + assert is_allowed_chat(200, "channel", 100) is False diff --git a/tests/test_version.py b/tests/test_version.py index 20b7125..37244eb 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -7,4 +7,4 @@ from common import __version__ def test_version_is_set(): assert __version__ - assert __version__ == "0.5.0" + assert __version__ == "0.5.1"