Protect deliveries to blocked Telegram users

This commit is contained in:
Андрей Цой
2026-07-02 17:49:05 +09:00
parent b0e42688b6
commit fb1830f77e
8 changed files with 508 additions and 250 deletions

View File

@@ -0,0 +1,130 @@
import os
import sys
import pytest
from aiogram.exceptions import TelegramForbiddenError
from sqlalchemy import delete, select
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import src.core.models # noqa: F401 - register SQLAlchemy models before init_db
from src.core.activity_service import ActivityService
from src.core.database import async_session_maker, init_db
from src.core.delivery import DeliveryService
from src.core.models import BlockedUser
class FakeTelegramMessage:
message_id = 123
async def _cleanup_blocked_user(telegram_id: int):
async with async_session_maker() as session:
await session.execute(
delete(BlockedUser).where(BlockedUser.telegram_id == telegram_id)
)
await session.commit()
async def _get_blocked_user(telegram_id: int):
async with async_session_maker() as session:
result = await session.execute(
select(BlockedUser).where(BlockedUser.telegram_id == telegram_id)
)
return result.scalar_one_or_none()
@pytest.mark.asyncio
async def test_delivery_guard_skips_known_blocked_user():
await init_db()
telegram_id = 880000001
await _cleanup_blocked_user(telegram_id)
async with async_session_maker() as session:
session.add(
BlockedUser(
telegram_id=telegram_id,
error_type="blocked_bot",
error_message="Forbidden: bot was blocked by the user",
is_active=True,
)
)
await session.commit()
called = False
async def send_call():
nonlocal called
called = True
return FakeTelegramMessage()
result = await DeliveryService().send_with_guard(telegram_id, send_call)
assert result.success is False
assert result.skipped is True
assert result.status == "blocked_bot"
assert called is False
await _cleanup_blocked_user(telegram_id)
@pytest.mark.asyncio
async def test_delivery_guard_marks_user_blocked_on_forbidden():
await init_db()
telegram_id = 880000002
await _cleanup_blocked_user(telegram_id)
async def send_call():
raise TelegramForbiddenError(
method=None,
message="Forbidden: bot was blocked by the user",
)
result = await DeliveryService().send_with_guard(telegram_id, send_call)
blocked_user = await _get_blocked_user(telegram_id)
assert result.success is False
assert result.status == "blocked_bot"
assert blocked_user is not None
assert blocked_user.is_active is True
assert blocked_user.error_type == "blocked_bot"
await _cleanup_blocked_user(telegram_id)
def test_delivery_guard_does_not_classify_parse_errors_as_blocked():
service = DeliveryService()
assert service.classify_bad_request(Exception("Bad Request: can't parse entities")) is None
@pytest.mark.asyncio
async def test_activity_reactivates_delivery_after_user_interaction():
await init_db()
telegram_id = 880000003
await _cleanup_blocked_user(telegram_id)
async with async_session_maker() as session:
session.add(
BlockedUser(
telegram_id=telegram_id,
error_type="blocked_bot",
error_message="Forbidden: bot was blocked by the user",
is_active=True,
)
)
await session.commit()
async with async_session_maker() as session:
reactivated = await ActivityService.update_activity_and_reactivate(
session,
telegram_id,
)
blocked_user = await _get_blocked_user(telegram_id)
assert reactivated is True
assert blocked_user is not None
assert blocked_user.is_active is False
await _cleanup_blocked_user(telegram_id)