diff --git a/discord_rss_bot/feeds.py b/discord_rss_bot/feeds.py index 684e012..adbfcb9 100644 --- a/discord_rss_bot/feeds.py +++ b/discord_rss_bot/feeds.py @@ -732,7 +732,7 @@ def send_to_discord(reader: Reader | None = None, feed: Feed | None = None, *, d else: logger.warning("No entry link found for feed %s, falling back to regular processing", entry.feed.url) - # Send the entry to Discord as it is not blacklisted or feed has a whitelist. + # Send the entry to Discord because the combined blacklist/whitelist decision allowed it. execute_webhook(webhook, entry, reader=effective_reader) # If we only want to send one entry, we will break the loop. This is used when testing this function. diff --git a/discord_rss_bot/filter/evaluator.py b/discord_rss_bot/filter/evaluator.py index 45ed7d7..30ca4ca 100644 --- a/discord_rss_bot/filter/evaluator.py +++ b/discord_rss_bot/filter/evaluator.py @@ -121,7 +121,7 @@ def evaluate_entry_filters( ) -> EntryFilterDecision: """Evaluate one entry against blacklist and whitelist settings. - Whitelist matches take precedence over blacklist matches. + Blacklist matches take precedence over whitelist matches. Args: entry: The entry to evaluate. @@ -140,10 +140,20 @@ def evaluate_entry_filters( has_blacklist_filters: bool = has_filter_values(normalized_blacklist_values) has_whitelist_filters: bool = has_filter_values(normalized_whitelist_values) - if whitelist_match and blacklist_match: + if blacklist_match and whitelist_match: return EntryFilterDecision( - should_send=True, - reason=f"Sent because {whitelist_match.description}; whitelist overrides blacklist.", + should_send=False, + reason=f"Skipped because {blacklist_match.description}; blacklist overrides whitelist.", + blacklist_match=blacklist_match, + whitelist_match=whitelist_match, + has_blacklist_filters=has_blacklist_filters, + has_whitelist_filters=has_whitelist_filters, + ) + + if blacklist_match: + return EntryFilterDecision( + should_send=False, + reason=f"Skipped because {blacklist_match.description}.", blacklist_match=blacklist_match, whitelist_match=whitelist_match, has_blacklist_filters=has_blacklist_filters, @@ -160,16 +170,6 @@ def evaluate_entry_filters( has_whitelist_filters=has_whitelist_filters, ) - if has_whitelist_filters and blacklist_match: - return EntryFilterDecision( - should_send=False, - reason=f"Skipped because {blacklist_match.description} and no whitelist rule matched.", - blacklist_match=blacklist_match, - whitelist_match=whitelist_match, - has_blacklist_filters=has_blacklist_filters, - has_whitelist_filters=has_whitelist_filters, - ) - if has_whitelist_filters: return EntryFilterDecision( should_send=False, @@ -180,16 +180,6 @@ def evaluate_entry_filters( has_whitelist_filters=has_whitelist_filters, ) - if blacklist_match: - return EntryFilterDecision( - should_send=False, - reason=f"Skipped because {blacklist_match.description}.", - blacklist_match=blacklist_match, - whitelist_match=whitelist_match, - has_blacklist_filters=has_blacklist_filters, - has_whitelist_filters=has_whitelist_filters, - ) - return EntryFilterDecision( should_send=True, reason="Sent because no active filter blocked it.", diff --git a/discord_rss_bot/templates/blacklist.html b/discord_rss_bot/templates/blacklist.html index 8f296d2..b9c2270 100644 --- a/discord_rss_bot/templates/blacklist.html +++ b/discord_rss_bot/templates/blacklist.html @@ -22,7 +22,7 @@

Plain text matching is case-insensitive and partial, so orld matches World of Warcraft.

-

Whitelist matches still win. If an entry matches both, the preview keeps it as sent.

+

Blacklist matches win. If an entry matches both, the preview keeps it as skipped.

Keep the left side for editing and the right side for checking what gets removed.

diff --git a/discord_rss_bot/templates/whitelist.html b/discord_rss_bot/templates/whitelist.html index 4345f72..e1b2859 100644 --- a/discord_rss_bot/templates/whitelist.html +++ b/discord_rss_bot/templates/whitelist.html @@ -20,7 +20,7 @@

Plain text matching is case-insensitive and partial, so orld matches World of Warcraft.

-

When an entry matches both lists, whitelist still wins and the preview shows it as sent.

+

When an entry matches both lists, blacklist wins and the preview shows it as skipped.

Saved blacklist rules remain active while you preview whitelist edits.

diff --git a/tests/test_blacklist.py b/tests/test_blacklist.py index 9e99518..62d1af5 100644 --- a/tests/test_blacklist.py +++ b/tests/test_blacklist.py @@ -207,8 +207,8 @@ def test_regex_should_be_skipped() -> None: assert entry_should_be_skipped(reader, first_entry[0]) is False, f"Entry should not be skipped: {first_entry[0]}" -def test_whitelist_match_overrides_blacklist_match() -> None: - """A whitelist hit should beat a blacklist hit in the final decision.""" +def test_blacklist_match_overrides_whitelist_match() -> None: + """A blacklist hit should beat a whitelist hit in the final decision.""" reader: Reader = get_reader() reader.add_feed(feed_url) @@ -232,10 +232,10 @@ def test_whitelist_match_overrides_blacklist_match() -> None: whitelist_values=get_filter_values_from_reader(reader, feed, "whitelist"), ) - assert decision.should_send is True, "Whitelist match should override blacklist match" + assert decision.should_send is False, "Blacklist match should override whitelist match" assert decision.blacklist_match is not None, "Expected a blacklist match" assert decision.whitelist_match is not None, "Expected a whitelist match" - assert "whitelist overrides blacklist" in decision.reason + assert "blacklist overrides whitelist" in decision.reason def test_blacklist_substring_match_on_title() -> None: diff --git a/tests/test_main.py b/tests/test_main.py index 720d0b6..4b43a0f 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -283,7 +283,7 @@ def test_blacklist_preview_does_not_persist_unsaved_rules() -> None: reader.delete_tag(feed_url, "blacklist_title") -def test_whitelist_preview_shows_precedence_over_blacklist() -> None: +def test_whitelist_preview_shows_blacklist_precedence() -> None: reader: Reader = ensure_preview_feed_exists() reader.set_tag(feed_url, "blacklist_title", "fvnnnfnfdnfdnfd") # pyright: ignore[reportArgumentType] @@ -297,8 +297,8 @@ def test_whitelist_preview_shows_precedence_over_blacklist() -> None: ) assert response.status_code == 200, f"/whitelist_preview failed: {response.text}" - assert "whitelist overrides blacklist" in response.text - assert "Sent" in response.text + assert "blacklist overrides whitelist" in response.text + assert "Skipped" in response.text finally: with contextlib.suppress(Exception): reader.delete_tag(feed_url, "blacklist_title") diff --git a/tests/test_whitelist.py b/tests/test_whitelist.py index 250dcfd..360d688 100644 --- a/tests/test_whitelist.py +++ b/tests/test_whitelist.py @@ -188,8 +188,8 @@ def test_regex_should_be_sent() -> None: assert should_be_sent(reader, first_entry[0]) is False, "Entry should not be sent" -def test_active_whitelist_blocks_non_matching_blacklisted_entry() -> None: - """An active whitelist should block non-matching entries even if blacklist also matches.""" +def test_blacklist_blocks_when_active_whitelist_misses() -> None: + """A blacklist hit should block when an active whitelist does not match.""" reader: Reader = get_reader() reader.add_feed(feed_url) @@ -213,10 +213,10 @@ def test_active_whitelist_blocks_non_matching_blacklisted_entry() -> None: whitelist_values=get_filter_values_from_reader(reader, feed, "whitelist"), ) - assert decision.should_send is False, "Entry should be skipped when whitelist is active but does not match" + assert decision.should_send is False, "Entry should be skipped when blacklist matches" assert decision.blacklist_match is not None, "Expected a blacklist match" assert decision.whitelist_match is None, "Expected whitelist to miss" - assert "no whitelist rule matched" in decision.reason + assert "blacklist text match on title" in decision.reason def test_whitelist_substring_match_on_title() -> None: