diff --git a/CHANGELOG.md b/CHANGELOG.md index c1e1d01c4..b32ae2e16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +### Added +- support for fedibird-fe, and non-breaking API parity for it to function + ### Fixed - Compatibility with latest meilisearch - Resolution of nested mix tasks (i.e search.meilisearch) in OTP releases diff --git a/config/config.exs b/config/config.exs index f49ec861c..83977da19 100644 --- a/config/config.exs +++ b/config/config.exs @@ -734,6 +734,14 @@ "build_dir" => "distribution", "ref" => "akkoma" }, + "fedibird-fe" => %{ + "name" => "fedibird-fe", + "git" => "https://akkoma.dev/AkkomaGang/fedibird-fe", + "build_url" => + "https://akkoma-updates.s3-website.fr-par.scw.cloud/frontend/${ref}/fedibird-fe.zip", + "build_dir" => "distribution", + "ref" => "akkoma" + }, "admin-fe" => %{ "name" => "admin-fe", "git" => "https://akkoma.dev/AkkomaGang/admin-fe", diff --git a/docs/docs/configuration/frontend_management.md b/docs/docs/configuration/frontend_management.md index a25120589..5e4b9b051 100644 --- a/docs/docs/configuration/frontend_management.md +++ b/docs/docs/configuration/frontend_management.md @@ -19,6 +19,10 @@ config :pleroma, :frontends, admin: %{ "name" => "admin-fe", "ref" => "stable" + }, + mastodon: %{ + "name" => "mastodon-fe", + "ref" => "akkoma" } ``` @@ -26,12 +30,18 @@ This would serve the frontend from the the folder at `$instance_static/frontends Refer to [the frontend CLI task](../../administration/CLI_tasks/frontend) for how to install the frontend's files -If you wish masto-fe to also be enabled, you will also need to run the install task for `mastodon-fe`. Not doing this will lead to the frontend not working. - If you choose not to install a frontend for whatever reason, it is recommended that you enable [`:static_fe`](#static_fe) to allow remote users to click "view remote source". Don't bother with this if you've got no unauthenticated access though. You can also replace the default "no frontend" page by placing an `index.html` file under your `instance/static/` directory. +## Mastodon-FE + +Akkoma supports both [glitchsoc](https://github.com/glitch-soc/mastodon)'s more "vanilla" mastodon frontend, +as well as [fedibird](https://github.com/fedibird/mastodon)'s extended frontend which has near-feature-parity with akkoma (with quoting and reactions). + +To enable either one, you must run the `frontend.install` task for either `mastodon-fe` or `fedibird-fe` (both `--ref akkoma`), then make sure +`:pleroma, :frontends, :mastodon` references the one you want. + ## Swagger (openAPI) documentation viewer If you're a developer and you'd like a human-readable rendering of the diff --git a/lib/pleroma/web/masto_fe_controller.ex b/lib/pleroma/web/masto_fe_controller.ex index d2460f51d..7b6e01aad 100644 --- a/lib/pleroma/web/masto_fe_controller.ex +++ b/lib/pleroma/web/masto_fe_controller.ex @@ -27,9 +27,21 @@ defmodule Pleroma.Web.MastoFEController do def index(conn, _params) do with %{assigns: %{user: %User{} = user, token: %Token{app_id: token_app_id} = token}} <- conn, {:ok, %{id: ^token_app_id}} <- AuthController.local_mastofe_app() do + flavour = + [:frontends, :mastodon] + |> Pleroma.Config.get() + |> Map.get("name", "mastodon-fe") + + index = + if flavour == "fedibird-fe" do + "fedibird.index.html" + else + "glitchsoc.index.html" + end + conn |> put_layout(false) - |> render("index.html", + |> render(index, token: token.token, user: user, custom_emojis: Pleroma.Emoji.get_all() diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index f0fe9a4ba..d099c4901 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -375,6 +375,7 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} emojis: build_emojis(object.data["emoji"]), quote_id: if(quote, do: quote.id, else: nil), quote: maybe_render_quote(quote, opts), + emoji_reactions: emoji_reactions, pleroma: %{ local: activity.local, conversation_id: get_context_id(activity), @@ -589,7 +590,8 @@ defp build_emoji_map(emoji, users, url, current_user) do name: emoji, count: length(users), url: MediaProxy.url(url), - me: !!(current_user && current_user.ap_id in users) + me: !!(current_user && current_user.ap_id in users), + account_ids: Enum.map(users, fn user -> User.get_cached_by_ap_id(user).id end) } end diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex index 861a7ce3e..582e65d70 100644 --- a/lib/pleroma/web/mastodon_api/websocket_handler.ex +++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex @@ -32,8 +32,15 @@ def init(%{qs: qs} = req, state) do req end - {:cowboy_websocket, req, %{user: user, topic: topic, count: 0, timer: nil}, - %{idle_timeout: @timeout}} + {:cowboy_websocket, req, + %{ + user: user, + topic: topic, + count: 0, + timer: nil, + subscriptions: [], + oauth_token: oauth_token + }, %{idle_timeout: @timeout}} else {:error, :bad_topic} -> Logger.debug("#{__MODULE__} bad topic #{inspect(req)}") @@ -65,21 +72,50 @@ def websocket_handle(:pong, state) do # We only receive pings for now def websocket_handle(:ping, state), do: {:ok, state} - def websocket_handle({:text, "ping"}, state) do + def websocket_handle({:text, ping}, state) when ping in ~w[ping PING] do if state.timer, do: Process.cancel_timer(state.timer) {:reply, {:text, "pong"}, %{state | timer: timer()}} end + def websocket_handle({:text, text}, state) do + with {:ok, json} <- Jason.decode(text) do + websocket_handle({:json, json}, state) + else + _ -> + Logger.error("#{__MODULE__} received text frame: #{text}") + {:ok, state} + end + end + + def websocket_handle( + {:json, %{"type" => "subscribe", "stream" => stream_name}}, + %{user: user, oauth_token: token} = state + ) do + with {:ok, topic} <- Streamer.get_topic(stream_name, user, token, %{}) do + new_subscriptions = + [topic | Map.get(state, :subscriptions, [])] + |> Enum.uniq() + + {:ok, _topic} = Streamer.add_socket(topic, user) + + {:ok, Map.put(state, :subscriptions, new_subscriptions)} + else + _ -> + Logger.error("#{__MODULE__} received invalid topic: #{stream_name}") + {:ok, state} + end + end + def websocket_handle(frame, state) do Logger.error("#{__MODULE__} received frame: #{inspect(frame)}") {:ok, state} end - def websocket_info({:render_with_user, view, template, item}, state) do + def websocket_info({:render_with_user, view, template, item, topic}, state) do user = %User{} = User.get_cached_by_ap_id(state.user.ap_id) unless Streamer.filtered_by_user?(user, item) do - websocket_info({:text, view.render(template, item, user)}, %{state | user: user}) + websocket_info({:text, view.render(template, item, user, topic)}, %{state | user: user}) else {:ok, state} end diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex index 1de02faf8..91658587a 100644 --- a/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex @@ -74,6 +74,8 @@ defp filter(reactions, %{emoji: emoji}) when is_binary(emoji) do defp filter(reactions, _), do: reactions def create(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do + emoji = Pleroma.Emoji.maybe_quote(emoji) + with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji) do activity = Activity.get_by_id(activity_id) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index a0310bbb5..647d99278 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -457,6 +457,11 @@ defmodule Pleroma.Web.Router do get("/federation_status", InstancesController, :show) end + scope "/api/v1", Pleroma.Web.PleromaAPI do + pipe_through(:authenticated_api) + put("/statuses/:id/emoji_reactions/:emoji", EmojiReactionController, :create) + end + scope "/api/v1", Pleroma.Web.MastodonAPI do pipe_through(:authenticated_api) diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index 9a4ac1317..d5b1d0678 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -114,6 +114,11 @@ def get_topic("list", _user, _oauth_token, _params) do {:error, :unauthorized} end + # mastodon multi-topic WS + def get_topic(nil, _user, _oauth_token, _params) do + {:ok, :multi} + end + def get_topic(_stream, _user, _oauth_token, _params) do {:error, :bad_topic} end @@ -186,8 +191,8 @@ defp do_stream("direct", item) do end defp do_stream("follow_relationship", item) do - text = StreamerView.render("follow_relationships_update.json", item) user_topic = "user:#{item.follower.id}" + text = StreamerView.render("follow_relationships_update.json", item, user_topic) Logger.debug("Trying to push follow relationship update to #{user_topic}\n\n") @@ -235,7 +240,7 @@ defp do_stream(topic, %Notification{} = item) when topic in ["user", "user:notification"] do Registry.dispatch(@registry, "#{topic}:#{item.user_id}", fn list -> Enum.each(list, fn {pid, _auth} -> - send(pid, {:render_with_user, StreamerView, "notification.json", item}) + send(pid, {:render_with_user, StreamerView, "notification.json", item, topic}) end) end) end @@ -259,7 +264,7 @@ defp do_stream(topic, item) do end defp push_to_socket(topic, %Participation{} = participation) do - rendered = StreamerView.render("conversation.json", participation) + rendered = StreamerView.render("conversation.json", participation, topic) Registry.dispatch(@registry, topic, fn list -> Enum.each(list, fn {pid, _} -> @@ -283,12 +288,12 @@ defp push_to_socket(topic, %Activity{ defp push_to_socket(_topic, %Activity{data: %{"type" => "Delete"}}), do: :noop defp push_to_socket(topic, item) do - anon_render = StreamerView.render("update.json", item) + anon_render = StreamerView.render("update.json", item, topic) Registry.dispatch(@registry, topic, fn list -> Enum.each(list, fn {pid, auth?} -> if auth? do - send(pid, {:render_with_user, StreamerView, "update.json", item}) + send(pid, {:render_with_user, StreamerView, "update.json", item, topic}) else send(pid, {:text, anon_render}) end diff --git a/lib/pleroma/web/templates/masto_fe/fedibird.index.html.eex b/lib/pleroma/web/templates/masto_fe/fedibird.index.html.eex new file mode 100644 index 000000000..02c421831 --- /dev/null +++ b/lib/pleroma/web/templates/masto_fe/fedibird.index.html.eex @@ -0,0 +1,34 @@ + + + + + + +<%= Config.get([:instance, :name]) %> + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + diff --git a/lib/pleroma/web/templates/masto_fe/index.html.eex b/lib/pleroma/web/templates/masto_fe/glitchsoc.index.html.eex similarity index 100% rename from lib/pleroma/web/templates/masto_fe/index.html.eex rename to lib/pleroma/web/templates/masto_fe/glitchsoc.index.html.eex diff --git a/lib/pleroma/web/views/masto_fe_view.ex b/lib/pleroma/web/views/masto_fe_view.ex index 63a9c8179..305368c9d 100644 --- a/lib/pleroma/web/views/masto_fe_view.ex +++ b/lib/pleroma/web/views/masto_fe_view.ex @@ -14,6 +14,7 @@ def initial_state(token, user, custom_emojis) do %{ meta: %{ + title: Config.get([:instance, :name]), streaming_api_base_url: Pleroma.Web.Endpoint.websocket_url(), access_token: token, locale: "en", @@ -27,7 +28,11 @@ def initial_state(token, user, custom_emojis) do display_sensitive_media: false, reduce_motion: false, max_toot_chars: limit, - mascot: User.get_mascot(user)["url"] + mascot: User.get_mascot(user)["url"], + show_quote_button: true, + enable_reaction: true, + compact_reaction: false, + advanced_layout: true }, poll_limits: Config.get([:instance, :poll_limits]), rights: %{ @@ -56,6 +61,7 @@ def initial_state(token, user, custom_emojis) do "video\/mp4" ] }, + lists: [], settings: user.mastofe_settings || %{}, push_subscription: nil, accounts: %{user.id => render(AccountView, "show.json", user: user, for: user)}, diff --git a/lib/pleroma/web/views/streamer_view.ex b/lib/pleroma/web/views/streamer_view.ex index de2e4d1e9..f455f941e 100644 --- a/lib/pleroma/web/views/streamer_view.ex +++ b/lib/pleroma/web/views/streamer_view.ex @@ -11,8 +11,9 @@ defmodule Pleroma.Web.StreamerView do alias Pleroma.User alias Pleroma.Web.MastodonAPI.NotificationView - def render("update.json", %Activity{} = activity, %User{} = user) do + def render("update.json", %Activity{} = activity, %User{} = user, topic) do %{ + stream: [topic], event: "update", payload: Pleroma.Web.MastodonAPI.StatusView.render( @@ -25,8 +26,9 @@ def render("update.json", %Activity{} = activity, %User{} = user) do |> Jason.encode!() end - def render("notification.json", %Notification{} = notify, %User{} = user) do + def render("notification.json", %Notification{} = notify, %User{} = user, topic) do %{ + stream: [topic], event: "notification", payload: NotificationView.render( @@ -38,8 +40,9 @@ def render("notification.json", %Notification{} = notify, %User{} = user) do |> Jason.encode!() end - def render("update.json", %Activity{} = activity) do + def render("update.json", %Activity{} = activity, topic) do %{ + stream: [topic], event: "update", payload: Pleroma.Web.MastodonAPI.StatusView.render( @@ -51,8 +54,9 @@ def render("update.json", %Activity{} = activity) do |> Jason.encode!() end - def render("follow_relationships_update.json", item) do + def render("follow_relationships_update.json", item, topic) do %{ + stream: [topic], event: "pleroma:follow_relationships_update", payload: %{ @@ -73,8 +77,9 @@ def render("follow_relationships_update.json", item) do |> Jason.encode!() end - def render("conversation.json", %Participation{} = participation) do + def render("conversation.json", %Participation{} = participation, topic) do %{ + stream: [topic], event: "conversation", payload: Pleroma.Web.MastodonAPI.ConversationView.render("participation.json", %{ diff --git a/test/pleroma/integration/mastodon_websocket_test.exs b/test/pleroma/integration/mastodon_websocket_test.exs index 43ec57893..356bfa48d 100644 --- a/test/pleroma/integration/mastodon_websocket_test.exs +++ b/test/pleroma/integration/mastodon_websocket_test.exs @@ -31,9 +31,9 @@ def start_socket(qs \\ nil, headers \\ []) do WebsocketClient.start_link(self(), path, headers) end - test "refuses invalid requests" do + test "allows multi-streams" do capture_log(fn -> - assert {:error, {404, _}} = start_socket() + assert {:ok, _} = start_socket() assert {:error, {404, _}} = start_socket("?stream=ncjdk") Process.sleep(30) end) diff --git a/test/pleroma/notification_test.exs b/test/pleroma/notification_test.exs index b47edd0a3..4354dd2b6 100644 --- a/test/pleroma/notification_test.exs +++ b/test/pleroma/notification_test.exs @@ -224,7 +224,7 @@ test "it creates a notification for user and send to the 'user' and the 'user:no task = Task.async(fn -> {:ok, _topic} = Streamer.get_topic_and_add_socket("user", user, oauth_token) - assert_receive {:render_with_user, _, _, _}, 4_000 + assert_receive {:render_with_user, _, _, _, "user"}, 4_000 end) task_user_notification = @@ -232,7 +232,7 @@ test "it creates a notification for user and send to the 'user' and the 'user:no {:ok, _topic} = Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) - assert_receive {:render_with_user, _, _, _}, 4_000 + assert_receive {:render_with_user, _, _, _, "user:notification"}, 4_000 end) activity = insert(:note_activity) diff --git a/test/pleroma/web/masto_fe_controller_test.exs b/test/pleroma/web/masto_fe_controller_test.exs new file mode 100644 index 000000000..924b45352 --- /dev/null +++ b/test/pleroma/web/masto_fe_controller_test.exs @@ -0,0 +1,38 @@ +defmodule Pleroma.Web.MastoFEControllerTest do + use Pleroma.Web.ConnCase, async: true + alias Pleroma.Web.MastodonAPI.AuthController + + describe "index/2 (main page)" do + test "GET /web/ (glitch-soc)" do + clear_config([:frontends, :mastodon], %{"name" => "mastodon-fe"}) + + {:ok, masto_app} = AuthController.local_mastofe_app() + user = Pleroma.Factory.insert(:user) + token = Pleroma.Factory.insert(:oauth_token, app: masto_app, user: user) + %{conn: conn} = oauth_access(["read", "write"], oauth_token: token, user: user) + + resp = + conn + |> get("/web/getting-started") + |> html_response(200) + + assert resp =~ "glitch" + end + + test "GET /web/ (fedibird)" do + clear_config([:frontends, :mastodon], %{"name" => "fedibird-fe"}) + + {:ok, masto_app} = AuthController.local_mastofe_app() + user = Pleroma.Factory.insert(:user) + token = Pleroma.Factory.insert(:oauth_token, app: masto_app, user: user) + %{conn: conn} = oauth_access(["read", "write"], oauth_token: token, user: user) + + resp = + conn + |> get("/web/getting-started") + |> html_response(200) + + refute resp =~ "glitch" + end + end +end diff --git a/test/pleroma/web/mastodon_api/views/status_view_test.exs b/test/pleroma/web/mastodon_api/views/status_view_test.exs index fb3255927..a6f8f3fc8 100644 --- a/test/pleroma/web/mastodon_api/views/status_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/status_view_test.exs @@ -44,14 +44,15 @@ test "has an emoji reaction list" do assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec()) assert status[:pleroma][:emoji_reactions] == [ - %{name: "☕", count: 2, me: false, url: nil}, + %{name: "☕", count: 2, me: false, url: nil, account_ids: [other_user.id, user.id]}, %{ count: 2, me: false, name: "dinosaur", - url: "http://localhost:4001/emoji/dino walking.gif" + url: "http://localhost:4001/emoji/dino walking.gif", + account_ids: [other_user.id, user.id] }, - %{name: "🍵", count: 1, me: false, url: nil} + %{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]} ] status = StatusView.render("show.json", activity: activity, for: user) @@ -59,14 +60,15 @@ test "has an emoji reaction list" do assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec()) assert status[:pleroma][:emoji_reactions] == [ - %{name: "☕", count: 2, me: true, url: nil}, + %{name: "☕", count: 2, me: true, url: nil, account_ids: [other_user.id, user.id]}, %{ count: 2, me: true, name: "dinosaur", - url: "http://localhost:4001/emoji/dino walking.gif" + url: "http://localhost:4001/emoji/dino walking.gif", + account_ids: [other_user.id, user.id] }, - %{name: "🍵", count: 1, me: false, url: nil} + %{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]} ] end @@ -82,7 +84,7 @@ test "works correctly with badly formatted emojis" do status = StatusView.render("show.json", activity: activity, for: user) assert status[:pleroma][:emoji_reactions] == [ - %{name: "☕", count: 1, me: true, url: nil} + %{name: "☕", count: 1, me: true, url: nil, account_ids: [user.id]} ] end @@ -102,7 +104,7 @@ test "doesn't show reactions from muted and blocked users" do status = StatusView.render("show.json", activity: activity) assert status[:pleroma][:emoji_reactions] == [ - %{name: "☕", count: 1, me: false, url: nil} + %{name: "☕", count: 1, me: false, url: nil, account_ids: [other_user.id]} ] status = StatusView.render("show.json", activity: activity, for: user) @@ -114,19 +116,25 @@ test "doesn't show reactions from muted and blocked users" do status = StatusView.render("show.json", activity: activity) assert status[:pleroma][:emoji_reactions] == [ - %{name: "☕", count: 2, me: false, url: nil} + %{ + name: "☕", + count: 2, + me: false, + url: nil, + account_ids: [third_user.id, other_user.id] + } ] status = StatusView.render("show.json", activity: activity, for: user) assert status[:pleroma][:emoji_reactions] == [ - %{name: "☕", count: 1, me: false, url: nil} + %{name: "☕", count: 1, me: false, url: nil, account_ids: [third_user.id]} ] status = StatusView.render("show.json", activity: activity, for: other_user) assert status[:pleroma][:emoji_reactions] == [ - %{name: "☕", count: 1, me: true, url: nil} + %{name: "☕", count: 1, me: true, url: nil, account_ids: [other_user.id]} ] end @@ -272,6 +280,7 @@ test "a note activity" do spoiler_text: HTML.filter_tags(object_data["summary"]), visibility: "public", media_attachments: [], + emoji_reactions: [], mentions: [], tags: [ %{ diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs index 65bb22e27..4898179e6 100644 --- a/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs @@ -31,7 +31,13 @@ test "PUT /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do assert to_string(activity.id) == id assert result["pleroma"]["emoji_reactions"] == [ - %{"name" => "☕", "count" => 1, "me" => true, "url" => nil} + %{ + "name" => "☕", + "count" => 1, + "me" => true, + "url" => nil, + "account_ids" => [other_user.id] + } ] {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) @@ -54,7 +60,8 @@ test "PUT /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do "name" => "dinosaur", "count" => 1, "me" => true, - "url" => "http://localhost:4001/emoji/dino walking.gif" + "url" => "http://localhost:4001/emoji/dino walking.gif", + "account_ids" => [other_user.id] } ] diff --git a/test/pleroma/web/streamer_test.exs b/test/pleroma/web/streamer_test.exs index 841db0e91..07129ff11 100644 --- a/test/pleroma/web/streamer_test.exs +++ b/test/pleroma/web/streamer_test.exs @@ -157,7 +157,8 @@ test "it streams the user's post in the 'user' stream", %{user: user, token: oau Streamer.get_topic_and_add_socket("user", user, oauth_token) {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) - assert_receive {:render_with_user, _, _, ^activity} + stream_name = "user:#{user.id}" + assert_receive {:render_with_user, _, _, ^activity, ^stream_name} refute Streamer.filtered_by_user?(user, activity) end @@ -168,7 +169,11 @@ test "it streams boosts of the user in the 'user' stream", %{user: user, token: {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"}) {:ok, announce} = CommonAPI.repeat(activity.id, user) - assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce} + stream_name = "user:#{user.id}" + + assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce, + ^stream_name} + refute Streamer.filtered_by_user?(user, announce) end @@ -221,7 +226,11 @@ test "it streams boosts of mastodon user in the 'user' stream", %{ {:ok, %Pleroma.Activity{data: _data, local: false} = announce} = Pleroma.Web.ActivityPub.Transmogrifier.handle_incoming(data) - assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce} + stream_name = "user:#{user.id}" + + assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce, + ^stream_name} + refute Streamer.filtered_by_user?(user, announce) end @@ -233,7 +242,7 @@ test "it sends notify to in the 'user' stream", %{ Streamer.get_topic_and_add_socket("user", user, oauth_token) Streamer.stream("user", notify) - assert_receive {:render_with_user, _, _, ^notify} + assert_receive {:render_with_user, _, _, ^notify, "user"} refute Streamer.filtered_by_user?(user, notify) end @@ -245,7 +254,7 @@ test "it sends notify to in the 'user:notification' stream", %{ Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) Streamer.stream("user:notification", notify) - assert_receive {:render_with_user, _, _, ^notify} + assert_receive {:render_with_user, _, _, ^notify, "user:notification"} refute Streamer.filtered_by_user?(user, notify) end @@ -291,7 +300,7 @@ test "it sends favorite to 'user:notification' stream'", %{ Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) {:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id) - assert_receive {:render_with_user, _, "notification.json", notif} + assert_receive {:render_with_user, _, "notification.json", notif, "user:notification"} assert notif.activity.id == favorite_activity.id refute Streamer.filtered_by_user?(user, notif) end @@ -320,7 +329,7 @@ test "it sends follow activities to the 'user:notification' stream", %{ Streamer.get_topic_and_add_socket("user:notification", user, oauth_token) {:ok, _follower, _followed, follow_activity} = CommonAPI.follow(user2, user) - assert_receive {:render_with_user, _, "notification.json", notif} + assert_receive {:render_with_user, _, "notification.json", notif, "user:notification"} assert notif.activity.id == follow_activity.id refute Streamer.filtered_by_user?(user, notif) end @@ -384,7 +393,7 @@ test "it sends to public (authenticated)" do Streamer.get_topic_and_add_socket("public", user, oauth_token) {:ok, activity} = CommonAPI.post(other_user, %{status: "Test"}) - assert_receive {:render_with_user, _, _, ^activity} + assert_receive {:render_with_user, _, _, ^activity, "public"} refute Streamer.filtered_by_user?(other_user, activity) end @@ -436,7 +445,7 @@ test "it filters to user if recipients invalid and thread containment is enabled Streamer.get_topic_and_add_socket("public", user, oauth_token) Streamer.stream("public", activity) - assert_receive {:render_with_user, _, _, ^activity} + assert_receive {:render_with_user, _, _, ^activity, "public"} assert Streamer.filtered_by_user?(user, activity) end @@ -458,7 +467,7 @@ test "it sends message if recipients invalid and thread containment is disabled" Streamer.get_topic_and_add_socket("public", user, oauth_token) Streamer.stream("public", activity) - assert_receive {:render_with_user, _, _, ^activity} + assert_receive {:render_with_user, _, _, ^activity, "public"} refute Streamer.filtered_by_user?(user, activity) end @@ -481,7 +490,7 @@ test "it sends message if recipients invalid and thread containment is enabled b Streamer.get_topic_and_add_socket("public", user, oauth_token) Streamer.stream("public", activity) - assert_receive {:render_with_user, _, _, ^activity} + assert_receive {:render_with_user, _, _, ^activity, "public"} refute Streamer.filtered_by_user?(user, activity) end end @@ -495,7 +504,7 @@ test "it filters messages involving blocked users", %{user: user, token: oauth_t Streamer.get_topic_and_add_socket("public", user, oauth_token) {:ok, activity} = CommonAPI.post(blocked_user, %{status: "Test"}) - assert_receive {:render_with_user, _, _, ^activity} + assert_receive {:render_with_user, _, _, ^activity, "public"} assert Streamer.filtered_by_user?(user, activity) end @@ -512,17 +521,17 @@ test "it filters messages transitively involving blocked users", %{ {:ok, activity_one} = CommonAPI.post(friend, %{status: "hey! @#{blockee.nickname}"}) - assert_receive {:render_with_user, _, _, ^activity_one} + assert_receive {:render_with_user, _, _, ^activity_one, "public"} assert Streamer.filtered_by_user?(blocker, activity_one) {:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"}) - assert_receive {:render_with_user, _, _, ^activity_two} + assert_receive {:render_with_user, _, _, ^activity_two, "public"} assert Streamer.filtered_by_user?(blocker, activity_two) {:ok, activity_three} = CommonAPI.post(blockee, %{status: "hey! @#{blocker.nickname}"}) - assert_receive {:render_with_user, _, _, ^activity_three} + assert_receive {:render_with_user, _, _, ^activity_three, "public"} assert Streamer.filtered_by_user?(blocker, activity_three) end end @@ -583,7 +592,8 @@ test "it sends wanted private posts to list", %{user: user_a, token: user_a_toke visibility: "private" }) - assert_receive {:render_with_user, _, _, ^activity} + stream_name = "list:#{list.id}" + assert_receive {:render_with_user, _, _, ^activity, ^stream_name} refute Streamer.filtered_by_user?(user_a, activity) end end @@ -601,7 +611,8 @@ test "it filters muted reblogs", %{user: user1, token: user1_token} do Streamer.get_topic_and_add_socket("user", user1, user1_token) {:ok, announce_activity} = CommonAPI.repeat(create_activity.id, user2) - assert_receive {:render_with_user, _, _, ^announce_activity} + stream_name = "user:#{user1.id}" + assert_receive {:render_with_user, _, _, ^announce_activity, ^stream_name} assert Streamer.filtered_by_user?(user1, announce_activity) end @@ -617,7 +628,7 @@ test "it filters reblog notification for reblog-muted actors", %{ Streamer.get_topic_and_add_socket("user", user1, user1_token) {:ok, _announce_activity} = CommonAPI.repeat(create_activity.id, user2) - assert_receive {:render_with_user, _, "notification.json", notif} + assert_receive {:render_with_user, _, "notification.json", notif, "user"} assert Streamer.filtered_by_user?(user1, notif) end @@ -633,7 +644,7 @@ test "it send non-reblog notification for reblog-muted actors", %{ Streamer.get_topic_and_add_socket("user", user1, user1_token) {:ok, _favorite_activity} = CommonAPI.favorite(user2, create_activity.id) - assert_receive {:render_with_user, _, "notification.json", notif} + assert_receive {:render_with_user, _, "notification.json", notif, "user"} refute Streamer.filtered_by_user?(user1, notif) end end @@ -648,7 +659,8 @@ test "it filters posts from muted threads" do {:ok, activity} = CommonAPI.post(user, %{status: "super hot take"}) {:ok, _} = CommonAPI.add_mute(user2, activity) - assert_receive {:render_with_user, _, _, ^activity} + stream_name = "user:#{user2.id}" + assert_receive {:render_with_user, _, _, ^activity, ^stream_name} assert Streamer.filtered_by_user?(user2, activity) end end @@ -690,7 +702,8 @@ test "it doesn't send conversation update to the 'direct' stream when the last m }) create_activity_id = create_activity.id - assert_receive {:render_with_user, _, _, ^create_activity} + stream_name = "direct:#{user.id}" + assert_receive {:render_with_user, _, _, ^create_activity, ^stream_name} assert_receive {:text, received_conversation1} assert %{"event" => "conversation", "payload" => _} = Jason.decode!(received_conversation1) @@ -725,8 +738,9 @@ test "it sends conversation update to the 'direct' stream when a message is dele visibility: "direct" }) - assert_receive {:render_with_user, _, _, ^create_activity} - assert_receive {:render_with_user, _, _, ^create_activity2} + stream_name = "direct:#{user.id}" + assert_receive {:render_with_user, _, _, ^create_activity, ^stream_name} + assert_receive {:render_with_user, _, _, ^create_activity2, ^stream_name} assert_receive {:text, received_conversation1} assert %{"event" => "conversation", "payload" => _} = Jason.decode!(received_conversation1) assert_receive {:text, received_conversation1}