Fix exclude_visibilities filter for followers-only Like notifications

This commit is contained in:
eugenijm 2019-11-09 13:56:27 +03:00
parent fb090b748a
commit f86a7d5d8b
2 changed files with 153 additions and 49 deletions

View File

@ -87,10 +87,28 @@ defp exclude_visibility(query, %{exclude_visibilities: visibility})
when is_list(visibility) do when is_list(visibility) do
if Enum.all?(visibility, &(&1 in @valid_visibilities)) do if Enum.all?(visibility, &(&1 in @valid_visibilities)) do
query query
|> join(:left, [n, a], mutated_activity in Pleroma.Activity,
on:
fragment("?->>'context'", a.data) ==
fragment("?->>'context'", mutated_activity.data) and
fragment("(?->>'type' = 'Like' or ?->>'type' = 'Announce')", a.data, a.data) and
fragment("?->>'type'", mutated_activity.data) == "Create",
as: :mutated_activity
)
|> where( |> where(
[n, a], [n, a, mutated_activity: mutated_activity],
not fragment( not fragment(
"activity_visibility(?, ?, ?) = ANY (?)", """
CASE WHEN (?->>'type') = 'Like' or (?->>'type') = 'Announce'
THEN (activity_visibility(?, ?, ?) = ANY (?))
ELSE (activity_visibility(?, ?, ?) = ANY (?)) END
""",
a.data,
a.data,
mutated_activity.actor,
mutated_activity.recipients,
mutated_activity.data,
^visibility,
a.actor, a.actor,
a.recipients, a.recipients,
a.data, a.data,
@ -105,17 +123,7 @@ defp exclude_visibility(query, %{exclude_visibilities: visibility})
defp exclude_visibility(query, %{exclude_visibilities: visibility}) defp exclude_visibility(query, %{exclude_visibilities: visibility})
when visibility in @valid_visibilities do when visibility in @valid_visibilities do
query exclude_visibility(query, [visibility])
|> where(
[n, a],
not fragment(
"activity_visibility(?, ?, ?) = (?)",
a.actor,
a.recipients,
a.data,
^visibility
)
)
end end
defp exclude_visibility(query, %{exclude_visibilities: visibility}) defp exclude_visibility(query, %{exclude_visibilities: visibility})

View File

@ -137,55 +137,151 @@ test "paginates notifications using min_id, since_id, max_id, and limit", %{conn
assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
end end
test "filters notifications using exclude_visibilities", %{conn: conn} do describe "exclude_visibilities" do
user = insert(:user) test "filters notifications for mentions", %{conn: conn} do
other_user = insert(:user) user = insert(:user)
other_user = insert(:user)
{:ok, public_activity} = {:ok, public_activity} =
CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "public"}) CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "public"})
{:ok, direct_activity} = {:ok, direct_activity} =
CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "direct"}) CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "direct"})
{:ok, unlisted_activity} = {:ok, unlisted_activity} =
CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "unlisted"}) CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "unlisted"})
{:ok, private_activity} = {:ok, private_activity} =
CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "private"}) CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "private"})
conn = assign(conn, :user, user) conn = assign(conn, :user, user)
conn_res = conn_res =
get(conn, "/api/v1/notifications", %{ get(conn, "/api/v1/notifications", %{
exclude_visibilities: ["public", "unlisted", "private"] exclude_visibilities: ["public", "unlisted", "private"]
}) })
assert [%{"status" => %{"id" => id}}] = json_response(conn_res, 200) assert [%{"status" => %{"id" => id}}] = json_response(conn_res, 200)
assert id == direct_activity.id assert id == direct_activity.id
conn_res = conn_res =
get(conn, "/api/v1/notifications", %{ get(conn, "/api/v1/notifications", %{
exclude_visibilities: ["public", "unlisted", "direct"] exclude_visibilities: ["public", "unlisted", "direct"]
}) })
assert [%{"status" => %{"id" => id}}] = json_response(conn_res, 200) assert [%{"status" => %{"id" => id}}] = json_response(conn_res, 200)
assert id == private_activity.id assert id == private_activity.id
conn_res = conn_res =
get(conn, "/api/v1/notifications", %{ get(conn, "/api/v1/notifications", %{
exclude_visibilities: ["public", "private", "direct"] exclude_visibilities: ["public", "private", "direct"]
}) })
assert [%{"status" => %{"id" => id}}] = json_response(conn_res, 200) assert [%{"status" => %{"id" => id}}] = json_response(conn_res, 200)
assert id == unlisted_activity.id assert id == unlisted_activity.id
conn_res = conn_res =
get(conn, "/api/v1/notifications", %{ get(conn, "/api/v1/notifications", %{
exclude_visibilities: ["unlisted", "private", "direct"] exclude_visibilities: ["unlisted", "private", "direct"]
}) })
assert [%{"status" => %{"id" => id}}] = json_response(conn_res, 200) assert [%{"status" => %{"id" => id}}] = json_response(conn_res, 200)
assert id == public_activity.id assert id == public_activity.id
end
test "filters notifications for Like activities", %{conn: conn} do
user = insert(:user)
other_user = insert(:user)
{:ok, public_activity} =
CommonAPI.post(other_user, %{"status" => ".", "visibility" => "public"})
{:ok, direct_activity} =
CommonAPI.post(other_user, %{"status" => "@#{user.nickname}", "visibility" => "direct"})
{:ok, unlisted_activity} =
CommonAPI.post(other_user, %{"status" => ".", "visibility" => "unlisted"})
{:ok, private_activity} =
CommonAPI.post(other_user, %{"status" => ".", "visibility" => "private"})
{:ok, _, _} = CommonAPI.favorite(public_activity.id, user)
{:ok, _, _} = CommonAPI.favorite(direct_activity.id, user)
{:ok, _, _} = CommonAPI.favorite(unlisted_activity.id, user)
{:ok, _, _} = CommonAPI.favorite(private_activity.id, user)
activity_ids =
conn
|> assign(:user, other_user)
|> get("/api/v1/notifications", %{exclude_visibilities: ["direct"]})
|> json_response(200)
|> Enum.map(& &1["status"]["id"])
assert public_activity.id in activity_ids
assert unlisted_activity.id in activity_ids
assert private_activity.id in activity_ids
refute direct_activity.id in activity_ids
activity_ids =
conn
|> assign(:user, other_user)
|> get("/api/v1/notifications", %{exclude_visibilities: ["unlisted"]})
|> json_response(200)
|> Enum.map(& &1["status"]["id"])
assert public_activity.id in activity_ids
refute unlisted_activity.id in activity_ids
assert private_activity.id in activity_ids
assert direct_activity.id in activity_ids
activity_ids =
conn
|> assign(:user, other_user)
|> get("/api/v1/notifications", %{exclude_visibilities: ["private"]})
|> json_response(200)
|> Enum.map(& &1["status"]["id"])
assert public_activity.id in activity_ids
assert unlisted_activity.id in activity_ids
refute private_activity.id in activity_ids
assert direct_activity.id in activity_ids
activity_ids =
conn
|> assign(:user, other_user)
|> get("/api/v1/notifications", %{exclude_visibilities: ["public"]})
|> json_response(200)
|> Enum.map(& &1["status"]["id"])
refute public_activity.id in activity_ids
assert unlisted_activity.id in activity_ids
assert private_activity.id in activity_ids
assert direct_activity.id in activity_ids
end
test "filters notifications for Announce activities", %{conn: conn} do
user = insert(:user)
other_user = insert(:user)
{:ok, public_activity} =
CommonAPI.post(other_user, %{"status" => ".", "visibility" => "public"})
{:ok, unlisted_activity} =
CommonAPI.post(other_user, %{"status" => ".", "visibility" => "unlisted"})
{:ok, _, _} = CommonAPI.repeat(public_activity.id, user)
{:ok, _, _} = CommonAPI.repeat(unlisted_activity.id, user)
activity_ids =
conn
|> assign(:user, other_user)
|> get("/api/v1/notifications", %{exclude_visibilities: ["unlisted"]})
|> json_response(200)
|> Enum.map(& &1["status"]["id"])
assert public_activity.id in activity_ids
refute unlisted_activity.id in activity_ids
end
end end
test "filters notifications using exclude_types", %{conn: conn} do test "filters notifications using exclude_types", %{conn: conn} do