forked from AkkomaGang/akkoma
replies filtering for blocked domains
This commit is contained in:
parent
7e6ec778d9
commit
19f468c5bc
5 changed files with 15 additions and 95 deletions
|
@ -228,24 +228,16 @@ defp fetch_public_timeline(user, :only_media) do
|
||||||
fetch_public_timeline(opts, "public timeline only media")
|
fetch_public_timeline(opts, "public timeline only media")
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: remove using `:method` after benchmarks
|
|
||||||
defp fetch_public_timeline(user, :with_blocks) do
|
defp fetch_public_timeline(user, :with_blocks) do
|
||||||
opts = opts_for_public_timeline(user)
|
opts = opts_for_public_timeline(user)
|
||||||
|
|
||||||
remote_non_friends = Agent.get(:non_friends_remote, & &1)
|
remote_non_friends = Agent.get(:non_friends_remote, & &1)
|
||||||
|
|
||||||
Benchee.run(
|
Benchee.run(%{
|
||||||
%{
|
"public timeline without blocks" => fn ->
|
||||||
"public timeline without blocks" => fn opts ->
|
ActivityPub.fetch_public_activities(opts)
|
||||||
ActivityPub.fetch_public_activities(opts)
|
end
|
||||||
end
|
})
|
||||||
},
|
|
||||||
inputs: %{
|
|
||||||
"old filtering" => Map.delete(opts, :method),
|
|
||||||
"with psql fun" => Map.put(opts, :method, :fun),
|
|
||||||
"with unnest" => Map.put(opts, :method, :unnest)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
Enum.each(remote_non_friends, fn non_friend ->
|
Enum.each(remote_non_friends, fn non_friend ->
|
||||||
{:ok, _} = User.block(user, non_friend)
|
{:ok, _} = User.block(user, non_friend)
|
||||||
|
@ -257,15 +249,10 @@ defp fetch_public_timeline(user, :with_blocks) do
|
||||||
|
|
||||||
Benchee.run(
|
Benchee.run(
|
||||||
%{
|
%{
|
||||||
"public timeline with user block" => fn opts ->
|
"public timeline with user block" => fn ->
|
||||||
ActivityPub.fetch_public_activities(opts)
|
ActivityPub.fetch_public_activities(opts)
|
||||||
end
|
end
|
||||||
},
|
},
|
||||||
inputs: %{
|
|
||||||
"old filtering" => Map.delete(opts, :method),
|
|
||||||
"with psql fun" => Map.put(opts, :method, :fun),
|
|
||||||
"with unnest" => Map.put(opts, :method, :unnest)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
domains =
|
domains =
|
||||||
|
@ -289,11 +276,6 @@ defp fetch_public_timeline(user, :with_blocks) do
|
||||||
"public timeline with domain block" => fn opts ->
|
"public timeline with domain block" => fn opts ->
|
||||||
ActivityPub.fetch_public_activities(opts)
|
ActivityPub.fetch_public_activities(opts)
|
||||||
end
|
end
|
||||||
},
|
|
||||||
inputs: %{
|
|
||||||
"old filtering" => Map.delete(opts, :method),
|
|
||||||
"with psql fun" => Map.put(opts, :method, :fun),
|
|
||||||
"with unnest" => Map.put(opts, :method, :unnest)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -932,37 +932,16 @@ defp restrict_blocked(query, %{"blocking_user" => %User{} = user} = opts) do
|
||||||
query =
|
query =
|
||||||
if has_named_binding?(query, :object), do: query, else: Activity.with_joined_object(query)
|
if has_named_binding?(query, :object), do: query, else: Activity.with_joined_object(query)
|
||||||
|
|
||||||
# TODO: update after benchmarks
|
|
||||||
query =
|
|
||||||
case opts[:method] do
|
|
||||||
:fun ->
|
|
||||||
from(a in query,
|
|
||||||
where:
|
|
||||||
fragment(
|
|
||||||
"recipients_contain_blocked_domains(?, ?) = false",
|
|
||||||
a.recipients,
|
|
||||||
^domain_blocks
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
:unnest ->
|
|
||||||
from(a in query,
|
|
||||||
where:
|
|
||||||
fragment(
|
|
||||||
"NOT ? && (SELECT ARRAY(SELECT split_part(UNNEST(?), '/', 3)))",
|
|
||||||
^domain_blocks,
|
|
||||||
a.recipients
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
query
|
|
||||||
end
|
|
||||||
|
|
||||||
from(
|
from(
|
||||||
[activity, object: o] in query,
|
[activity, object: o] in query,
|
||||||
where: fragment("not (? = ANY(?))", activity.actor, ^blocked_ap_ids),
|
where: fragment("not (? = ANY(?))", activity.actor, ^blocked_ap_ids),
|
||||||
where: fragment("not (? && ?)", activity.recipients, ^blocked_ap_ids),
|
where: fragment("not (? && ?)", activity.recipients, ^blocked_ap_ids),
|
||||||
|
where:
|
||||||
|
fragment(
|
||||||
|
"recipients_contain_blocked_domains(?, ?) = false",
|
||||||
|
activity.recipients,
|
||||||
|
^domain_blocks
|
||||||
|
),
|
||||||
where:
|
where:
|
||||||
fragment(
|
fragment(
|
||||||
"not (?->>'type' = 'Announce' and ?->'to' \\?| ?)",
|
"not (?->>'type' = 'Announce' and ?->'to' \\?| ?)",
|
||||||
|
|
|
@ -62,13 +62,6 @@ def public_operation do
|
||||||
only_media_param(),
|
only_media_param(),
|
||||||
with_muted_param(),
|
with_muted_param(),
|
||||||
exclude_visibilities_param(),
|
exclude_visibilities_param(),
|
||||||
# TODO: remove after benchmarks
|
|
||||||
Operation.parameter(
|
|
||||||
:method,
|
|
||||||
:query,
|
|
||||||
%Schema{type: :string},
|
|
||||||
"Temp parameter"
|
|
||||||
),
|
|
||||||
reply_visibility_param() | pagination_params()
|
reply_visibility_param() | pagination_params()
|
||||||
],
|
],
|
||||||
operationId: "TimelineController.public",
|
operationId: "TimelineController.public",
|
||||||
|
|
|
@ -109,23 +109,14 @@ def public(%{assigns: %{user: user}} = conn, params) do
|
||||||
if restrict? and is_nil(user) do
|
if restrict? and is_nil(user) do
|
||||||
render_error(conn, :unauthorized, "authorization required for timeline view")
|
render_error(conn, :unauthorized, "authorization required for timeline view")
|
||||||
else
|
else
|
||||||
# TODO: return back after benchmarks
|
activities =
|
||||||
params =
|
|
||||||
params
|
params
|
||||||
|> Map.put("type", ["Create", "Announce"])
|
|> Map.put("type", ["Create", "Announce"])
|
||||||
|> Map.put("local_only", local_only)
|
|> Map.put("local_only", local_only)
|
||||||
|> Map.put("blocking_user", user)
|
|> Map.put("blocking_user", user)
|
||||||
|> Map.put("muting_user", user)
|
|> Map.put("muting_user", user)
|
||||||
|> Map.put("reply_filtering_user", user)
|
|> Map.put("reply_filtering_user", user)
|
||||||
|
|> ActivityPub.fetch_public_activities()
|
||||||
params =
|
|
||||||
if params["method"] do
|
|
||||||
Map.put(params, :method, String.to_existing_atom(params["method"]))
|
|
||||||
else
|
|
||||||
params
|
|
||||||
end
|
|
||||||
|
|
||||||
activities = ActivityPub.fetch_public_activities(params)
|
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> add_link_headers(activities, %{"local" => local_only})
|
|> add_link_headers(activities, %{"local" => local_only})
|
||||||
|
|
|
@ -111,7 +111,6 @@ test "doesn't return replies if follower is posting with blocked user" do
|
||||||
[%{"id" => ^activity_id}] = json_response_and_validate_schema(res_conn, 200)
|
[%{"id" => ^activity_id}] = json_response_and_validate_schema(res_conn, 200)
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: update after benchmarks
|
|
||||||
test "doesn't return replies if follow is posting with users from blocked domain" do
|
test "doesn't return replies if follow is posting with users from blocked domain" do
|
||||||
%{conn: conn, user: blocker} = oauth_access(["read:statuses"])
|
%{conn: conn, user: blocker} = oauth_access(["read:statuses"])
|
||||||
friend = insert(:user)
|
friend = insert(:user)
|
||||||
|
@ -129,31 +128,7 @@ test "doesn't return replies if follow is posting with users from blocked domain
|
||||||
{:ok, _reply_from_friend} =
|
{:ok, _reply_from_friend} =
|
||||||
CommonAPI.post(friend, %{status: "status", in_reply_to_status_id: reply_from_blockee})
|
CommonAPI.post(friend, %{status: "status", in_reply_to_status_id: reply_from_blockee})
|
||||||
|
|
||||||
res_conn = get(conn, "/api/v1/timelines/public?method=fun")
|
res_conn = get(conn, "/api/v1/timelines/public")
|
||||||
|
|
||||||
activities = json_response_and_validate_schema(res_conn, 200)
|
|
||||||
[%{"id" => ^activity_id}] = activities
|
|
||||||
end
|
|
||||||
|
|
||||||
# TODO: update after benchmarks
|
|
||||||
test "doesn't return replies if follow is posting with users from blocked domain with unnest param" do
|
|
||||||
%{conn: conn, user: blocker} = oauth_access(["read:statuses"])
|
|
||||||
friend = insert(:user)
|
|
||||||
blockee = insert(:user, ap_id: "https://example.com/users/blocked")
|
|
||||||
{:ok, blocker} = User.follow(blocker, friend)
|
|
||||||
{:ok, blocker} = User.block_domain(blocker, "example.com")
|
|
||||||
|
|
||||||
conn = assign(conn, :user, blocker)
|
|
||||||
|
|
||||||
{:ok, %{id: activity_id} = activity} = CommonAPI.post(friend, %{status: "hey!"})
|
|
||||||
|
|
||||||
{:ok, reply_from_blockee} =
|
|
||||||
CommonAPI.post(blockee, %{status: "heya", in_reply_to_status_id: activity})
|
|
||||||
|
|
||||||
{:ok, _reply_from_friend} =
|
|
||||||
CommonAPI.post(friend, %{status: "status", in_reply_to_status_id: reply_from_blockee})
|
|
||||||
|
|
||||||
res_conn = get(conn, "/api/v1/timelines/public?method=unnest")
|
|
||||||
|
|
||||||
activities = json_response_and_validate_schema(res_conn, 200)
|
activities = json_response_and_validate_schema(res_conn, 200)
|
||||||
[%{"id" => ^activity_id}] = activities
|
[%{"id" => ^activity_id}] = activities
|
||||||
|
|
Loading…
Reference in a new issue