Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/telegram_resender/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def handle_text(self, message: IncomingMessage) -> ForwardingDecision:
matching_routes = tuple(
route
for route in self._routes
if route.matches(username=message.user.username, text=message.text)
if route.matches(username=message.user.username, text=parsed_request.fields["building"])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep blacklist checks outside building

For routes that use keywords_none as a blocklist for request-level words (for example the documented "cancel"/"отмена" route examples), passing only parsed_request.fields["building"] means RouteRule.matches() now checks both allow and deny keywords only against the building value. A complete request like Building: Tower A ... Comment: cancel will still match and be forwarded, whereas before the negative keyword suppressed it; this should separate building-only positive route selection from request-wide negative filtering if blacklist keywords are meant to block canceled or disallowed requests outside the building field.

Useful? React with 👍 / 👎.

)
if not matching_routes:
return ForwardingDecision(
Expand Down
45 changes: 45 additions & 0 deletions tests/unit/test_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,51 @@ def test_service_routes_request_to_matching_destinations() -> None:
assert service.render_forward_text_for_target(300, decision.forward_text).startswith("[all]")


def test_service_matches_route_keywords_only_against_building_field() -> None:
"""Keywords in free-form fields must not add unintended destinations."""

service = ResenderService(
whitelist=Whitelist(["alice"]),
formatter=MessageFormatter(),
request_accepted_message="ok",
access_denied_message="deny",
missing_username_message=RU_MESSAGES.access_denied_missing_username,
invalid_request_message=RU_MESSAGES.invalid_request,
missing_fields_message=RU_MESSAGES.missing_fields,
no_route_matched_message=RU_MESSAGES.no_route_matched,
locale="ru",
routes=(
RouteRule(
name="tower-a",
target_chat_id=200,
allowed_usernames=frozenset(),
keywords_any=("башня а",),
keywords_none=(),
template=None,
),
RouteRule(
name="tower-b",
target_chat_id=300,
allowed_usernames=frozenset(),
keywords_any=("башня б",),
keywords_none=(),
template=None,
),
),
)

decision = service.handle_text(
IncomingMessage(
chat_id=1,
text=f"{VALID_REQUEST}\nКомментарий: пожалуйста не отправляйте в Башня Б",
user=UserProfile(username="alice"),
)
)

assert decision.should_forward is True
assert decision.target_chat_ids == (200,)


def test_service_rejects_complete_request_when_no_route_matches() -> None:
"""A complete request should not be forwarded if all route filters reject it."""

Expand Down