623 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			Elixir
		
	
	
	
	
	
			
		
		
	
	
			623 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			Elixir
		
	
	
	
	
	
| defmodule Pleroma.LoadTesting.Fetcher do
 | |
|   alias Pleroma.Activity
 | |
|   alias Pleroma.Pagination
 | |
|   alias Pleroma.Repo
 | |
|   alias Pleroma.User
 | |
|   alias Pleroma.Web.ActivityPub.ActivityPub
 | |
|   alias Pleroma.Web.MastodonAPI.MastodonAPI
 | |
|   alias Pleroma.Web.MastodonAPI.StatusView
 | |
| 
 | |
|   @spec run_benchmarks(User.t()) :: any()
 | |
|   def run_benchmarks(user) do
 | |
|     fetch_user(user)
 | |
|     fetch_timelines(user)
 | |
|     render_views(user)
 | |
|   end
 | |
| 
 | |
|   defp formatters do
 | |
|     [
 | |
|       Benchee.Formatters.Console
 | |
|     ]
 | |
|   end
 | |
| 
 | |
|   defp fetch_user(user) do
 | |
|     Benchee.run(
 | |
|       %{
 | |
|         "By id" => fn -> Repo.get_by(User, id: user.id) end,
 | |
|         "By ap_id" => fn -> Repo.get_by(User, ap_id: user.ap_id) end,
 | |
|         "By email" => fn -> Repo.get_by(User, email: user.email) end,
 | |
|         "By nickname" => fn -> Repo.get_by(User, nickname: user.nickname) end
 | |
|       },
 | |
|       formatters: formatters()
 | |
|     )
 | |
|   end
 | |
| 
 | |
|   defp create_filter(user) do
 | |
|     Pleroma.Filter.create(%Pleroma.Filter{
 | |
|       user_id: user.id,
 | |
|       phrase: "must be filtered",
 | |
|       hide: true
 | |
|     })
 | |
|   end
 | |
| 
 | |
|   defp delete_filter(filter), do: Repo.delete(filter)
 | |
| 
 | |
|   defp fetch_timelines(user) do
 | |
|     fetch_home_timeline(user)
 | |
|     fetch_home_timeline_with_filter(user)
 | |
|     fetch_direct_timeline(user)
 | |
|     fetch_public_timeline(user)
 | |
|     fetch_public_timeline_with_filter(user)
 | |
|     fetch_public_timeline(user, :with_blocks)
 | |
|     fetch_public_timeline(user, :local)
 | |
|     fetch_public_timeline(user, :tag)
 | |
|     fetch_notifications(user)
 | |
|     fetch_favourites(user)
 | |
|     fetch_long_thread(user)
 | |
|     fetch_timelines_with_reply_filtering(user)
 | |
|   end
 | |
| 
 | |
|   defp render_views(user) do
 | |
|     render_timelines(user)
 | |
|     render_long_thread(user)
 | |
|   end
 | |
| 
 | |
|   defp opts_for_home_timeline(user) do
 | |
