Skip notifications for statuses that contain an irreversible filtered word

This commit is contained in:
Sergey Suprunenko 2019-11-22 19:52:50 +01:00 committed by Alexander Strizhakov
parent 4a8c26654e
commit 5af1bf443d
No known key found for this signature in database
GPG Key ID: 022896A53AEF1381
2 changed files with 119 additions and 18 deletions

View File

@ -130,6 +130,7 @@ def for_user_query(user, opts \\ %{}) do
|> preload([n, a, o], activity: {a, object: o}) |> preload([n, a, o], activity: {a, object: o})
|> exclude_notification_muted(user, exclude_notification_muted_opts) |> exclude_notification_muted(user, exclude_notification_muted_opts)
|> exclude_blocked(user, exclude_blocked_opts) |> exclude_blocked(user, exclude_blocked_opts)
|> exclude_filtered(user)
|> exclude_visibility(opts) |> exclude_visibility(opts)
end end
@ -158,6 +159,20 @@ defp exclude_notification_muted(query, user, opts) do
|> where([n, a, o, tm], is_nil(tm.user_id)) |> where([n, a, o, tm], is_nil(tm.user_id))
end end
defp exclude_filtered(query, user) do
case Pleroma.Filter.compose_regex(user) do
nil ->
query
regex ->
from([_n, a, o] in query,
where:
fragment("not(?->>'content' ~* ?)", o.data, ^regex) or
fragment("?->>'actor' = ?", o.data, ^user.ap_id)
)
end
end
@valid_visibilities ~w[direct unlisted public private] @valid_visibilities ~w[direct unlisted public private]
defp exclude_visibility(query, %{exclude_visibilities: visibility}) defp exclude_visibility(query, %{exclude_visibilities: visibility})
@ -555,7 +570,8 @@ def skip?(%Activity{} = activity, %User{} = user) do
:follows, :follows,
:non_followers, :non_followers,
:non_follows, :non_follows,
:recently_followed :recently_followed,
:filtered
] ]
|> Enum.find(&skip?(&1, activity, user)) |> Enum.find(&skip?(&1, activity, user))
end end
@ -624,6 +640,24 @@ def skip?(:recently_followed, %Activity{data: %{"type" => "Follow"}} = activity,
end) end)
end end
def skip?(:filtered, activity, user) do
object = Object.normalize(activity)
cond do
is_nil(object) ->
false
object.data["actor"] == user.ap_id ->
false
not is_nil(regex = Pleroma.Filter.compose_regex(user, :re)) ->
Regex.match?(regex, object.data["content"])
true ->
false
end
end
def skip?(_, _, _), do: false def skip?(_, _, _), do: false
def for_user_and_activity(user, activity) do def for_user_and_activity(user, activity) do

View File

