From f4ff4ffba2761925dde59ff1989dfdb232732dd7 Mon Sep 17 00:00:00 2001 From: Karen Konou Date: Tue, 5 Feb 2019 13:35:24 +0100 Subject: [PATCH 01/15] Migration and some boilerplate stuff --- .../mastodon_api/mastodon_api_controller.ex | 16 ++++++++++++ lib/pleroma/web/router.ex | 2 ++ lib/pleroma/web/thread_mute.ex | 26 +++++++++++++++++++ .../20190205114625_create_thread_mutes.exs | 12 +++++++++ 4 files changed, 56 insertions(+) create mode 100644 lib/pleroma/web/thread_mute.ex create mode 100644 priv/repo/migrations/20190205114625_create_thread_mutes.exs diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 7f3fbff4a..00b39d76b 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -445,6 +445,22 @@ def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do end end + def mute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with {:ok, activity} <- Pleroma.Web.ThreadMute.add_mute(user, id) do + conn + |> put_view(StatusView) + |> try_render("status.json", %{activity: activity, for: user, as: :activity}) + end + end + + def unmute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with {:ok, activity} <- Pleroma.Web.ThreadMute.remove_mute(user, id) do + conn + |> put_view(StatusView) + |> try_render("status.json", %{activity: activity, for: user, as: :activity}) + end + end + def notifications(%{assigns: %{user: user}} = conn, params) do notifications = Notification.for_user(user, params) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index c6b4d37ab..3f9759ca9 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -198,6 +198,8 @@ defmodule Pleroma.Web.Router do post("/statuses/:id/unpin", MastodonAPIController, :unpin_status) post("/statuses/:id/bookmark", MastodonAPIController, :bookmark_status) post("/statuses/:id/unbookmark", MastodonAPIController, :unbookmark_status) + post("/statuses/:id/mute", MastodonAPIController, :mute_conversation) + post("/statuses/:id/unmute", MastodonAPIController, :unmute_conversation) post("/notifications/clear", MastodonAPIController, :clear_notifications) post("/notifications/dismiss", MastodonAPIController, :dismiss_notification) diff --git a/lib/pleroma/web/thread_mute.ex b/lib/pleroma/web/thread_mute.ex new file mode 100644 index 000000000..8892155cd --- /dev/null +++ b/lib/pleroma/web/thread_mute.ex @@ -0,0 +1,26 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ThreadMute do + use Ecto.Schema + + alias Pleroma.{Activity, Notification, User} + + schema "thread_mutes" do + field(:user_id, :string) + field(:context, :string) + end + + def add_mute(user, id) do + %{id: user_id} = user + %{data: %{"context" => context}} = Activity.get_by_id(id) + Pleroma.Repo.insert(%Pleroma.Web.ThreadMute{user_id: user_id, context: context}) + end + + def remove_mute(user, id) do + end + + def mute_thread() do + end +end diff --git a/priv/repo/migrations/20190205114625_create_thread_mutes.exs b/priv/repo/migrations/20190205114625_create_thread_mutes.exs new file mode 100644 index 000000000..b16f557f0 --- /dev/null +++ b/priv/repo/migrations/20190205114625_create_thread_mutes.exs @@ -0,0 +1,12 @@ +defmodule Pleroma.Repo.Migrations.CreateThreadMutes do + use Ecto.Migration + + def change do + create table(:thread_mutes) do + add :user_id, references(:users, type: :uuid, on_delete: :delete_all) + add :context, :string + end + + create index(:thread_mutes, [:user_id]) + end +end From 77448de4925f3793bde201a49d204f881163b1b8 Mon Sep 17 00:00:00 2001 From: Karen Konou Date: Thu, 7 Feb 2019 22:25:07 +0100 Subject: [PATCH 02/15] ugghhhh --- lib/pleroma/web/thread_mute.ex | 6 +++--- priv/repo/migrations/20190205114625_create_thread_mutes.exs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/web/thread_mute.ex b/lib/pleroma/web/thread_mute.ex index 8892155cd..50a6219d1 100644 --- a/lib/pleroma/web/thread_mute.ex +++ b/lib/pleroma/web/thread_mute.ex @@ -8,14 +8,14 @@ defmodule Pleroma.Web.ThreadMute do alias Pleroma.{Activity, Notification, User} schema "thread_mutes" do - field(:user_id, :string) + belongs_to(:user, User, type: Pleroma.FlakeId) field(:context, :string) end def add_mute(user, id) do - %{id: user_id} = user + user_id = user.id %{data: %{"context" => context}} = Activity.get_by_id(id) - Pleroma.Repo.insert(%Pleroma.Web.ThreadMute{user_id: user_id, context: context}) + Pleroma.Repo.insert(%Pleroma.Web.ThreadMute{user: user_id, context: context}) end def remove_mute(user, id) do diff --git a/priv/repo/migrations/20190205114625_create_thread_mutes.exs b/priv/repo/migrations/20190205114625_create_thread_mutes.exs index b16f557f0..16083332b 100644 --- a/priv/repo/migrations/20190205114625_create_thread_mutes.exs +++ b/priv/repo/migrations/20190205114625_create_thread_mutes.exs @@ -3,10 +3,10 @@ defmodule Pleroma.Repo.Migrations.CreateThreadMutes do def change do create table(:thread_mutes) do - add :user_id, references(:users, type: :uuid, on_delete: :delete_all) + add :user, references(:users, type: :uuid, on_delete: :delete_all) add :context, :string end - create index(:thread_mutes, [:user_id]) + create index(:thread_mutes, [:user]) end end From 6b5032e10eb64c466e320f870b3cdad611b100d5 Mon Sep 17 00:00:00 2001 From: Karen Konou Date: Thu, 7 Feb 2019 22:38:54 +0100 Subject: [PATCH 03/15] made a silly oopsie --- lib/pleroma/web/thread_mute.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/thread_mute.ex b/lib/pleroma/web/thread_mute.ex index 50a6219d1..f2283cf86 100644 --- a/lib/pleroma/web/thread_mute.ex +++ b/lib/pleroma/web/thread_mute.ex @@ -15,7 +15,7 @@ defmodule Pleroma.Web.ThreadMute do def add_mute(user, id) do user_id = user.id %{data: %{"context" => context}} = Activity.get_by_id(id) - Pleroma.Repo.insert(%Pleroma.Web.ThreadMute{user: user_id, context: context}) + Pleroma.Repo.insert(%Pleroma.Web.ThreadMute{}, %{user: user_id, context: context}) end def remove_mute(user, id) do From 7e3ec93ed0047063c54a9e2a31be803e7ec4780f Mon Sep 17 00:00:00 2001 From: Karen Konou Date: Thu, 7 Feb 2019 22:38:54 +0100 Subject: [PATCH 04/15] made a silly oopsie --- lib/pleroma/web/thread_mute.ex | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/thread_mute.ex b/lib/pleroma/web/thread_mute.ex index 50a6219d1..333b26246 100644 --- a/lib/pleroma/web/thread_mute.ex +++ b/lib/pleroma/web/thread_mute.ex @@ -5,7 +5,7 @@ defmodule Pleroma.Web.ThreadMute do use Ecto.Schema - alias Pleroma.{Activity, Notification, User} + alias Pleroma.{Activity, Notification, User, Repo} schema "thread_mutes" do belongs_to(:user, User, type: Pleroma.FlakeId) @@ -13,9 +13,8 @@ defmodule Pleroma.Web.ThreadMute do end def add_mute(user, id) do - user_id = user.id %{data: %{"context" => context}} = Activity.get_by_id(id) - Pleroma.Repo.insert(%Pleroma.Web.ThreadMute{user: user_id, context: context}) + Repo.insert(%Pleroma.Web.ThreadMute{}, %{user_id: user.id, context: context}) end def remove_mute(user, id) do From c43f414a79ff9b276b8162ac1ab10e84651e881d Mon Sep 17 00:00:00 2001 From: Karen Konou Date: Thu, 7 Feb 2019 23:44:30 +0100 Subject: [PATCH 05/15] Somehow fixed the repo insert [skip-ci] --- lib/pleroma/web/thread_mute.ex | 3 ++- priv/repo/migrations/20190205114625_create_thread_mutes.exs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/thread_mute.ex b/lib/pleroma/web/thread_mute.ex index 333b26246..b37dda58b 100644 --- a/lib/pleroma/web/thread_mute.ex +++ b/lib/pleroma/web/thread_mute.ex @@ -14,7 +14,8 @@ defmodule Pleroma.Web.ThreadMute do def add_mute(user, id) do %{data: %{"context" => context}} = Activity.get_by_id(id) - Repo.insert(%Pleroma.Web.ThreadMute{}, %{user_id: user.id, context: context}) + mute = %Pleroma.Web.ThreadMute{user_id: user.id, context: context} + Repo.insert(mute) end def remove_mute(user, id) do diff --git a/priv/repo/migrations/20190205114625_create_thread_mutes.exs b/priv/repo/migrations/20190205114625_create_thread_mutes.exs index 16083332b..b16f557f0 100644 --- a/priv/repo/migrations/20190205114625_create_thread_mutes.exs +++ b/priv/repo/migrations/20190205114625_create_thread_mutes.exs @@ -3,10 +3,10 @@ defmodule Pleroma.Repo.Migrations.CreateThreadMutes do def change do create table(:thread_mutes) do - add :user, references(:users, type: :uuid, on_delete: :delete_all) + add :user_id, references(:users, type: :uuid, on_delete: :delete_all) add :context, :string end - create index(:thread_mutes, [:user]) + create index(:thread_mutes, [:user_id]) end end From a44e532fb1be973d6974aa9e357096764252796d Mon Sep 17 00:00:00 2001 From: Karen Konou Date: Fri, 8 Feb 2019 13:17:11 +0100 Subject: [PATCH 06/15] Added thread unmuting (still a bit buggy maybe) --- lib/pleroma/web/thread_mute.ex | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/web/thread_mute.ex b/lib/pleroma/web/thread_mute.ex index b37dda58b..a0d564e82 100644 --- a/lib/pleroma/web/thread_mute.ex +++ b/lib/pleroma/web/thread_mute.ex @@ -4,8 +4,8 @@ defmodule Pleroma.Web.ThreadMute do use Ecto.Schema - - alias Pleroma.{Activity, Notification, User, Repo} + alias Pleroma.{Activity, Repo, User} + require Ecto.Query schema "thread_mutes" do belongs_to(:user, User, type: Pleroma.FlakeId) @@ -19,8 +19,9 @@ def add_mute(user, id) do end def remove_mute(user, id) do - end - - def mute_thread() do + user_id = Pleroma.FlakeId.from_string(user.id) + %{data: %{"context" => context}} = Activity.get_by_id(id) + Ecto.Query.from(m in "thread_mutes", where: m.user_id == ^user_id and m.context == ^context) + |> Repo.delete_all end end From 5c5b228f21a75c665ab7501ab02765183d00f410 Mon Sep 17 00:00:00 2001 From: Karen Konou Date: Fri, 8 Feb 2019 13:17:11 +0100 Subject: [PATCH 07/15] Added thread unmuting (still a bit buggy maybe) --- lib/pleroma/web/thread_mute.ex | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/web/thread_mute.ex b/lib/pleroma/web/thread_mute.ex index b37dda58b..a0d564e82 100644 --- a/lib/pleroma/web/thread_mute.ex +++ b/lib/pleroma/web/thread_mute.ex @@ -4,8 +4,8 @@ defmodule Pleroma.Web.ThreadMute do use Ecto.Schema - - alias Pleroma.{Activity, Notification, User, Repo} + alias Pleroma.{Activity, Repo, User} + require Ecto.Query schema "thread_mutes" do belongs_to(:user, User, type: Pleroma.FlakeId) @@ -19,8 +19,9 @@ def add_mute(user, id) do end def remove_mute(user, id) do - end - - def mute_thread() do + user_id = Pleroma.FlakeId.from_string(user.id) + %{data: %{"context" => context}} = Activity.get_by_id(id) + Ecto.Query.from(m in "thread_mutes", where: m.user_id == ^user_id and m.context == ^context) + |> Repo.delete_all end end From 09189c3a7c61d15dc8c73c2474df19320f5032d0 Mon Sep 17 00:00:00 2001 From: Karen Konou Date: Sat, 9 Feb 2019 14:23:51 +0100 Subject: [PATCH 08/15] Made a test! --- test/web/thread_mute_test.exs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 test/web/thread_mute_test.exs diff --git a/test/web/thread_mute_test.exs b/test/web/thread_mute_test.exs new file mode 100644 index 000000000..4dea44d2f --- /dev/null +++ b/test/web/thread_mute_test.exs @@ -0,0 +1,25 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ThreadMuteTest do + use Pleroma.DataCase + import Pleroma.Web.ThreadMute + + import Pleroma.Factory + + test "add a mute" do + user = insert(:user, %{id: "1"}) + + activity = + insert(:note_activity, %{ + data: %{"context" => "http://localhost:4000/contexts/361ca23e-ffa7-4773-b981-a355a18dc592"} + }) + + id = activity.id + {:ok, mute} = add_mute(user, id) + + assert mute.user_id == "1" + assert mute.context == "http://localhost:4000/contexts/361ca23e-ffa7-4773-b981-a355a18dc592" + end +end From 4430a0ad127411b818d875dbbaf14369c109f331 Mon Sep 17 00:00:00 2001 From: Karen Konou Date: Sat, 9 Feb 2019 14:34:42 +0100 Subject: [PATCH 09/15] added another test --- test/web/thread_mute_test.exs | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/test/web/thread_mute_test.exs b/test/web/thread_mute_test.exs index 4dea44d2f..75277ef62 100644 --- a/test/web/thread_mute_test.exs +++ b/test/web/thread_mute_test.exs @@ -8,18 +8,33 @@ defmodule Pleroma.Web.ThreadMuteTest do import Pleroma.Factory - test "add a mute" do - user = insert(:user, %{id: "1"}) + describe "mute tests" do + setup do + user = insert(:user, %{id: "1"}) - activity = - insert(:note_activity, %{ - data: %{"context" => "http://localhost:4000/contexts/361ca23e-ffa7-4773-b981-a355a18dc592"} - }) + activity = + insert(:note_activity, %{ + data: %{ + "context" => "http://localhost:4000/contexts/361ca23e-ffa7-4773-b981-a355a18dc592" + } + }) - id = activity.id - {:ok, mute} = add_mute(user, id) + [user: user, activity: activity] + end - assert mute.user_id == "1" - assert mute.context == "http://localhost:4000/contexts/361ca23e-ffa7-4773-b981-a355a18dc592" + test "add mute", %{user: user, activity: activity} do + id = activity.id + {:ok, mute} = add_mute(user, id) + + assert mute.user_id == "1" + assert mute.context == "http://localhost:4000/contexts/361ca23e-ffa7-4773-b981-a355a18dc592" + end + + test "remove mute", %{user: user, activity: activity} do + id = activity.id + + add_mute(user, id) + {1, nil} = remove_mute(user, id) + end end end From a0d732ec55fcbce8cf345344d1456dc77bb0f3bf Mon Sep 17 00:00:00 2001 From: Karen Konou Date: Sat, 9 Feb 2019 17:47:57 +0100 Subject: [PATCH 10/15] it works!! --- lib/pleroma/notification.ex | 2 ++ lib/pleroma/web/thread_mute.ex | 28 +++++++++++++++++++++++++--- test/web/thread_mute_test.exs | 25 +++++++++++++------------ 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 2364d36da..d05708e41 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Notification do use Ecto.Schema alias Pleroma.{User, Activity, Notification, Repo} alias Pleroma.Web.CommonAPI.Utils + alias Pleroma.Web.ThreadMute import Ecto.Query schema "notifications" do @@ -112,6 +113,7 @@ def create_notifications(_), do: {:ok, []} # TODO move to sql, too. def create_notification(%Activity{} = activity, %User{} = user) do unless User.blocks?(user, %{ap_id: activity.data["actor"]}) or + ThreadMute.muted?(user, activity) or user.ap_id == activity.data["actor"] or (activity.data["type"] == "Follow" and Enum.any?(Notification.for_user(user), fn notif -> diff --git a/lib/pleroma/web/thread_mute.ex b/lib/pleroma/web/thread_mute.ex index 3a950f474..146de0d80 100644 --- a/lib/pleroma/web/thread_mute.ex +++ b/lib/pleroma/web/thread_mute.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.ThreadMute do use Ecto.Schema + alias Pleroma.Web.ThreadMute alias Pleroma.{Activity, Repo, User} require Ecto.Query @@ -13,16 +14,37 @@ defmodule Pleroma.Web.ThreadMute do end def add_mute(user, id) do - %{data: %{"context" => context}} = Activity.get_by_id(id) + activity = Activity.get_by_id(id) + context = activity.data["context"] mute = %Pleroma.Web.ThreadMute{user_id: user.id, context: context} Repo.insert(mute) + {:ok, activity} end def remove_mute(user, id) do user_id = Pleroma.FlakeId.from_string(user.id) - %{data: %{"context" => context}} = Activity.get_by_id(id) + activity = Activity.get_by_id(id) + context = activity.data["context"] - Ecto.Query.from(m in "thread_mutes", where: m.user_id == ^user_id and m.context == ^context) + Ecto.Query.from(m in ThreadMute, where: m.user_id == ^user_id and m.context == ^context) |> Repo.delete_all() + + {:ok, activity} + end + + def muted?(user, activity) do + user_id = Pleroma.FlakeId.from_string(user.id) + context = activity.data["context"] + + result = + Ecto.Query.from(m in ThreadMute, + where: m.user_id == ^user_id and m.context == ^context + ) + |> Repo.all() + + case result do + [] -> false + _ -> true + end end end diff --git a/test/web/thread_mute_test.exs b/test/web/thread_mute_test.exs index 75277ef62..212cae860 100644 --- a/test/web/thread_mute_test.exs +++ b/test/web/thread_mute_test.exs @@ -10,31 +10,32 @@ defmodule Pleroma.Web.ThreadMuteTest do describe "mute tests" do setup do - user = insert(:user, %{id: "1"}) + user = insert(:user) - activity = - insert(:note_activity, %{ - data: %{ - "context" => "http://localhost:4000/contexts/361ca23e-ffa7-4773-b981-a355a18dc592" - } - }) + activity = insert(:note_activity) [user: user, activity: activity] end test "add mute", %{user: user, activity: activity} do id = activity.id - {:ok, mute} = add_mute(user, id) - - assert mute.user_id == "1" - assert mute.context == "http://localhost:4000/contexts/361ca23e-ffa7-4773-b981-a355a18dc592" + {:ok, _activity} = add_mute(user, id) end test "remove mute", %{user: user, activity: activity} do id = activity.id add_mute(user, id) - {1, nil} = remove_mute(user, id) + {:ok, _activity} = remove_mute(user, id) + end + + test "check mute", %{user: user, activity: activity} do + id = activity.id + + add_mute(user, id) + assert muted?(user, activity) + remove_mute(user, id) + refute muted?(user, activity) end end end From 638456ce8f6b7f44356e69bac89d794c19e969d7 Mon Sep 17 00:00:00 2001 From: Karen Konou Date: Sat, 9 Feb 2019 18:08:46 +0100 Subject: [PATCH 11/15] elixir too new for CI's mix format lol --- lib/pleroma/notification.ex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index d05708e41..ce4826b23 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -113,8 +113,7 @@ def create_notifications(_), do: {:ok, []} # TODO move to sql, too. def create_notification(%Activity{} = activity, %User{} = user) do unless User.blocks?(user, %{ap_id: activity.data["actor"]}) or - ThreadMute.muted?(user, activity) or - user.ap_id == activity.data["actor"] or + ThreadMute.muted?(user, activity) or user.ap_id == activity.data["actor"] or (activity.data["type"] == "Follow" and Enum.any?(Notification.for_user(user), fn notif -> notif.activity.data["type"] == "Follow" and From 478a05b4c99d696846b71d0eb4d6982ba422bfb8 Mon Sep 17 00:00:00 2001 From: Karen Konou Date: Sat, 9 Feb 2019 18:34:00 +0100 Subject: [PATCH 12/15] Merged "check mute" test into the other two --- test/web/thread_mute_test.exs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/test/web/thread_mute_test.exs b/test/web/thread_mute_test.exs index 212cae860..119a06f52 100644 --- a/test/web/thread_mute_test.exs +++ b/test/web/thread_mute_test.exs @@ -20,6 +20,7 @@ defmodule Pleroma.Web.ThreadMuteTest do test "add mute", %{user: user, activity: activity} do id = activity.id {:ok, _activity} = add_mute(user, id) + assert muted?(user, activity) end test "remove mute", %{user: user, activity: activity} do @@ -27,14 +28,6 @@ test "remove mute", %{user: user, activity: activity} do add_mute(user, id) {:ok, _activity} = remove_mute(user, id) - end - - test "check mute", %{user: user, activity: activity} do - id = activity.id - - add_mute(user, id) - assert muted?(user, activity) - remove_mute(user, id) refute muted?(user, activity) end end From 6a150de3bd416cfe0b4870deee2e6557791345f8 Mon Sep 17 00:00:00 2001 From: Karen Konou Date: Sat, 9 Feb 2019 20:52:11 +0100 Subject: [PATCH 13/15] Add unique index and unique constraint check, uniqueness test fails --- lib/pleroma/web/thread_mute.ex | 16 +++++++++++++--- .../20190205114625_create_thread_mutes.exs | 2 +- test/web/thread_mute_test.exs | 15 +++++++++------ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/lib/pleroma/web/thread_mute.ex b/lib/pleroma/web/thread_mute.ex index 146de0d80..b5bff86be 100644 --- a/lib/pleroma/web/thread_mute.ex +++ b/lib/pleroma/web/thread_mute.ex @@ -13,12 +13,22 @@ defmodule Pleroma.Web.ThreadMute do field(:context, :string) end + def changeset(mute, params \\ %{}) do + mute + |> Ecto.Changeset.cast(params, [:user_id, :context]) + |> Ecto.Changeset.foreign_key_constraint(:user_id) + |> Ecto.Changeset.unique_constraint(:user_id, name: :unique_index) + end + def add_mute(user, id) do activity = Activity.get_by_id(id) context = activity.data["context"] - mute = %Pleroma.Web.ThreadMute{user_id: user.id, context: context} - Repo.insert(mute) - {:ok, activity} + changeset = changeset(%Pleroma.Web.ThreadMute{}, %{user_id: user.id, context: context}) + + case Repo.insert(changeset) do + {:ok, _} -> {:ok, activity} + {:error, _} -> {:error, "conversation is already muted"} + end end def remove_mute(user, id) do diff --git a/priv/repo/migrations/20190205114625_create_thread_mutes.exs b/priv/repo/migrations/20190205114625_create_thread_mutes.exs index b16f557f0..8e9eccbae 100644 --- a/priv/repo/migrations/20190205114625_create_thread_mutes.exs +++ b/priv/repo/migrations/20190205114625_create_thread_mutes.exs @@ -7,6 +7,6 @@ def change do add :context, :string end - create index(:thread_mutes, [:user_id]) + create unique_index(:thread_mutes, [:user_id, :context], name: :unique_index) end end diff --git a/test/web/thread_mute_test.exs b/test/web/thread_mute_test.exs index 119a06f52..f3a24613c 100644 --- a/test/web/thread_mute_test.exs +++ b/test/web/thread_mute_test.exs @@ -18,17 +18,20 @@ defmodule Pleroma.Web.ThreadMuteTest do end test "add mute", %{user: user, activity: activity} do - id = activity.id - {:ok, _activity} = add_mute(user, id) + {:ok, _activity} = add_mute(user, activity.id) assert muted?(user, activity) end test "remove mute", %{user: user, activity: activity} do - id = activity.id - - add_mute(user, id) - {:ok, _activity} = remove_mute(user, id) + add_mute(user, activity.id) + {:ok, _activity} = remove_mute(user, activity.id) refute muted?(user, activity) end + + test "check that mutes can't be duplicate", %{user: user, activity: activity} do + add_mute(user, activity.id) + assert muted?(user, activity) + {:error, _} = add_mute(user, activity.id) + end end end From cc21fc5f537510416a088adff085b675de1be58e Mon Sep 17 00:00:00 2001 From: Karen Konou Date: Sun, 10 Feb 2019 09:31:20 +0100 Subject: [PATCH 14/15] refactor, status view updating, error handling --- .../mastodon_api/mastodon_api_controller.ex | 5 +++ .../web/mastodon_api/views/status_view.ex | 2 +- lib/pleroma/web/thread_mute.ex | 38 ++++++++++--------- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index a93f4297b..073e0a5ea 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -450,6 +450,11 @@ def mute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do conn |> put_view(StatusView) |> try_render("status.json", %{activity: activity, for: user, as: :activity}) + else + {:error, reason} -> + conn + |> put_resp_content_type("application/json") + |> send_resp(:bad_request, Jason.encode!(%{"error" => reason})) end end diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index a227d742d..d6176a68a 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -160,7 +160,7 @@ def render("status.json", %{activity: %{data: %{"object" => object}} = activity} reblogged: present?(repeated), favourited: present?(favorited), bookmarked: present?(bookmarked), - muted: false, + muted: Pleroma.Web.ThreadMute.muted?(user, activity), pinned: pinned?(activity, user), sensitive: sensitive, spoiler_text: object["summary"] || "", diff --git a/lib/pleroma/web/thread_mute.ex b/lib/pleroma/web/thread_mute.ex index b5bff86be..695ea2512 100644 --- a/lib/pleroma/web/thread_mute.ex +++ b/lib/pleroma/web/thread_mute.ex @@ -20,40 +20,42 @@ def changeset(mute, params \\ %{}) do |> Ecto.Changeset.unique_constraint(:user_id, name: :unique_index) end + def query(user, context) do + user_id = Pleroma.FlakeId.from_string(user.id) + + ThreadMute + |> Ecto.Query.where(user_id: ^user_id) + |> Ecto.Query.where(context: ^context) + end + def add_mute(user, id) do activity = Activity.get_by_id(id) - context = activity.data["context"] - changeset = changeset(%Pleroma.Web.ThreadMute{}, %{user_id: user.id, context: context}) - case Repo.insert(changeset) do - {:ok, _} -> {:ok, activity} + with changeset <- + changeset(%ThreadMute{}, %{user_id: user.id, context: activity.data["context"]}), + {:ok, _} <- Repo.insert(changeset) do + {:ok, activity} + else {:error, _} -> {:error, "conversation is already muted"} end end def remove_mute(user, id) do - user_id = Pleroma.FlakeId.from_string(user.id) activity = Activity.get_by_id(id) - context = activity.data["context"] - Ecto.Query.from(m in ThreadMute, where: m.user_id == ^user_id and m.context == ^context) + query(user, activity.data["context"]) |> Repo.delete_all() {:ok, activity} end + def muted?(%{id: nil} = _user, _), do: false + def muted?(user, activity) do - user_id = Pleroma.FlakeId.from_string(user.id) - context = activity.data["context"] - - result = - Ecto.Query.from(m in ThreadMute, - where: m.user_id == ^user_id and m.context == ^context - ) - |> Repo.all() - - case result do - [] -> false + with query <- query(user, activity.data["context"]), + [] <- Repo.all(query) do + false + else _ -> true end end From c01ef574c192488c2643a20b4064439757613449 Mon Sep 17 00:00:00 2001 From: Karen Konou Date: Mon, 11 Feb 2019 11:59:51 +0100 Subject: [PATCH 15/15] Refactor as per Rin's suggestions, add endpoint tests --- lib/pleroma/notification.ex | 4 +- lib/pleroma/thread_mute.ex | 45 ++++++++++++++ lib/pleroma/web/common_api/common_api.ex | 25 +++++++- .../mastodon_api/mastodon_api_controller.ex | 6 +- .../web/mastodon_api/views/status_view.ex | 3 +- lib/pleroma/web/thread_mute.ex | 62 ------------------- test/web/common_api/common_api_test.exs | 26 ++++++++ .../mastodon_api_controller_test.exs | 33 ++++++++++ test/web/thread_mute_test.exs | 37 ----------- 9 files changed, 136 insertions(+), 105 deletions(-) create mode 100644 lib/pleroma/thread_mute.ex delete mode 100644 lib/pleroma/web/thread_mute.ex delete mode 100644 test/web/thread_mute_test.exs diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index ce4826b23..9ebfd5cb0 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Notification do use Ecto.Schema alias Pleroma.{User, Activity, Notification, Repo} alias Pleroma.Web.CommonAPI.Utils - alias Pleroma.Web.ThreadMute + alias Pleroma.Web.CommonAPI import Ecto.Query schema "notifications" do @@ -113,7 +113,7 @@ def create_notifications(_), do: {:ok, []} # TODO move to sql, too. def create_notification(%Activity{} = activity, %User{} = user) do unless User.blocks?(user, %{ap_id: activity.data["actor"]}) or - ThreadMute.muted?(user, activity) or user.ap_id == activity.data["actor"] or + CommonAPI.thread_muted?(user, activity) or user.ap_id == activity.data["actor"] or (activity.data["type"] == "Follow" and Enum.any?(Notification.for_user(user), fn notif -> notif.activity.data["type"] == "Follow" and diff --git a/lib/pleroma/thread_mute.ex b/lib/pleroma/thread_mute.ex new file mode 100644 index 000000000..0b577113d --- /dev/null +++ b/lib/pleroma/thread_mute.ex @@ -0,0 +1,45 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.ThreadMute do + use Ecto.Schema + alias Pleroma.{Repo, User, ThreadMute} + require Ecto.Query + + schema "thread_mutes" do + belongs_to(:user, User, type: Pleroma.FlakeId) + field(:context, :string) + end + + def changeset(mute, params \\ %{}) do + mute + |> Ecto.Changeset.cast(params, [:user_id, :context]) + |> Ecto.Changeset.foreign_key_constraint(:user_id) + |> Ecto.Changeset.unique_constraint(:user_id, name: :unique_index) + end + + def query(user_id, context) do + user_id = Pleroma.FlakeId.from_string(user_id) + + ThreadMute + |> Ecto.Query.where(user_id: ^user_id) + |> Ecto.Query.where(context: ^context) + end + + def add_mute(user_id, context) do + %ThreadMute{} + |> changeset(%{user_id: user_id, context: context}) + |> Repo.insert() + end + + def remove_mute(user_id, context) do + query(user_id, context) + |> Repo.delete_all() + end + + def check_muted(user_id, context) do + query(user_id, context) + |> Repo.all() + end +end diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 7084da6de..7782c64dd 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.CommonAPI do - alias Pleroma.{User, Repo, Activity, Object} + alias Pleroma.{User, Repo, Activity, Object, ThreadMute} alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Formatter @@ -216,4 +216,27 @@ def unpin(id_or_ap_id, user) do {:error, "Could not unpin"} end end + + def add_mute(user, activity) do + with {:ok, _} <- ThreadMute.add_mute(user.id, activity.data["context"]) do + {:ok, activity} + else + {:error, _} -> {:error, "conversation is already muted"} + end + end + + def remove_mute(user, activity) do + ThreadMute.remove_mute(user.id, activity.data["context"]) + {:ok, activity} + end + + def thread_muted?(%{id: nil} = _user, _activity), do: false + + def thread_muted?(user, activity) do + with [] <- ThreadMute.check_muted(user.id, activity.data["context"]) do + false + else + _ -> true + end + end end diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 073e0a5ea..18fa16b03 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -446,7 +446,8 @@ def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do end def mute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with {:ok, activity} <- Pleroma.Web.ThreadMute.add_mute(user, id) do + activity = Activity.get_by_id(id) + with {:ok, activity} <- CommonAPI.add_mute(user, activity) do conn |> put_view(StatusView) |> try_render("status.json", %{activity: activity, for: user, as: :activity}) @@ -459,7 +460,8 @@ def mute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do end def unmute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with {:ok, activity} <- Pleroma.Web.ThreadMute.remove_mute(user, id) do + activity = Activity.get_by_id(id) + with {:ok, activity} <- CommonAPI.remove_mute(user, activity) do conn |> put_view(StatusView) |> try_render("status.json", %{activity: activity, for: user, as: :activity}) diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index d6176a68a..368b79ea7 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do alias Pleroma.HTML alias Pleroma.Repo alias Pleroma.User + alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI.Utils alias Pleroma.Web.MediaProxy alias Pleroma.Web.MastodonAPI.AccountView @@ -160,7 +161,7 @@ def render("status.json", %{activity: %{data: %{"object" => object}} = activity} reblogged: present?(repeated), favourited: present?(favorited), bookmarked: present?(bookmarked), - muted: Pleroma.Web.ThreadMute.muted?(user, activity), + muted: CommonAPI.thread_muted?(user, activity), pinned: pinned?(activity, user), sensitive: sensitive, spoiler_text: object["summary"] || "", diff --git a/lib/pleroma/web/thread_mute.ex b/lib/pleroma/web/thread_mute.ex deleted file mode 100644 index 695ea2512..000000000 --- a/lib/pleroma/web/thread_mute.ex +++ /dev/null @@ -1,62 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ThreadMute do - use Ecto.Schema - alias Pleroma.Web.ThreadMute - alias Pleroma.{Activity, Repo, User} - require Ecto.Query - - schema "thread_mutes" do - belongs_to(:user, User, type: Pleroma.FlakeId) - field(:context, :string) - end - - def changeset(mute, params \\ %{}) do - mute - |> Ecto.Changeset.cast(params, [:user_id, :context]) - |> Ecto.Changeset.foreign_key_constraint(:user_id) - |> Ecto.Changeset.unique_constraint(:user_id, name: :unique_index) - end - - def query(user, context) do - user_id = Pleroma.FlakeId.from_string(user.id) - - ThreadMute - |> Ecto.Query.where(user_id: ^user_id) - |> Ecto.Query.where(context: ^context) - end - - def add_mute(user, id) do - activity = Activity.get_by_id(id) - - with changeset <- - changeset(%ThreadMute{}, %{user_id: user.id, context: activity.data["context"]}), - {:ok, _} <- Repo.insert(changeset) do - {:ok, activity} - else - {:error, _} -> {:error, "conversation is already muted"} - end - end - - def remove_mute(user, id) do - activity = Activity.get_by_id(id) - - query(user, activity.data["context"]) - |> Repo.delete_all() - - {:ok, activity} - end - - def muted?(%{id: nil} = _user, _), do: false - - def muted?(user, activity) do - with query <- query(user, activity.data["context"]), - [] <- Repo.all(query) do - false - else - _ -> true - end - end -end diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index a7d9e6161..d26b6e49c 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -164,4 +164,30 @@ test "should unpin when deleting a status", %{user: user, activity: activity} do assert %User{info: %{pinned_activities: []}} = user end end + + describe "mute tests" do + setup do + user = insert(:user) + + activity = insert(:note_activity) + + [user: user, activity: activity] + end + + test "add mute", %{user: user, activity: activity} do + {:ok, _} = CommonAPI.add_mute(user, activity) + assert CommonAPI.thread_muted?(user, activity) + end + + test "remove mute", %{user: user, activity: activity} do + CommonAPI.add_mute(user, activity) + {:ok, _} = CommonAPI.remove_mute(user, activity) + refute CommonAPI.thread_muted?(user, activity) + end + + test "check that mutes can't be duplicate", %{user: user, activity: activity} do + CommonAPI.add_mute(user, activity) + {:error, _} = CommonAPI.add_mute(user, activity) + end + end end diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index f8da86004..f7c059663 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -1749,4 +1749,37 @@ test "bookmarks" do assert [json_response(response2, 200)] == json_response(bookmarks, 200) end + + describe "conversation muting" do + setup do + + user = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"}) + + [user: user, activity: activity] + end + + test "mute conversation", %{conn: conn, user: user, activity: activity} do + id_str = to_string(activity.id) + + assert %{"id" => ^id_str, "muted" => true} = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/#{activity.id}/mute") + |> json_response(200) + end + + test "unmute conversation", %{conn: conn, user: user, activity: activity} do + {:ok, _} = CommonAPI.add_mute(user, activity) + + id_str = to_string(activity.id) + user = refresh_record(user) + + assert %{"id" => ^id_str, "muted" => false} = + conn + |> assign(:user, user) + |> post("/api/v1/statuses/#{activity.id}/unmute") + |> json_response(200) + end + end end diff --git a/test/web/thread_mute_test.exs b/test/web/thread_mute_test.exs deleted file mode 100644 index f3a24613c..000000000 --- a/test/web/thread_mute_test.exs +++ /dev/null @@ -1,37 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.ThreadMuteTest do - use Pleroma.DataCase - import Pleroma.Web.ThreadMute - - import Pleroma.Factory - - describe "mute tests" do - setup do - user = insert(:user) - - activity = insert(:note_activity) - - [user: user, activity: activity] - end - - test "add mute", %{user: user, activity: activity} do - {:ok, _activity} = add_mute(user, activity.id) - assert muted?(user, activity) - end - - test "remove mute", %{user: user, activity: activity} do - add_mute(user, activity.id) - {:ok, _activity} = remove_mute(user, activity.id) - refute muted?(user, activity) - end - - test "check that mutes can't be duplicate", %{user: user, activity: activity} do - add_mute(user, activity.id) - assert muted?(user, activity) - {:error, _} = add_mute(user, activity.id) - end - end -end