Browse Source

Merge branch 'muting' into 'develop'

Implement muting, add it to the whole mastodon API

See merge request pleroma/pleroma!319
tags/v1.1.4
lambda 5 years ago
parent
commit
11b3c10c54
9 changed files with 205 additions and 22 deletions
  1. +29
    -0
      lib/pleroma/user.ex
  2. +17
    -0
      lib/pleroma/user/info.ex
  3. +13
    -0
      lib/pleroma/web/activity_pub/activity_pub.ex
  4. +39
    -0
      lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
  5. +1
    -1
      lib/pleroma/web/mastodon_api/views/account_view.ex
  6. +3
    -3
      lib/pleroma/web/router.ex
  7. +23
    -0
      test/user_test.exs
  8. +42
    -0
      test/web/activity_pub/activity_pub_test.exs
  9. +38
    -18
      test/web/mastodon_api/mastodon_api_controller_test.exs

+ 29
- 0
lib/pleroma/user.ex View File

@@ -888,6 +888,30 @@ defmodule Pleroma.User do
)
end

def mute(muter, %User{ap_id: ap_id}) do
info_cng =
muter.info
|> User.Info.add_to_mutes(ap_id)

cng =
change(muter)
|> put_embed(:info, info_cng)

update_and_set_cache(cng)
end

def unmute(muter, %{ap_id: ap_id}) do
info_cng =
muter.info
|> User.Info.remove_from_mutes(ap_id)

cng =
change(muter)
|> put_embed(:info, info_cng)

update_and_set_cache(cng)
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 +954,8 @@ defmodule Pleroma.User 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
@@ -941,6 +967,9 @@ defmodule Pleroma.User do
end)
end

def muted_users(user),
do: Repo.all(from(u in User, where: u.ap_id in ^user.info.mutes))

def blocked_users(user),
do: Repo.all(from(u in User, where: u.ap_id in ^user.info.blocks))



+ 17
- 0
lib/pleroma/user/info.ex View File

@@ -19,6 +19,7 @@ defmodule Pleroma.User.Info do
field(:default_scope, :string, default: "public")
field(:blocks, {:array, :string}, default: [])
field(:domain_blocks, {:array, :string}, default: [])
field(:mutes, {:array, :string}, default: [])
field(:deactivated, :boolean, default: false)
field(:no_rich_text, :boolean, default: false)
field(:ap_enabled, :boolean, default: false)
@@ -74,6 +75,14 @@ defmodule Pleroma.User.Info do
|> validate_required([:follower_count])
end

def set_mutes(info, mutes) do
params = %{mutes: mutes}

info
|> cast(params, [:mutes])
|> validate_required([:mutes])
end

def set_blocks(info, blocks) do
params = %{blocks: blocks}

@@ -82,6 +91,14 @@ defmodule Pleroma.User.Info do
|> validate_required([:blocks])
end

def add_to_mutes(info, muted) do
set_mutes(info, Enum.uniq([muted | info.mutes]))
end

def remove_from_mutes(info, muted) do
set_mutes(info, List.delete(info.mutes, muted))
end

def add_to_block(info, blocked) do
set_blocks(info, Enum.uniq([blocked | info.blocks]))
end


+ 13
- 0
lib/pleroma/web/activity_pub/activity_pub.ex View File

@@ -576,6 +576,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do

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 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|> restrict_type(opts)
|> restrict_favorited_by(opts)
|> restrict_blocked(opts)
|> restrict_muted(opts)
|> restrict_media(opts)
|> restrict_visibility(opts)
|> restrict_replies(opts)


+ 39
- 0
lib/pleroma/web/mastodon_api/mastodon_api_controller.ex View File

@@ -232,6 +232,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController 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 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController 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 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController 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,41 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController 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
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: muter, target: muted})
else
{:error, message} ->
conn
|> put_resp_content_type("application/json")
|> send_resp(403, Jason.encode!(%{"error" => message}))
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
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: muter, target: muted})
else
{:error, message} ->
conn
|> put_resp_content_type("application/json")
|> send_resp(403, Jason.encode!(%{"error" => message}))
end
end

def mutes(%{assigns: %{user: user}} = conn, _) do
with muted_accounts <- User.muted_users(user) do
res = AccountView.render("accounts.json", users: muted_accounts, for: user, as: :user)
json(conn, res)
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 +1056,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
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).


+ 1
- 1
lib/pleroma/web/mastodon_api/views/account_view.ex View File

@@ -47,7 +47,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
following: User.following?(user, target),
followed_by: User.following?(target, user),
blocking: User.blocks?(user, target),
muting: false,
muting: User.mutes?(user, target),
muting_notifications: false,
requested: requested,
domain_blocking: false,


+ 3
- 3
lib/pleroma/web/router.ex View File

