)
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 =
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
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 || []
|> restrict_type(opts)
|> restrict_favorited_by(opts)
|> restrict_blocked(opts)
+ |> restrict_muted(opts)
|> restrict_media(opts)
|> restrict_visibility(opts)
|> restrict_replies(opts)
params
|> Map.put("type", ["Create", "Announce"])
|> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
|> Map.put("user", user)
activities =
|> 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()
|> 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)
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),
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).
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,
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)