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