|     %{
 | |
|       blocking_user: user,
 | |
|       count: "20",
 | |
|       muting_user: user,
 | |
|       type: ["Create", "Announce"],
 | |
|       user: user,
 | |
|       with_muted: true
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   defp fetch_home_timeline(user, title_end \\ "") do
 | |
|     opts = opts_for_home_timeline(user)
 | |
| 
 | |
|     recipients = [user.ap_id | User.following(user)]
 | |
| 
 | |
|     first_page_last =
 | |
|       ActivityPub.fetch_activities(recipients, opts) |> Enum.reverse() |> List.last()
 | |
| 
 | |
|     second_page_last =
 | |
|       ActivityPub.fetch_activities(recipients, Map.put(opts, :max_id, first_page_last.id))
 | |
|       |> Enum.reverse()
 | |
|       |> List.last()
 | |
| 
 | |
|     third_page_last =
 | |
|       ActivityPub.fetch_activities(recipients, Map.put(opts, :max_id, second_page_last.id))
 | |
|       |> Enum.reverse()
 | |
|       |> List.last()
 | |
| 
 | |
|     forth_page_last =
 | |
|       ActivityPub.fetch_activities(recipients, Map.put(opts, :max_id, third_page_last.id))
 | |
|       |> Enum.reverse()
 | |
|       |> List.last()
 | |
| 
 | |
|     title = "home timeline " <> title_end
 | |
| 
 | |
|     Benchee.run(
 | |
|       %{
 | |
|         title => fn opts -> ActivityPub.fetch_activities(recipients, opts) end
 | |
|       },
 | |
|       inputs: %{
 | |
|         "1 page" => opts,
 | |
|         "2 page" => Map.put(opts, :max_id, first_page_last.id),
 | |
|         "3 page" => Map.put(opts, :max_id, second_page_last.id),
 | |
|         "4 page" => Map.put(opts, :max_id, third_page_last.id),
 | |
|         "5 page" => Map.put(opts, :max_id, forth_page_last.id),
 | |
|         "1 page only media" => Map.put(opts, :only_media, true),
 | |
|         "2 page only media" =>
 | |
|           Map.put(opts, :max_id, first_page_last.id) |> Map.put(:only_media, true),
 | |
|         "3 page only media" =>
 | |
|           Map.put(opts, :max_id, second_page_last.id) |> Map.put(:only_media, true),
 | |
|         "4 page only media" =>
 | |
|           Map.put(opts, :max_id, third_page_last.id) |> Map.put(:only_media, true),
 | |
|         "5 page only media" =>
 | |
|           Map.put(opts, :max_id, forth_page_last.id) |> Map.put(:only_media, true)
 | |
|       },
 | |
|       formatters: formatters()
 | |
|     )
 | |
|   end
 | |
| 
 | |
|   defp fetch_home_timeline_with_filter(user) do
 | |
|     {:ok, filter} = create_filter(user)
 | |
| 
 | |
|     fetch_home_timeline(user, "with filters")
 | |
| 
 | |
|     delete_filter(filter)
 | |
|   end
 | |
| 
 | |
|   defp opts_for_direct_timeline(user) do
 | |
|     %{
 | |
|       visibility: "direct",
 | |
|       blocking_user: user,
 | |
|       count: "20",
 | |
|       type: "Create",
 | |
|       user: user,
 | |
|       with_muted: true
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   defp fetch_direct_timeline(user) do
 | |
|     recipients = [user.ap_id]
 | |
| 
 | |
|     opts = opts_for_direct_timeline(user)
 | |
| 
 | |
|     first_page_last =
 | |
|       recipients
 | |
|       |> ActivityPub.fetch_activities_query(opts)
 | |
|       |> Pagination.fetch_paginated(opts)
 | |
|       |> List.last()
 | |
| 
 | |
|     opts2 = Map.put(opts, :max_id, first_page_last.id)
 | |
| 
 | |
|     second_page_last =
 | |
|       recipients
 | |
|       |> ActivityPub.fetch_activities_query(opts2)
 | |
|       |> Pagination.fetch_paginated(opts2)
 | |
|       |> List.last()
 | |
| 
 | |
|     opts3 = Map.put(opts, :max_id, second_page_last.id)
 | |
| 
 | |
|     third_page_last =
 | |
|       recipients
 | |
|       |> ActivityPub.fetch_activities_query(opts3)
 | |
|       |> Pagination.fetch_paginated(opts3)
 | |
|       |> List.last()
 | |
| 
 | |
|     opts4 = Map.put(opts, :max_id, third_page_last.id)
 | |
| 
 | |
|     forth_page_last =
 | |
|       recipients
 | |
|       |> ActivityPub.fetch_activities_query(opts4)
 | |
|       |> Pagination.fetch_paginated(opts4)
 | |
|       |> List.last()
 | |
| 
 | |
|     Benchee.run(
 | |
|       %{
 | |
|         "direct timeline" => fn opts ->
 | |
|           ActivityPub.fetch_activities_query(recipients, opts) |> Pagination.fetch_paginated(opts)
 | |
|         end
 | |
|       },
 | |
|       inputs: %{
 | |
|         "1 page" => opts,
 | |
|         "2 page" => opts2,
 | |
|         "3 page" => opts3,
 | |
|         "4 page" => opts4,
 | |
|         "5 page" => Map.put(opts4, :max_id, forth_page_last.id)
 | |
|       },
 | |
|       formatters: formatters()
 | |
|     )
 | |
|   end
 | |
| 
 | |
|   defp opts_for_public_timeline(user) do
 | |
|     %{
 | |
|       type: ["Create", "Announce"],
 | |
|       local_only: false,
 | |
|       blocking_user: user,
 | |
|       muting_user: user
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   defp opts_for_public_timeline(user, :local) do
 | |
|     %{
 | |
|       type: ["Create", "Announce"],
 | |
|       local_only: true,
 | |
|       blocking_user: user,
 | |
|       muting_user: user
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   defp opts_for_public_timeline(user, :tag) do
 | |
|     %{
 | |
|       blocking_user: user,
 | |
|       count: "20",
 | |
|       local_only: nil,
 | |
|       muting_user: user,
 | |
|       tag: ["tag"],
 | |
|       tag_all: [],
 | |
|       tag_reject: [],
 | |
|       type: "Create",
 | |
|       user: user,
 | |
|       with_muted: true
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   defp fetch_public_timeline(user) do
 | |
|     opts = opts_for_public_timeline(user)
 | |
| 
 | |
|     fetch_public_timeline(opts, "public timeline")
 | |
|   end
 | |
| 
 | |
|   defp fetch_public_timeline_with_filter(user) do
 | |
|     {:ok, filter} = create_filter(user)
 | |
|     opts = opts_for_public_timeline(user)
 | |
| 
 | |
|     fetch_public_timeline(opts, "public timeline with filters")
 | |
|     delete_filter(filter)
 | |
|   end
 | |
| 
 | |
|   defp fetch_public_timeline(user, :local) do
 | |
|     opts = opts_for_public_timeline(user, :local)
 | |
| 
 | |
|     fetch_public_timeline(opts, "public timeline only local")
 | |
|   end
 | |
| 
 | |
|   defp fetch_public_timeline(user, :tag) do
 | |
|     opts = opts_for_public_timeline(user, :tag)
 | |
| 
 | |
|     fetch_public_timeline(opts, "hashtag timeline")
 | |
|   end
 | |
| 
 | |
|   defp fetch_public_timeline(user, :only_media) do
 | |
|     opts = opts_for_public_timeline(user) |> Map.put(:only_media, true)
 | |
| 
 | |
|     fetch_public_timeline(opts, "public timeline only media")
 | |
|   end
 | |
| 
 | |
|   defp fetch_public_timeline(user, :with_blocks) do
 | |
|     opts = opts_for_public_timeline(user)
 | |
| 
 | |
|     remote_non_friends = Agent.get(:non_friends_remote, & &1)
 | |
| 
 | |
|     Benchee.run(%{
 | |
|       "public timeline without blocks" => fn ->
 | |
|         ActivityPub.fetch_public_activities(opts)
 | |
|       end
 | |
|     })
 | |
| 
 | |
|     Enum.each(remote_non_friends, fn non_friend ->
 | |
|       {:ok, _} = User.block(user, non_friend)
 | |
|     end)
 | |
| 
 | |
|     user = User.get_by_id(user.id)
 | |
| 
 | |
|     opts = Map.put(opts, :blocking_user, user)
 | |
| 
 | |
|     Benchee.run(%{
 | |
|       "public timeline with user block" => fn ->
 | |
|         ActivityPub.fetch_public_activities(opts)
 | |
|       end
 | |
|     })
 | |
| 
 | |
|     domains =
 | |
|       Enum.reduce(remote_non_friends, [], fn non_friend, domains ->
 | |
|         {:ok, _user} = User.unblock(user, non_friend)
 | |
|         %{host: host} = URI.parse(non_friend.ap_id)
 | |
|         [host | domains]
 | |
|       end)
 | |
| 
 | |
|     domains = Enum.uniq(domains)
 | |
| 
 | |
|     Enum.each(domains, fn domain ->
 | |
|       {:ok, _} = User.block_domain(user, domain)
 | |
|     end)
 | |
| 
 | |
|     user = User.get_by_id(user.id)
 | |
|     opts = Map.put(opts, :blocking_user, user)
 | |
| 
 | |
|     Benchee.run(%{
 | |
|       "public timeline with domain block" => fn ->
 | |
|         ActivityPub.fetch_public_activities(opts)
 | |
|       end
 | |
|     })
 | |
|   end
 | |
| 
 | |
|   defp fetch_public_timeline(opts, title) when is_binary(title) do
 | |
|     first_page_last = ActivityPub.fetch_public_activities(opts) |> List.last()
 | |
| 
 | |
|     second_page_last =
 | |
|       ActivityPub.fetch_public_activities(Map.put(opts, :max_id, first_page_last.id))
 | |
|       |> List.last()
 | |
| 
 | |
|     third_page_last =
 | |
|       ActivityPub.fetch_public_activities(Map.put(opts, :max_id, second_page_last.id))
 | |
|       |> List.last()
 | |
| 
 | |
|     forth_page_last =
 | |
|       ActivityPub.fetch_public_activities(Map.put(opts, :max_id, third_page_last.id))
 | |
|       |> List.last()
 | |
| 
 | |
|     Benchee.run(
 | |
|       %{
 | |
|         title => fn opts ->
 | |
|           ActivityPub.fetch_public_activities(opts)
 | |
|         end
 | |
|       },
 | |
|       inputs: %{
 | |
|         "1 page" => opts,
 | |
|         "2 page" => Map.put(opts, :max_id, first_page_last.id),
 | |
|         "3 page" => Map.put(opts, :max_id, second_page_last.id),
 | |
|         "4 page" => Map.put(opts, :max_id, third_page_last.id),
 | |
|         "5 page" => Map.put(opts, :max_id, forth_page_last.id)
 | |
|       },
 | |
|       formatters: formatters()
 | |
|     )
 | |
|   end
 | |
| 
 | |
|   defp opts_for_notifications do
 | |
|     %{count: "20", with_muted: true}
 | |
|   end
 | |
| 
 | |
|   defp fetch_notifications(user) do
 | |
|     opts = opts_for_notifications()
 | |
| 
 | |
|     first_page_last = MastodonAPI.get_notifications(user, opts) |> List.last()
 | |
| 
 | |
|     second_page_last =
 | |
|       MastodonAPI.get_notifications(user, Map.put(opts, :max_id, first_page_last.id))
 | |
|       |> List.last()
 | |
| 
 | |
|     third_page_last =
 | |
|       MastodonAPI.get_notifications(user, Map.put(opts, :max_id, second_page_last.id))
 | |
|       |> List.last()
 | |
| 
 | |
|     forth_page_last =
 | |
|       MastodonAPI.get_notifications(user, Map.put(opts, :max_id, third_page_last.id))
 | |
|       |> List.last()
 | |
| 
 | |
|     Benchee.run(
 | |
|       %{
 | |
|         "Notifications" => fn opts ->
 | |
|           MastodonAPI.get_notifications(user, opts)
 | |
|         end
 | |
|       },
 | |
|       inputs: %{
 | |
|         "1 page" => opts,
 | |
|         "2 page" => Map.put(opts, :max_id, first_page_last.id),
 | |
|         "3 page" => Map.put(opts, :max_id, second_page_last.id),
 | |
|         "4 page" => Map.put(opts, :max_id, third_page_last.id),
 | |
|         "5 page" => Map.put(opts, :max_id, forth_page_last.id)
 | |
|       },
 | |
|       formatters: formatters()
 | |
|     )
 | |
|   end
 | |
| 
 | |
|   defp fetch_favourites(user) do
 | |
|     first_page_last = ActivityPub.fetch_favourites(user) |> List.last()
 | |
| 
 | |
|     second_page_last =
 | |
|       ActivityPub.fetch_favourites(user, %{:max_id => first_page_last.id}) |> List.last()
 | |
| 
 | |
|     third_page_last =
 | |
|       ActivityPub.fetch_favourites(user, %{:max_id => second_page_last.id}) |> List.last()
 | |
| 
 | |
|     forth_page_last =
 | |
|       ActivityPub.fetch_favourites(user, %{:max_id => third_page_last.id}) |> List.last()
 | |
| 
 | |
|     Benchee.run(
 | |
|       %{
 | |
|         "Favourites" => fn opts ->
 | |
|           ActivityPub.fetch_favourites(user, opts)
 | |
|         end
 | |
|       },
 | |
|       inputs: %{
 | |
|         "1 page" => %{},
 | |
|         "2 page" => %{:max_id => first_page_last.id},
 | |
|         "3 page" => %{:max_id => second_page_last.id},
 | |
|         "4 page" => %{:max_id => third_page_last.id},
 | |
|         "5 page" => %{:max_id => forth_page_last.id}
 | |
|       },
 | |
|       formatters: formatters()
 | |
|     )
 | |
|   end
 | |
| 
 | |
|   defp opts_for_long_thread(user) do
 | |
|     %{
 | |
|       blocking_user: user,
 | |
|       user: user
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   defp fetch_long_thread(user) do
 | |
|     %{public_thread: public, private_thread: private} =
 | |
|       Agent.get(:benchmark_state, fn state -> state end)
 | |
| 
 | |
|     opts = opts_for_long_thread(user)
 | |
| 
 | |
|     private_input = {private.data["context"], Map.put(opts, :exclude_id, private.id)}
 | |
| 
 | |
|     public_input = {public.data["context"], Map.put(opts, :exclude_id, public.id)}
 | |
| 
 | |
|     Benchee.run(
 | |
|       %{
 | |
|         "fetch context" => fn {context, opts} ->
 | |
|           ActivityPub.fetch_activities_for_context(context, opts)
 | |
|         end
 | |
|       },
 | |
|       inputs: %{
 | |
|         "Private long thread" => private_input,
 | |
|         "Public long thread" => public_input
 | |
|       },
 | |
|       formatters: formatters()
 | |
|     )
 | |
|   end
 | |
| 
 | |
|   defp render_timelines(user) do
 | |
|     opts = opts_for_home_timeline(user)
 | |
| 
 | |
|     recipients = [user.ap_id | User.following(user)]
 | |
| 
 | |
|     home_activities = ActivityPub.fetch_activities(recipients, opts) |> Enum.reverse()
 | |
| 
 | |
|     recipients = [user.ap_id]
 | |
| 
 | |
|     opts = opts_for_direct_timeline(user)
 | |
| 
 | |
|     direct_activities =
 | |
|       recipients
 | |
|       |> ActivityPub.fetch_activities_query(opts)
 | |
|       |> Pagination.fetch_paginated(opts)
 | |
| 
 | |
|     opts = opts_for_public_timeline(user)
 | |
| 
 | |
|     public_activities = ActivityPub.fetch_public_activities(opts)
 | |
| 
 | |
|     opts = opts_for_public_timeline(user, :tag)
 | |
| 
 | |
|     tag_activities = ActivityPub.fetch_public_activities(opts)
 | |
| 
 | |
|     opts = opts_for_notifications()
 | |
| 
 | |
|     notifications = MastodonAPI.get_notifications(user, opts)
 | |
| 
 | |
|     favourites = ActivityPub.fetch_favourites(user)
 | |
| 
 | |
|     Benchee.run(
 | |
|       %{
 | |
|         "Rendering home timeline" => fn ->
 | |
|           StatusView.render("index.json", %{
 | |
|             activities: home_activities,
 | |
|             for: user,
 | |
|             as: :activity
 | |
|           })
 | |
|         end,
 | |
|         "Rendering direct timeline" => fn ->
 | |
|           StatusView.render("index.json", %{
 | |
|             activities: direct_activities,
 | |
|             for: user,
 | |
|             as: :activity
 | |
|           })
 | |
|         end,
 | |
|         "Rendering public timeline" => fn ->
 | |
|           StatusView.render("index.json", %{
 | |
|             activities: public_activities,
 | |
|             for: user,
 | |
|             as: :activity
 | |
|           })
 | |
|         end,
 | |
|         "Rendering tag timeline" => fn ->
 | |
|           StatusView.render("index.json", %{
 | |
|             activities: tag_activities,
 | |
|             for: user,
 | |
|             as: :activity
 | |
|           })
 | |
|         end,
 | |
|         "Rendering notifications" => fn ->
 | |
|           Pleroma.Web.MastodonAPI.NotificationView.render("index.json", %{
 | |
|             notifications: notifications,
 | |
|             for: user
 | |
|           })
 | |
|         end,
 | |
|         "Rendering favourites timeline" => fn ->
 | |
|           StatusView.render("index.json", %{
 | |
|             activities: favourites,
 | |
|             for: user,
 | |
|             as: :activity
 | |
|           })
 | |
|         end
 | |
|       },
 | |
|       formatters: formatters()
 | |
|     )
 | |
|   end
 | |
| 
 | |
|   defp render_long_thread(user) do
 | |
|     %{public_thread: public, private_thread: private} =
 | |
|       Agent.get(:benchmark_state, fn state -> state end)
 | |
| 
 | |
|     opts = %{for: user}
 | |
|     public_activity = Activity.get_by_id_with_object(public.id)
 | |
|     private_activity = Activity.get_by_id_with_object(private.id)
 | |
| 
 | |
|     Benchee.run(
 | |
|       %{
 | |
|         "render" => fn opts ->
 | |
|           StatusView.render("show.json", opts)
 | |
|         end
 | |
|       },
 | |
|       inputs: %{
 | |
|         "Public root" => Map.put(opts, :activity, public_activity),
 | |
|         "Private root" => Map.put(opts, :activity, private_activity)
 | |
|       },
 | |
|       formatters: formatters()
 | |
|     )
 | |
| 
 | |
|     fetch_opts = opts_for_long_thread(user)
 | |
| 
 | |
|     public_context =
 | |
|       ActivityPub.fetch_activities_for_context(
 | |
|         public.data["context"],
 | |
|         Map.put(fetch_opts, :exclude_id, public.id)
 | |
|       )
 | |
| 
 | |
|     private_context =
 | |
|       ActivityPub.fetch_activities_for_context(
 | |
|         private.data["context"],
 | |
|         Map.put(fetch_opts, :exclude_id, private.id)
 | |
|       )
 | |
| 
 | |
|     Benchee.run(
 | |
|       %{
 | |
|         "render" => fn opts ->
 | |
|           StatusView.render("context.json", opts)
 | |
|         end
 | |
|       },
 | |
|       inputs: %{
 | |
|         "Public context" => %{user: user, activity: public_activity, activities: public_context},
 | |
|         "Private context" => %{
 | |
|           user: user,
 | |
|           activity: private_activity,
 | |
|           activities: private_context
 | |
|         }
 | |
|       },
 | |
|       formatters: formatters()
 | |
|     )
 | |
|   end
 | |
| 
 | |
|   defp fetch_timelines_with_reply_filtering(user) do
 | |
|     public_params = opts_for_public_timeline(user)
 | |
| 
 | |
|     Benchee.run(
 | |
|       %{
 | |
|         "Public timeline without reply filtering" => fn ->
 | |
|           ActivityPub.fetch_public_activities(public_params)
 | |
|         end,
 | |
|         "Public timeline with reply filtering - following" => fn ->
 | |
|           public_params
 | |
|           |> Map.put(:reply_visibility, "following")
 | |
|           |> Map.put(:reply_filtering_user, user)
 | |
|           |> ActivityPub.fetch_public_activities()
 | |
|         end,
 | |
|         "Public timeline with reply filtering - self" => fn ->
 | |
|           public_params
 | |
|           |> Map.put(:reply_visibility, "self")
 | |
|           |> Map.put(:reply_filtering_user, user)
 | |
|           |> ActivityPub.fetch_public_activities()
 | |
|         end
 | |
|       },
 | |
|       formatters: formatters()
 | |
|     )
 | |
| 
 | |
|     private_params = opts_for_home_timeline(user)
 | |
| 
 | |
|     recipients = [user.ap_id | User.following(user)]
 | |
| 
 | |
|     Benchee.run(
 | |
|       %{
 | |
|         "Home timeline without reply filtering" => fn ->
 | |
|           ActivityPub.fetch_activities(recipients, private_params)
 | |
|         end,
 | |
|         "Home timeline with reply filtering - following" => fn ->
 | |
|           private_params =
 | |
|             private_params
 | |
|             |> Map.put(:reply_filtering_user, user)
 | |
|             |> Map.put(:reply_visibility, "following")
 | |
| 
 | |
|           ActivityPub.fetch_activities(recipients, private_params)
 | |
|         end,
 | |
|         "Home timeline with reply filtering - self" => fn ->
 | |
|           private_params =
 | |
|             private_params
 | |
|             |> Map.put(:reply_filtering_user, user)
 | |
|             |> Map.put(:reply_visibility, "self")
 | |
| 
 | |
|           ActivityPub.fetch_activities(recipients, private_params)
 | |
|         end
 | |
|       },
 | |
|       formatters: formatters()
 | |
|     )
 | |
|   end
 | |
| end
 | 
