fix(filters): honour whole_word

The whole_word field was stored and returned by the API, but the regex
always used word boundaries. As in Mastodon, a filter with whole_word
false now also matches inside words.
This commit is contained in:
Lain Soykaf 2026-10-27 12:50:04 +04:00
commit 422a1d1475
No known key found for this signature in database
3 changed files with 19 additions and 4 deletions

View file

@ -0,0 +1 @@
Filters with whole_word set to false now also match inside words

View file

@ -212,7 +212,7 @@ defmodule Pleroma.Filter do
phrases =
filters
|> Enum.map(&phrase_regex(&1.phrase, boundary))
|> Enum.map(&phrase_regex(&1, boundary))
|> Enum.join("|")
case format do
@ -223,9 +223,12 @@ defmodule Pleroma.Filter do
def compose_regex(_, _), do: nil
# Phrases are literal text. Like Mastodon, only add a word boundary
# where the phrase starts or ends with a word character.
defp phrase_regex(phrase, boundary) do
# Phrases are literal text. Like Mastodon, whole-word filters only get a
# word boundary where the phrase starts or ends with a word character.
defp phrase_regex(%__MODULE__{phrase: phrase, whole_word: false}, _boundary),
do: Regex.escape(phrase)
defp phrase_regex(%__MODULE__{phrase: phrase}, boundary) do
prefix = if String.match?(phrase, ~r/^\w/u), do: boundary, else: ""
suffix = if String.match?(phrase, ~r/\w$/u), do: boundary, else: ""

View file

@ -233,6 +233,17 @@ defmodule Pleroma.FilterTest do
end
end
test "matches inside words when whole_word is false" do
filters = [%Filter{phrase: "cat", whole_word: false}, %Filter{phrase: "dog"}]
pg = Filter.compose_regex(filters)
re = Filter.compose_regex(filters, :re)
for {text, expected} <- [{"a catalog", true}, {"a hotdog", false}, {"a dog", true}] do
assert pg_match?(pg, text) == expected
assert Regex.match?(re, text) == expected
end
end
test "keeps word boundaries for every phrase in Elixir" do
regex = Filter.compose_regex(filters(["cat", "dog"]), :re)