@@ -168,8 +168,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)
@@ -180,7 +180,7 @@ defmodule Pleroma.Web.Router do

get("/blocks", MastodonAPIController, :blocks)

get("/mutes", MastodonAPIController, :empty_array)
get("/mutes", MastodonAPIController, :mutes)

get("/timelines/home", MastodonAPIController, :home_timeline)



+ 23
- 0
test/user_test.exs View File

@@ -594,6 +594,29 @@ defmodule Pleroma.UserTest do
end
end

describe "mutes" do
test "it mutes people" do
user = insert(:user)
muted_user = insert(:user)

refute User.mutes?(user, muted_user)

{:ok, user} = User.mute(user, muted_user)

assert User.mutes?(user, muted_user)
end

test "it unmutes users" do
user = insert(:user)
muted_user = insert(:user)

{:ok, user} = User.mute(user, muted_user)
{:ok, user} = User.unmute(user, muted_user)

refute User.mutes?(user, muted_user)
end
end

describe "blocks" do
test "it blocks people" do
user = insert(:user)


+ 42
- 0
test/web/activity_pub/activity_pub_test.exs View File

@@ -277,6 +277,48 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert Enum.member?(activities, activity_one)
end

test "doesn't return muted activities" do
activity_one = insert(:note_activity)
activity_two = insert(:note_activity)
activity_three = insert(:note_activity)
user = insert(:user)
booster = insert(:user)
{:ok, user} = User.mute(user, %User{ap_id: activity_one.data["actor"]})

activities = ActivityPub.fetch_activities([], %{"muting_user" => user})

assert Enum.member?(activities, activity_two)
assert Enum.member?(activities, activity_three)
refute Enum.member?(activities, activity_one)

{:ok, user} = User.unmute(user, %User{ap_id: activity_one.data["actor"]})

activities = ActivityPub.fetch_activities([], %{"muting_user" => user})

assert Enum.member?(activities, activity_two)
assert Enum.member?(activities, activity_three)
assert Enum.member?(activities, activity_one)

{:ok, user} = User.mute(user, %User{ap_id: activity_three.data["actor"]})
{:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
%Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
activity_three = Repo.get(Activity, activity_three.id)

activities = ActivityPub.fetch_activities([], %{"muting_user" => user})

assert Enum.member?(activities, activity_two)
refute Enum.member?(activities, activity_three)
refute Enum.member?(activities, boost_activity)
assert Enum.member?(activities, activity_one)

activities = ActivityPub.fetch_activities([], %{"muting_user" => nil})

assert Enum.member?(activities, activity_two)
assert Enum.member?(activities, activity_three)
assert Enum.member?(activities, boost_activity)
assert Enum.member?(activities, activity_one)
end

test "excludes reblogs on request" do
user = insert(:user)
{:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user})


+ 38
- 18
test/web/mastodon_api/mastodon_api_controller_test.exs View File

@@ -1206,6 +1206,42 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert id == to_string(other_user.id)
end

test "muting / unmuting a user", %{conn: conn} do
user = insert(:user)
other_user = insert(:user)

conn =
conn
|> assign(:user, user)
|> post("/api/v1/accounts/#{other_user.id}/mute")

assert %{"id" => _id, "muting" => true} = json_response(conn, 200)

user = Repo.get(User, user.id)

conn =
build_conn()
|> assign(:user, user)
|> post("/api/v1/accounts/#{other_user.id}/unmute")

assert %{"id" => _id, "muting" => false} = json_response(conn, 200)
end

test "getting a list of mutes", %{conn: conn} do
user = insert(:user)
other_user = insert(:user)

{:ok, user} = User.mute(user, other_user)

conn =
conn
|> assign(:user, user)
|> get("/api/v1/mutes")

other_user_id = to_string(other_user.id)
assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
end

test "blocking / unblocking a user", %{conn: conn} do
user = insert(:user)
other_user = insert(:user)
@@ -1282,26 +1318,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert "even.worse.site" in domain_blocks
end

test "unimplemented mute endpoints" do
user = insert(:user)
other_user = insert(:user)

["mute", "unmute"]
|> Enum.each(fn endpoint ->
conn =
build_conn()
|> assign(:user, user)
|> post("/api/v1/accounts/#{other_user.id}/#{endpoint}")

assert %{"id" => id} = json_response(conn, 200)
assert id == to_string(other_user.id)
end)
end

test "unimplemented mutes, follow_requests, blocks, domain blocks" do
test "unimplemented follow_requests, blocks, domain blocks" do
user = insert(:user)

["blocks", "domain_blocks", "mutes", "follow_requests"]
["blocks", "domain_blocks", "follow_requests"]
|> Enum.each(fn endpoint ->
conn =
build_conn()


Loading…
Cancel
Save