diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 8aa9ed2d4..8c7103bc3 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -120,8 +120,11 @@ defmodule Pleroma.Notification do notification_muted_ap_ids = opts[:notification_muted_users_ap_ids] || User.notification_muted_users_ap_ids(user) + domain_mutes = user.domain_mutes || [] + query |> where([n, a], a.actor not in ^notification_muted_ap_ids) + |> where([n, a], fragment("not split_part(?, '/', 3) = ANY(?)", a.actor, ^domain_mutes)) |> join(:left, [n, a], tm in ThreadMute, on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data) ) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index cba391072..6cd0995fa 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -30,6 +30,7 @@ defmodule Pleroma.User do alias Pleroma.Web alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Builder + alias Pleroma.Web.ActivityPub.MRF alias Pleroma.Web.ActivityPub.ObjectValidators.Types alias Pleroma.Web.ActivityPub.Pipeline alias Pleroma.Web.ActivityPub.Utils @@ -108,6 +109,7 @@ defmodule Pleroma.User do field(:confirmation_token, :string, default: nil) field(:default_scope, :string, default: "public") field(:domain_blocks, {:array, :string}, default: []) + field(:domain_mutes, {:array, :string}, default: []) field(:deactivated, :boolean, default: false) field(:no_rich_text, :boolean, default: false) field(:ap_enabled, :boolean, default: false) @@ -359,8 +361,8 @@ defmodule Pleroma.User do defp fix_follower_address(params), do: params def remote_user_changeset(struct \\ %User{local: false}, params) do - bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000) - name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) + bio_limit = Config.get([:instance, :user_bio_length], 5000) + name_limit = Config.get([:instance, :user_name_length], 100) name = case params[:name] do @@ -419,8 +421,8 @@ defmodule Pleroma.User do end def update_changeset(struct, params \\ %{}) do - bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000) - name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) + bio_limit = Config.get([:instance, :user_bio_length], 5000) + name_limit = Config.get([:instance, :user_name_length], 100) struct |> cast( @@ -589,12 +591,12 @@ defmodule Pleroma.User do def force_password_reset(user), do: update_password_reset_pending(user, true) def register_changeset(struct, params \\ %{}, opts \\ []) do - bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000) - name_limit = Pleroma.Config.get([:instance, :user_name_length], 100) + bio_limit = Config.get([:instance, :user_bio_length], 5000) + name_limit = Config.get([:instance, :user_name_length], 100) need_confirmation? = if is_nil(opts[:need_confirmation]) do - Pleroma.Config.get([:instance, :account_activation_required]) + Config.get([:instance, :account_activation_required]) else opts[:need_confirmation] end @@ -606,7 +608,7 @@ defmodule Pleroma.User do |> validate_confirmation(:password) |> unique_constraint(:email) |> unique_constraint(:nickname) - |> validate_exclusion(:nickname, Pleroma.Config.get([User, :restricted_nicknames])) + |> validate_exclusion(:nickname, Config.get([User, :restricted_nicknames])) |> validate_format(:nickname, local_nickname_regex()) |> validate_format(:email, @email_regex) |> validate_length(:bio, max: bio_limit) @@ -621,7 +623,7 @@ defmodule Pleroma.User do def maybe_validate_required_email(changeset, true), do: changeset def maybe_validate_required_email(changeset, _) do - if Pleroma.Config.get([:instance, :account_activation_required]) do + if Config.get([:instance, :account_activation_required]) do validate_required(changeset, [:email]) else changeset @@ -641,7 +643,7 @@ defmodule Pleroma.User do end defp autofollow_users(user) do - candidates = Pleroma.Config.get([:instance, :autofollowed_nicknames]) + candidates = Config.get([:instance, :autofollowed_nicknames]) autofollowed_users = User.Query.build(%{nickname: candidates, local: true, deactivated: false}) @@ -668,7 +670,7 @@ defmodule Pleroma.User do def try_send_confirmation_email(%User{} = user) do if user.confirmation_pending && - Pleroma.Config.get([:instance, :account_activation_required]) do + Config.get([:instance, :account_activation_required]) do user |> Pleroma.Emails.UserEmail.account_confirmation_email() |> Pleroma.Emails.Mailer.deliver_async() @@ -725,7 +727,7 @@ defmodule Pleroma.User do defdelegate following(user), to: FollowingRelationship def follow(%User{} = follower, %User{} = followed, state \\ :follow_accept) do - deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked]) + deny_follow_blocked = Config.get([:user, :deny_follow_blocked]) cond do followed.deactivated -> @@ -916,7 +918,7 @@ defmodule Pleroma.User do end def get_cached_by_nickname_or_id(nickname_or_id, opts \\ []) do - restrict_to_local = Pleroma.Config.get([:instance, :limit_to_local_content]) + restrict_to_local = Config.get([:instance, :limit_to_local_content]) cond do is_integer(nickname_or_id) or FlakeId.flake_id?(nickname_or_id) -> @@ -977,14 +979,14 @@ defmodule Pleroma.User do @spec get_followers_query(User.t()) :: Ecto.Query.t() def get_followers_query(user), do: get_followers_query(user, nil) - @spec get_followers(User.t(), pos_integer() | nil) :: {:ok, list(User.t())} + @spec get_followers(User.t(), pos_integer() | nil) :: [User.t()] def get_followers(user, page \\ nil) do user |> get_followers_query(page) |> Repo.all() end - @spec get_external_followers(User.t(), pos_integer() | nil) :: {:ok, list(User.t())} + @spec get_external_followers(User.t(), pos_integer() | nil) :: [User.t()] def get_external_followers(user, page \\ nil) do user |> get_followers_query(page) @@ -1013,6 +1015,7 @@ defmodule Pleroma.User do @spec get_friends_query(User.t()) :: Ecto.Query.t() def get_friends_query(user), do: get_friends_query(user, nil) + @spec get_friends(User.t(), pos_integer() | nil) :: [User.t()] def get_friends(user, page \\ nil) do user |> get_friends_query(page) @@ -1111,7 +1114,7 @@ defmodule Pleroma.User do end def update_follower_count(%User{} = user) do - if user.local or !Pleroma.Config.get([:instance, :external_user_synchronization]) do + if user.local or !Config.get([:instance, :external_user_synchronization]) do follower_count_query = User.Query.build(%{followers: user, deactivated: false}) |> select([u], %{count: count(u.id)}) @@ -1135,7 +1138,7 @@ defmodule Pleroma.User do @spec update_following_count(User.t()) :: User.t() def update_following_count(%User{local: false} = user) do - if Pleroma.Config.get([:instance, :external_user_synchronization]) do + if Config.get([:instance, :external_user_synchronization]) do maybe_fetch_follow_information(user) else user @@ -1219,7 +1222,7 @@ defmodule Pleroma.User do end def subscribe(%User{} = subscriber, %User{} = target) do - deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked]) + deny_follow_blocked = Config.get([:user, :deny_follow_blocked]) if blocks?(target, subscriber) and deny_follow_blocked do {:error, "Could not subscribe: #{target.nickname} is blocking you"} @@ -1286,13 +1289,27 @@ defmodule Pleroma.User do unblock(blocker, get_cached_by_ap_id(ap_id)) end + @spec mutes?(User.t() | nil, User.t()) :: boolean() def mutes?(nil, _), do: false - def mutes?(%User{} = user, %User{} = target), do: mutes_user?(user, target) + def mutes?(%User{} = user, %User{} = target) do + mutes_user?(user, target) || mutes_domain?(user, target) + end + + @spec mutes_user?(User.t(), User.t()) :: boolean() def mutes_user?(%User{} = user, %User{} = target) do UserRelationship.mute_exists?(user, target) end + @spec mutes_domain?(User.t() | nil, User.t()) :: boolean() + def mutes_domain?(nil, _), do: false + + def mutes_domain?(%User{} = user, %User{} = target) do + domain_mutes = MRF.subdomains_regex(user.domain_mutes) + %{host: host} = URI.parse(target.ap_id) + MRF.subdomain_match?(domain_mutes, host) + end + @spec muted_notifications?(User.t() | nil, User.t() | map()) :: boolean() def muted_notifications?(nil, _), do: false @@ -1313,9 +1330,9 @@ defmodule Pleroma.User do def blocks_user?(_, _), do: false def blocks_domain?(%User{} = user, %User{} = target) do - domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.domain_blocks) + domain_blocks = MRF.subdomains_regex(user.domain_blocks) %{host: host} = URI.parse(target.ap_id) - Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, host) + MRF.subdomain_match?(domain_blocks, host) end def blocks_domain?(_, _), do: false @@ -1584,7 +1601,7 @@ defmodule Pleroma.User do Pleroma.HTML.Scrubber.TwitterText end - def html_filter_policy(_), do: Pleroma.Config.get([:markup, :scrub_policy]) + def html_filter_policy(_), do: Config.get([:markup, :scrub_policy]) def fetch_by_ap_id(ap_id), do: ActivityPub.make_user_from_ap_id(ap_id) @@ -1759,7 +1776,7 @@ defmodule Pleroma.User do end defp local_nickname_regex do - if Pleroma.Config.get([:instance, :extended_nickname_format]) do + if Config.get([:instance, :extended_nickname_format]) do @extended_local_nickname_regex else @strict_local_nickname_regex @@ -1887,8 +1904,8 @@ defmodule Pleroma.User do def get_mascot(%{mascot: mascot}) when is_nil(mascot) do # use instance-default - config = Pleroma.Config.get([:assets, :mascots]) - default_mascot = Pleroma.Config.get([:assets, :default_mascot]) + config = Config.get([:assets, :mascots]) + default_mascot = Config.get([:assets, :default_mascot]) mascot = Keyword.get(config, default_mascot) %{ @@ -1983,7 +2000,7 @@ defmodule Pleroma.User do def validate_fields(changeset, remote? \\ false) do limit_name = if remote?, do: :max_remote_account_fields, else: :max_account_fields - limit = Pleroma.Config.get([:instance, limit_name], 0) + limit = Config.get([:instance, limit_name], 0) changeset |> validate_length(:fields, max: limit) @@ -1997,8 +2014,8 @@ defmodule Pleroma.User do end defp valid_field?(%{"name" => name, "value" => value}) do - name_limit = Pleroma.Config.get([:instance, :account_field_name_length], 255) - value_limit = Pleroma.Config.get([:instance, :account_field_value_length], 255) + name_limit = Config.get([:instance, :account_field_name_length], 255) + value_limit = Config.get([:instance, :account_field_value_length], 255) is_binary(name) && is_binary(value) && String.length(name) <= name_limit && String.length(value) <= value_limit @@ -2008,10 +2025,10 @@ defmodule Pleroma.User do defp truncate_field(%{"name" => name, "value" => value}) do {name, _chopped} = - String.split_at(name, Pleroma.Config.get([:instance, :account_field_name_length], 255)) + String.split_at(name, Config.get([:instance, :account_field_name_length], 255)) {value, _chopped} = - String.split_at(value, Pleroma.Config.get([:instance, :account_field_value_length], 255)) + String.split_at(value, Config.get([:instance, :account_field_value_length], 255)) %{"name" => name, "value" => value} end @@ -2066,7 +2083,7 @@ defmodule Pleroma.User do def add_pinnned_activity(user, %Pleroma.Activity{id: id}) do if id not in user.pinned_activities do - max_pinned_statuses = Pleroma.Config.get([:instance, :max_pinned_statuses], 0) + max_pinned_statuses = Config.get([:instance, :max_pinned_statuses], 0) params = %{pinned_activities: user.pinned_activities ++ [id]} user @@ -2121,13 +2138,32 @@ defmodule Pleroma.User do set_domain_blocks(user, List.delete(user.domain_blocks, domain_blocked)) end + defp set_domain_mutes(user, domain_mutes) do + params = %{domain_mutes: domain_mutes} + + user + |> cast(params, [:domain_mutes]) + |> validate_required([:domain_mutes]) + |> update_and_set_cache() + end + + @spec mute_domain(User.t(), String.t()) :: {:ok, User.t()} + def mute_domain(%User{} = user, muted_domain) do + set_domain_mutes(user, Enum.uniq([muted_domain | user.domain_mutes])) + end + + @spec unmute_domain(User.t(), String.t()) :: {:ok, User.t()} + def unmute_domain(user, muted_domain) do + set_domain_mutes(user, List.delete(user.domain_mutes, muted_domain)) + end + @spec add_to_block(User.t(), User.t()) :: {:ok, UserRelationship.t()} | {:error, Ecto.Changeset.t()} defp add_to_block(%User{} = user, %User{} = blocked) do UserRelationship.create_block(user, blocked) end - @spec add_to_block(User.t(), User.t()) :: + @spec remove_from_block(User.t(), User.t()) :: {:ok, UserRelationship.t()} | {:ok, nil} | {:error, Ecto.Changeset.t()} defp remove_from_block(%User{} = user, %User{} = blocked) do UserRelationship.delete_block(user, blocked) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index d752f4f04..d68cfba3f 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -924,11 +924,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_muted(query, %{"muting_user" => %User{} = user} = opts) do mutes = opts["muted_users_ap_ids"] || User.muted_users_ap_ids(user) + domain_mutes = user.domain_mutes || [] query = from([activity] in query, where: fragment("not (? = ANY(?))", activity.actor, ^mutes), - where: fragment("not (?->'to' \\?| ?)", activity.data, ^mutes) + where: fragment("not (?->'to' \\?| ?)", activity.data, ^mutes), + where: fragment("not split_part(?, '/', 3) = ANY(?)", activity.actor, ^domain_mutes) ) unless opts["skip_preload"] do diff --git a/lib/pleroma/web/api_spec/operations/domain_mute_operation.ex b/lib/pleroma/web/api_spec/operations/domain_mute_operation.ex new file mode 100644 index 000000000..54d708c45 --- /dev/null +++ b/lib/pleroma/web/api_spec/operations/domain_mute_operation.ex @@ -0,0 +1,81 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ApiSpec.DomainMuteOperation do + alias OpenApiSpex.Operation + alias OpenApiSpex.Schema + import Pleroma.Web.ApiSpec.Helpers + + def open_api_operation(action) do + operation = String.to_existing_atom("#{action}_operation") + apply(__MODULE__, operation, []) + end + + def index_operation do + %Operation{ + tags: ["domain_mutes"], + summary: "Fetch domain mutes", + description: "View domains the user has muted.", + security: [%{"oAuth" => ["follow", "read:mutes"]}], + operationId: "DomainMuteController.index", + responses: %{ + 200 => + Operation.response("Domain mutes", "application/json", %Schema{ + description: "Response schema for domain mutes", + type: :array, + items: %Schema{type: :string}, + example: ["google.com", "facebook.com"] + }) + } + } + end + + def create_operation do + %Operation{ + tags: ["domain_mutes"], + summary: "Mute a domain", + description: """ + Mute a domain to: + + - hide all posts from it + - hide all notifications from it + """, + operationId: "DomainMuteController.create", + requestBody: domain_mute_request(), + security: [%{"oAuth" => ["follow", "write:mutes"]}], + responses: %{200 => empty_object_response()} + } + end + + def delete_operation do + %Operation{ + tags: ["domain_mutes"], + summary: "Unmute a domain", + description: "Remove a domain mute, if it exists in the user's array of muted domains.", + operationId: "DomainMuteController.delete", + requestBody: domain_mute_request(), + security: [%{"oAuth" => ["follow", "write:mutes"]}], + responses: %{ + 200 => Operation.response("Empty object", "application/json", %Schema{type: :object}) + } + } + end + + defp domain_mute_request do + request_body( + "Parameters", + %Schema{ + type: :object, + properties: %{ + domain: %Schema{type: :string} + }, + required: [:domain] + }, + required: true, + example: %{ + "domain" => "facebook.com" + } + ) + end +end diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 45fffaad2..04db1de84 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -109,7 +109,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do :mute, reading_user, target, - &User.mutes?(&1, &2) + &User.mutes_user?(&1, &2) ), muting_notifications: UserRelationship.exists?( diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 05a26017a..5622e6da8 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -308,6 +308,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do _ -> [] end + mutes_domain? = User.mutes_domain?(opts[:for], user) # Status muted state (would do 1 request per status unless user mutes are preloaded) muted = thread_muted? || @@ -316,8 +317,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do :mute, opts[:for], user, - fn for_user, user -> User.mutes?(for_user, user) end - ) + fn for_user, user -> User.mutes_user?(for_user, user) end + ) || mutes_domain? %{ id: to_string(activity.id), @@ -364,7 +365,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do expires_at: expires_at, direct_conversation_id: direct_conversation_id, thread_muted: thread_muted?, - emoji_reactions: emoji_reactions + emoji_reactions: emoji_reactions, + instance_muted: mutes_domain? } } end diff --git a/lib/pleroma/web/pleroma_api/controllers/domain_mute_controller.ex b/lib/pleroma/web/pleroma_api/controllers/domain_mute_controller.ex new file mode 100644 index 000000000..274094306 --- /dev/null +++ b/lib/pleroma/web/pleroma_api/controllers/domain_mute_controller.ex @@ -0,0 +1,37 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.DomainMuteController do + use Pleroma.Web, :controller + + plug(Pleroma.Web.ApiSpec.CastAndValidate) + defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.DomainMuteOperation + + plug( + Pleroma.Plugs.OAuthScopesPlug, + %{scopes: ["follow", "read:mutes"]} when action == :index + ) + + plug( + Pleroma.Plugs.OAuthScopesPlug, + %{scopes: ["follow", "write:mutes"]} when action != :index + ) + + @doc "GET /api/pleroma/domain_mutes" + def index(%{assigns: %{user: user}} = conn, _) do + json(conn, Map.get(user, :domain_mutes, [])) + end + + @doc "POST /api/pleroma/domain_mutes" + def create(%{assigns: %{user: user}, body_params: %{domain: domain}} = conn, _) do + Pleroma.User.mute_domain(user, domain) + json(conn, %{}) + end + + @doc "DELETE /api/pleroma/domain_mutes" + def delete(%{assigns: %{user: user}, body_params: %{domain: domain}} = conn, _) do + Pleroma.User.unmute_domain(user, domain) + json(conn, %{}) + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index d77a61361..ce8187cff 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -267,6 +267,10 @@ defmodule Pleroma.Web.Router do get("/accounts/mfa/setup/:method", TwoFactorAuthenticationController, :setup) post("/accounts/mfa/confirm/:method", TwoFactorAuthenticationController, :confirm) delete("/accounts/mfa/:method", TwoFactorAuthenticationController, :disable) + + get("/domain_mutes", DomainMuteController, :index) + post("/domain_mutes", DomainMuteController, :create) + delete("/domain_mutes", DomainMuteController, :delete) end scope "/oauth", Pleroma.Web.OAuth do diff --git a/priv/repo/migrations/20200513112138_add_domain_mutes_to_users.exs b/priv/repo/migrations/20200513112138_add_domain_mutes_to_users.exs new file mode 100644 index 000000000..01b54d3fa --- /dev/null +++ b/priv/repo/migrations/20200513112138_add_domain_mutes_to_users.exs @@ -0,0 +1,9 @@ +defmodule Pleroma.Repo.Migrations.AddDomainMutesToUsers do + use Ecto.Migration + + def change do + alter table(:users) do + add_if_not_exists(:domain_mutes, {:array, :text}, default: []) + end + end +end diff --git a/test/web/mastodon_api/controllers/notification_controller_test.exs b/test/web/mastodon_api/controllers/notification_controller_test.exs index 562fc4d8e..1912982ad 100644 --- a/test/web/mastodon_api/controllers/notification_controller_test.exs +++ b/test/web/mastodon_api/controllers/notification_controller_test.exs @@ -479,6 +479,30 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do assert length(json_response_and_validate_schema(conn, 200)) == 1 end + describe "muting domain" do + setup do + %{user: user, conn: conn} = oauth_access(["read:notifications"]) + user2 = insert(:user, ap_id: "https://example.com/users/other_user") + {:ok, user, _, _} = CommonAPI.follow(user, user2) + {:ok, user} = User.mute_domain(user, "example.com") + {:ok, _} = CommonAPI.post(user2, %{status: "hello @#{user.nickname}"}) + conn = assign(conn, :user, user) + [conn: conn] + end + + test "see notifications with_muted parameter", %{conn: conn} do + conn = get(conn, "/api/v1/notifications?with_muted=true") + + assert length(json_response_and_validate_schema(conn, 200)) == 1 + end + + test "doesn't see notifications without with_muted parameter", %{conn: conn} do + conn = get(conn, "/api/v1/notifications") + + assert json_response_and_validate_schema(conn, 200) == [] + end + end + @tag capture_log: true test "see move notifications" do old_user = insert(:user) diff --git a/test/web/mastodon_api/controllers/timeline_controller_test.exs b/test/web/mastodon_api/controllers/timeline_controller_test.exs index 2375ac8e8..a0eaae795 100644 --- a/test/web/mastodon_api/controllers/timeline_controller_test.exs +++ b/test/web/mastodon_api/controllers/timeline_controller_test.exs @@ -57,6 +57,63 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do end end + describe "home timeline and user muting" do + setup do: oauth_access(["read:statuses"]) + + setup %{user: user} do + other_user = insert(:user, ap_id: "https://example.com/users/other_user") + {:ok, user} = User.follow(user, other_user) + {:ok, activity} = CommonAPI.post(other_user, %{status: "Some status"}) + + {:ok, _} = User.mute(user, other_user) + [activity: activity] + end + + test "returns statuses with_muted = true", %{conn: conn, activity: activity} do + conn = get(conn, "/api/v1/timelines/home?with_muted=true") + + [status] = json_response_and_validate_schema(conn, :ok) + assert activity.id == status["id"] + assert status["muted"] + refute status["pleroma"]["instance_muted"] + end + + test "doesn't return statuses with_muted = false", %{conn: conn} do + conn = get(conn, "/api/v1/timelines/home?with_muted=false") + + assert json_response_and_validate_schema(conn, :ok) == [] + end + end + + describe "home timeline and domain muting" do + setup do: oauth_access(["read:statuses"]) + + setup %{user: user, conn: conn} do + other_user = insert(:user, ap_id: "https://example.com/users/other_user") + {:ok, user} = User.follow(user, other_user) + {:ok, activity} = CommonAPI.post(other_user, %{status: "Some Status"}) + + {:ok, user} = User.mute_domain(user, "example.com") + conn = assign(conn, :user, user) + [activity: activity, conn: conn] + end + + test "returns statuses with_muted = true", %{conn: conn, activity: activity} do + conn = get(conn, "/api/v1/timelines/home?with_muted=true") + + [status] = json_response_and_validate_schema(conn, :ok) + assert activity.id == status["id"] + assert status["muted"] + assert status["pleroma"]["instance_muted"] + end + + test "doesn't return statuses with_muted = false", %{conn: conn} do + conn = get(conn, "/api/v1/timelines/home?with_muted=false") + + assert json_response_and_validate_schema(conn, :ok) == [] + end + end + describe "public" do @tag capture_log: true test "the public timeline", %{conn: conn} do diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs index 5d7adbe29..4787c9832 100644 --- a/test/web/mastodon_api/views/status_view_test.exs +++ b/test/web/mastodon_api/views/status_view_test.exs @@ -226,7 +226,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do expires_at: nil, direct_conversation_id: nil, thread_muted: false, - emoji_reactions: [] + emoji_reactions: [], + instance_muted: false } } diff --git a/test/web/pleroma_api/controllers/domain_mute_controller_test.exs b/test/web/pleroma_api/controllers/domain_mute_controller_test.exs new file mode 100644 index 000000000..79b71dfee --- /dev/null +++ b/test/web/pleroma_api/controllers/domain_mute_controller_test.exs @@ -0,0 +1,44 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.DomainMuteControllerTest do + use Pleroma.Web.ConnCase, async: true + + import Pleroma.Factory + + alias Pleroma.User + + test "muting / unmuting domain" do + %{user: user, conn: conn} = oauth_access(["write:mutes", "read:mutes"]) + conn = put_req_header(conn, "content-type", "application/json") + + other_user = insert(:user, ap_id: "https://example.com/users/other_user") + + response = post(conn, "/api/pleroma/domain_mutes", %{"domain" => "example.com"}) + + assert %{} == json_response_and_validate_schema(response, 200) + user = User.get_cached_by_ap_id(user.ap_id) + assert User.mutes?(user, other_user) + assert User.mutes_domain?(user, other_user) + + assert ["example.com"] == + conn + |> assign(:user, user) + |> get("/api/pleroma/domain_mutes") + |> json_response_and_validate_schema(200) + + response = delete(conn, "/api/pleroma/domain_mutes", %{"domain" => "example.com"}) + + assert %{} == json_response_and_validate_schema(response, 200) + user = User.get_cached_by_ap_id(user.ap_id) + refute User.mutes?(user, other_user) + refute User.mutes_domain?(user, other_user) + + assert [] == + conn + |> assign(:user, user) + |> get("/api/pleroma/domain_mutes") + |> json_response_and_validate_schema(200) + end +end