From f41f017bbca232c2ab3cd41ad23ef95d5ad13e36 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Wed, 5 Sep 2018 23:49:15 +0300 Subject: [PATCH] Implement muting, add it to the mastodon API --- lib/pleroma/user.ex | 24 +++++++++++++++++++ lib/pleroma/web/activity_pub/activity_pub.ex | 13 ++++++++++ .../mastodon_api/mastodon_api_controller.ex | 18 ++++++++++++++ .../web/mastodon_api/views/account_view.ex | 1 + lib/pleroma/web/router.ex | 4 ++-- 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 18bb56667..9a774e7b7 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -888,6 +888,28 @@ def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_i ) end + def mute(muter, %User{ap_id: ap_id} = muted) do + if following?(muter, muter) do + unfollow(muter, muter) + end + + mutes = muter.info["mutes"] || [] + new_mutes = Enum.uniq([ap_id | mutes]) + new_info = Map.put(muter.info, "mutes", new_mutes) + + cs = User.info_changeset(muter, %{info: new_info}) + update_and_set_cache(cs) + end + + def unmute(user, %{ap_id: ap_id}) do + mutes = user.info["mutes"] || [] + new_mutes = List.delete(mutes, ap_id) + new_info = Map.put(user.info, "mutes", new_mutes) + + cs = User.info_changeset(user, %{info: new_info}) + update_and_set_cache(cs) + end + def block(blocker, %User{ap_id: ap_id} = blocked) do # sever any follow relationships to prevent leaks per activitypub (Pleroma issue #213) blocker = @@ -930,6 +952,8 @@ def unblock(blocker, %{ap_id: ap_id}) do update_and_set_cache(cng) end + def mutes?(user, %{ap_id: ap_id}), do: Enum.member?(user.info["mutes"] || [], ap_id) + def blocks?(user, %{ap_id: ap_id}) do blocks = user.info.blocks domain_blocks = user.info.domain_blocks diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 8d3116839..36e5e23bf 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -576,6 +576,18 @@ defp restrict_reblogs(query, %{"exclude_reblogs" => val}) when val == "true" or defp restrict_reblogs(query, _), do: query + defp restrict_muted(query, %{"muting_user" => %User{info: info}}) do + mutes = info["mutes"] || [] + + from( + activity in query, + where: fragment("not (? = ANY(?))", activity.actor, ^mutes), + where: fragment("not (?->'to' \\?| ?)", activity.data, ^mutes) + ) + end + + defp restrict_muted(query, _), do: query + defp restrict_blocked(query, %{"blocking_user" => %User{info: info}}) do blocks = info.blocks || [] domain_blocks = info.domain_blocks || [] @@ -629,6 +641,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do |> restrict_type(opts) |> restrict_favorited_by(opts) |> restrict_blocked(opts) + |> restrict_muted(opts) |> restrict_media(opts) |> restrict_visibility(opts) |> restrict_replies(opts) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index e2715bd08..af16264ee 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -232,6 +232,7 @@ def home_timeline(%{assigns: %{user: user}} = conn, params) do params |> Map.put("type", ["Create", "Announce"]) |> Map.put("blocking_user", user) + |> Map.put("muting_user", user) |> Map.put("user", user) activities = @@ -254,6 +255,7 @@ def public_timeline(%{assigns: %{user: user}} = conn, params) do |> Map.put("type", ["Create", "Announce"]) |> Map.put("local_only", local_only) |> Map.put("blocking_user", user) + |> Map.put("muting_user", user) |> ActivityPub.fetch_public_activities() |> Enum.reverse() @@ -620,6 +622,7 @@ def hashtag_timeline(%{assigns: %{user: user}} = conn, params) do |> Map.put("type", "Create") |> Map.put("local_only", local_only) |> Map.put("blocking_user", user) + |> Map.put("muting_user", user) |> Map.put("tag", tags) |> Map.put("tag_all", tag_all) |> Map.put("tag_reject", tag_reject) @@ -763,6 +766,20 @@ def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do end end + def mute(%{assigns: %{user: muter}} = conn, %{"id" => id}) do + with %User{} = muted <- Repo.get(User, id), + {:ok, muter} <- User.mute(muter, muted) do + render(conn, AccountView, "relationship.json", %{user: muter, target: muted}) + end + end + + def unmute(%{assigns: %{user: muter}} = conn, %{"id" => id}) do + with %User{} = muted <- Repo.get(User, id), + {:ok, muter} <- User.unmute(muter, muted) do + render(conn, AccountView, "relationship.json", %{user: muter, target: muted}) + end + end + def block(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do with %User{} = blocked <- Repo.get(User, id), {:ok, blocker} <- User.block(blocker, blocked), @@ -1018,6 +1035,7 @@ def list_timeline(%{assigns: %{user: user}} = conn, %{"list_id" => id} = params) params |> Map.put("type", "Create") |> Map.put("blocking_user", user) + |> Map.put("muting_user", user) # we must filter the following list for the user to avoid leaking statuses the user # does not actually have permission to see (for more info, peruse security issue #270). diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 9df9f14b2..91b3e034f 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -47,6 +47,7 @@ def render("relationship.json", %{user: user, target: target}) do following: User.following?(user, target), followed_by: User.following?(target, user), blocking: User.blocks?(user, target), + muting: User.mutes?(user, target), muting: false, muting_notifications: false, requested: requested, diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 9a6cf2232..fb7a8d448 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -166,8 +166,8 @@ defmodule Pleroma.Web.Router do post("/accounts/:id/unfollow", MastodonAPIController, :unfollow) post("/accounts/:id/block", MastodonAPIController, :block) post("/accounts/:id/unblock", MastodonAPIController, :unblock) - post("/accounts/:id/mute", MastodonAPIController, :relationship_noop) - post("/accounts/:id/unmute", MastodonAPIController, :relationship_noop) + post("/accounts/:id/mute", MastodonAPIController, :mute) + post("/accounts/:id/unmute", MastodonAPIController, :unmute) get("/accounts/:id/lists", MastodonAPIController, :account_lists) get("/follow_requests", MastodonAPIController, :follow_requests)