## [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
"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",
admin: %{
"name" => "admin-fe",
"ref" => "stable"
+ },
+ mastodon: %{
+ "name" => "mastodon-fe",
+ "ref" => "akkoma"
}
```
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
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()
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),
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
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)}")
# 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
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)
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)
{: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
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")
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
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, _} ->
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
--- /dev/null
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<meta charset='utf-8'>
+<meta content='width=device-width, initial-scale=1' name='viewport'>
+<title>
+<%= Config.get([:instance, :name]) %>
+</title>
+<link rel="icon" type="image/png" href="/favicon.png"/>
+<link rel="manifest" type="applicaton/manifest+json" href="<%= Routes.masto_fe_path(Pleroma.Web.Endpoint, :manifest) %>" />
+
+<meta name="theme-color" content="<%= Config.get([:manifest, :theme_color]) %>" />
+
+<script id='initial-state' type='application/json'><%= initial_state(@token, @user, @custom_emojis) %></script>
+
+<script crossorigin='anonymous' src="/packs/js/common.js"></script>
+<script crossorigin='anonymous' src="/packs/js/locale_en.js"></script>
+
+<link rel='preload' as='script' crossorigin='anonymous' href='/packs/js/features/getting_started.js'>
+<link rel='preload' as='script' crossorigin='anonymous' href='/packs/js/features/compose.js'>
+<link rel='preload' as='script' crossorigin='anonymous' href='/packs/js/features/home_timeline.js'>
+<link rel='preload' as='script' crossorigin='anonymous' href='/packs/js/features/notifications.js'>
+<script crossorigin='anonymous' src="/packs/js/application.js"></script>
+
+
+<link rel="stylesheet" media="all" href="/packs/css/common.css" />
+<link rel="stylesheet" media="all" href="/packs/css/default.css" />
+
+</head>
+<body class='app-body no-reduce-motion system-font'>
+ <div class='app-holder' data-props='{"locale":"en"}' id='mastodon'>
+ </div>
+</body>
+</html>
%{
meta: %{
+ title: Config.get([:instance, :name]),
streaming_api_base_url: Pleroma.Web.Endpoint.websocket_url(),
access_token: token,
locale: "en",
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: %{
"video\/mp4"
]
},
+ lists: [],
settings: user.mastofe_settings || %{},
push_subscription: nil,
accounts: %{user.id => render(AccountView, "show.json", user: user, for: user)},
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(
|> 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(
|> 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(
|> 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:
%{
|> 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", %{
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)
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 =
{: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)
--- /dev/null
+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
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)
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
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
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)
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
spoiler_text: HTML.filter_tags(object_data["summary"]),
visibility: "public",
media_attachments: [],
+ emoji_reactions: [],
mentions: [],
tags: [
%{
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"})
"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]
}
]
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
{: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
{: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
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
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
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
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
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
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
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
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
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
{: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
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
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
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
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
{: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
})
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)
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}