@ -324,6 +324,44 @@ test "it disables notifications from people who are invisible" do
{:ok, status} = CommonAPI.post(author, %{status: "hey @#{user.nickname}"}) {:ok, status} = CommonAPI.post(author, %{status: "hey @#{user.nickname}"})
refute Notification.create_notification(status, user) refute Notification.create_notification(status, user)
end end
test "it doesn't create notifications if content matches with an irreversible filter" do
user = insert(:user)
subscriber = insert(:user)
User.subscribe(subscriber, user)
insert(:filter, user: subscriber, phrase: "cofe", hide: true)
{:ok, status} = CommonAPI.post(user, %{"status" => "got cofe?"})
assert {:ok, [nil]} == Notification.create_notifications(status)
end
test "it creates notifications if content matches with a not irreversible filter" do
user = insert(:user)
subscriber = insert(:user)
User.subscribe(subscriber, user)
insert(:filter, user: subscriber, phrase: "cofe", hide: false)
{:ok, status} = CommonAPI.post(user, %{"status" => "got cofe?"})
{:ok, [notification]} = Notification.create_notifications(status)
assert notification
end
test "it creates notifications when someone likes user's status with a filtered word" do
user = insert(:user)
other_user = insert(:user)
insert(:filter, user: user, phrase: "tesla", hide: true)
{:ok, activity_one} = CommonAPI.post(user, %{"status" => "wow tesla"})
{:ok, activity_two, _} = CommonAPI.favorite(activity_one.id, other_user)
{:ok, [notification]} = Notification.create_notifications(activity_two)
assert notification
end
end end
describe "follow / follow_request notifications" do describe "follow / follow_request notifications" do
@ -990,8 +1028,13 @@ test "move activity generates a notification" do
end end
describe "for_user" do describe "for_user" do
test "it returns notifications for muted user without notifications" do setup do
user = insert(:user) user = insert(:user)
{:ok, %{user: user}}
end
test "it returns notifications for muted user without notifications", %{user: user} do
muted = insert(:user) muted = insert(:user)
{:ok, _user_relationships} = User.mute(user, muted, false) {:ok, _user_relationships} = User.mute(user, muted, false)
@ -1002,8 +1045,7 @@ test "it returns notifications for muted user without notifications" do
assert notification.activity.object assert notification.activity.object
end end
test "it doesn't return notifications for muted user with notifications" do test "it doesn't return notifications for muted user with notifications", %{user: user} do
user = insert(:user)
muted = insert(:user) muted = insert(:user)
{:ok, _user_relationships} = User.mute(user, muted) {:ok, _user_relationships} = User.mute(user, muted)
@ -1012,8 +1054,7 @@ test "it doesn't return notifications for muted user with notifications" do
assert Notification.for_user(user) == [] assert Notification.for_user(user) == []
end end
test "it doesn't return notifications for blocked user" do test "it doesn't return notifications for blocked user", %{user: user} do
user = insert(:user)
blocked = insert(:user) blocked = insert(:user)
{:ok, _user_relationship} = User.block(user, blocked) {:ok, _user_relationship} = User.block(user, blocked)
@ -1022,8 +1063,7 @@ test "it doesn't return notifications for blocked user" do
assert Notification.for_user(user) == [] assert Notification.for_user(user) == []
end end
test "it doesn't return notifications for domain-blocked non-followed user" do test "it doesn't return notifications for domain-blocked non-followed user", %{user: user} do
user = insert(:user)
blocked = insert(:user, ap_id: "http://some-domain.com") blocked = insert(:user, ap_id: "http://some-domain.com")
{:ok, user} = User.block_domain(user, "some-domain.com") {:ok, user} = User.block_domain(user, "some-domain.com")
@ -1044,8 +1084,7 @@ test "it returns notifications for domain-blocked but followed user" do
assert length(Notification.for_user(user)) == 1 assert length(Notification.for_user(user)) == 1
end end
test "it doesn't return notifications for muted thread" do test "it doesn't return notifications for muted thread", %{user: user} do
user = insert(:user)
another_user = insert(:user) another_user = insert(:user)
{:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"}) {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
@ -1054,8 +1093,7 @@ test "it doesn't return notifications for muted thread" do
assert Notification.for_user(user) == [] assert Notification.for_user(user) == []
end end
test "it returns notifications from a muted user when with_muted is set" do test "it returns notifications from a muted user when with_muted is set", %{user: user} do
user = insert(:user)
muted = insert(:user) muted = insert(:user)
{:ok, _user_relationships} = User.mute(user, muted) {:ok, _user_relationships} = User.mute(user, muted)
@ -1064,8 +1102,9 @@ test "it returns notifications from a muted user when with_muted is set" do
assert length(Notification.for_user(user, %{with_muted: true})) == 1 assert length(Notification.for_user(user, %{with_muted: true})) == 1
end end
test "it doesn't return notifications from a blocked user when with_muted is set" do test "it doesn't return notifications from a blocked user when with_muted is set", %{
user = insert(:user) user: user
} do
blocked = insert(:user) blocked = insert(:user)
{:ok, _user_relationship} = User.block(user, blocked) {:ok, _user_relationship} = User.block(user, blocked)
@ -1075,8 +1114,8 @@ test "it doesn't return notifications from a blocked user when with_muted is set
end end
test "when with_muted is set, " <> test "when with_muted is set, " <>
"it doesn't return notifications from a domain-blocked non-followed user" do "it doesn't return notifications from a domain-blocked non-followed user",
user = insert(:user) %{user: user} do
blocked = insert(:user, ap_id: "http://some-domain.com") blocked = insert(:user, ap_id: "http://some-domain.com")
{:ok, user} = User.block_domain(user, "some-domain.com") {:ok, user} = User.block_domain(user, "some-domain.com")
@ -1085,8 +1124,7 @@ test "when with_muted is set, " <>
assert Enum.empty?(Notification.for_user(user, %{with_muted: true})) assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
end end
test "it returns notifications from muted threads when with_muted is set" do test "it returns notifications from muted threads when with_muted is set", %{user: user} do
user = insert(:user)
another_user = insert(:user) another_user = insert(:user)
{:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"}) {:ok, activity} = CommonAPI.post(another_user, %{status: "hey @#{user.nickname}"})
@ -1094,5 +1132,34 @@ test "it returns notifications from muted threads when with_muted is set" do
{:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"]) {:ok, _} = Pleroma.ThreadMute.add_mute(user.id, activity.data["context"])
assert length(Notification.for_user(user, %{with_muted: true})) == 1 assert length(Notification.for_user(user, %{with_muted: true})) == 1
end end
test "it doesn't return notifications about mentiones with filtered word", %{user: user} do
insert(:filter, user: user, phrase: "cofe", hide: true)
another_user = insert(:user)
{:ok, _activity} =
CommonAPI.post(another_user, %{"status" => "@#{user.nickname} got cofe?"})
assert Enum.empty?(Notification.for_user(user))
end
test "it returns notifications about mentiones with not hidden filtered word", %{user: user} do
insert(:filter, user: user, phrase: "test", hide: false)
another_user = insert(:user)
{:ok, _activity} = CommonAPI.post(another_user, %{"status" => "@#{user.nickname} test"})
assert length(Notification.for_user(user)) == 1
end
test "it returns notifications about favorites with filtered word", %{user: user} do
insert(:filter, user: user, phrase: "cofe", hide: true)
another_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "Give me my cofe!"})
{:ok, _, _} = CommonAPI.favorite(activity.id, another_user)
assert length(Notification.for_user(user)) == 1
end
end end
end end