diff options
24 files changed, 332 insertions, 49 deletions
| diff --git a/CHANGELOG.md b/CHANGELOG.md index 99b42e280..4766aef6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).  - MRF: Support for stripping avatars and banner images from specific instances (`mrf_simple`)  - MRF: Support for running subchains.  - Addressable lists +- Configuration: `skip_thread_containment` option  ### Changed  - **Breaking:** Configuration: move from Pleroma.Mailer to Pleroma.Emails.Mailer diff --git a/config/config.exs b/config/config.exs index 7d70c1a5e..a3f33cfbb 100644 --- a/config/config.exs +++ b/config/config.exs @@ -243,7 +243,8 @@ config :pleroma, :instance,    max_report_comment_size: 1000,    safe_dm_mentions: false,    healthcheck: false, -  remote_post_retention_days: 90 +  remote_post_retention_days: 90, +  skip_thread_containment: false  config :pleroma, :app_account_creation, enabled: true, max_requests: 25, interval: 1800 diff --git a/docs/api/differences_in_mastoapi_responses.md b/docs/api/differences_in_mastoapi_responses.md index 27463f8f3..fd23fe2d2 100644 --- a/docs/api/differences_in_mastoapi_responses.md +++ b/docs/api/differences_in_mastoapi_responses.md @@ -83,6 +83,7 @@ Additional parameters can be added to the JSON body/Form data:  - `show_role` - if true, user's role (e.g admin, moderator) will be exposed to anyone in the API  - `default_scope` - the scope returned under `privacy` key in Source subentity  - `pleroma_settings_store` - Opaque user settings to be saved on the backend. +- `skip_thread_containment` - if true, skip filtering out broken threads  ### Pleroma Settings Store  Pleroma has mechanism that allows frontends to save blobs of json for each user on the backend. This can be used to save frontend-specific settings for a user that the backend does not need to know about. diff --git a/docs/config.md b/docs/config.md index 718a7912a..f4a1868fd 100644 --- a/docs/config.md +++ b/docs/config.md @@ -111,6 +111,7 @@ config :pleroma, Pleroma.Emails.Mailer,  * `safe_dm_mentions`: If set to true, only mentions at the beginning of a post will be used to address people in direct messages. This is to prevent accidental mentioning of people when talking about them (e.g. "@friend hey i really don't like @enemy"). (Default: `false`)  * `healthcheck`: if set to true, system data will be shown on ``/api/pleroma/healthcheck``.  * `remote_post_retention_days`: the default amount of days to retain remote posts when pruning the database +* `skip_thread_containment`: Skip filter out broken threads. the default is `false`.  ## :app_account_creation  REST API for creating an account settings diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex index 2a11f9069..2c13c4b40 100644 --- a/lib/pleroma/conversation/participation.ex +++ b/lib/pleroma/conversation/participation.ex @@ -79,5 +79,6 @@ defmodule Pleroma.Conversation.Participation do          | last_activity_id: activity_id        }      end) +    |> Enum.filter(& &1.last_activity_id)    end  end diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index 7d12eff7f..de7fcc1ce 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -97,10 +97,22 @@ defmodule Pleroma.Emoji do          # There was some other error          Logger.error("Could not access the custom emoji directory #{emoji_dir_path}: #{e}") -      {:ok, packs} -> +      {:ok, results} -> +        grouped = Enum.group_by(results, &File.dir?/1) +        packs = grouped[true] || [] +        files = grouped[false] || [] +          # Print the packs we've found          Logger.info("Found emoji packs: #{Enum.join(packs, ", ")}") +        if not Enum.empty?(files) do +          Logger.warn( +            "Found files in the emoji folder. These will be ignored, please move them to a subdirectory\nFound files: #{ +              Enum.join(files, ", ") +            }" +          ) +        end +          emojis =            Enum.flat_map(              packs, diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index fb9ab92ab..08e43ff0f 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -55,6 +55,8 @@ defmodule Pleroma.User.Info do        }      ) +    field(:skip_thread_containment, :boolean, default: false) +      # Found in the wild      # ap_id -> Where is this used?      # bio -> Where is this used? @@ -220,6 +222,7 @@ defmodule Pleroma.User.Info do        :hide_favorites,        :background,        :show_role, +      :skip_thread_containment,        :pleroma_settings_store      ])    end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 47115aa6e..73c6e4cbf 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -4,6 +4,7 @@  defmodule Pleroma.Web.ActivityPub.ActivityPub do    alias Pleroma.Activity +  alias Pleroma.Config    alias Pleroma.Conversation    alias Pleroma.Notification    alias Pleroma.Object @@ -72,7 +73,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do    end    defp check_remote_limit(%{"object" => %{"content" => content}}) when not is_nil(content) do -    limit = Pleroma.Config.get([:instance, :remote_limit]) +    limit = Config.get([:instance, :remote_limit])      String.length(content) <= limit    end @@ -410,8 +411,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do    end    def block(blocker, blocked, activity_id \\ nil, local \\ true) do -    outgoing_blocks = Pleroma.Config.get([:activitypub, :outgoing_blocks]) -    unfollow_blocked = Pleroma.Config.get([:activitypub, :unfollow_blocked]) +    outgoing_blocks = Config.get([:activitypub, :outgoing_blocks]) +    unfollow_blocked = Config.get([:activitypub, :unfollow_blocked])      if unfollow_blocked do        follow_activity = fetch_latest_follow(blocker, blocked) @@ -556,14 +557,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do    defp restrict_visibility(query, %{visibility: visibility})         when visibility in @valid_visibilities do -    query = -      from( -        a in query, -        where: -          fragment("activity_visibility(?, ?, ?) = ?", a.actor, a.recipients, a.data, ^visibility) -      ) - -    query +    from( +      a in query, +      where: +        fragment("activity_visibility(?, ?, ?) = ?", a.actor, a.recipients, a.data, ^visibility) +    )    end    defp restrict_visibility(_query, %{visibility: visibility}) @@ -573,17 +571,24 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do    defp restrict_visibility(query, _visibility), do: query -  defp restrict_thread_visibility(query, %{"user" => %User{ap_id: ap_id}}) do -    query = -      from( -        a in query, -        where: fragment("thread_visibility(?, (?)->>'id') = true", ^ap_id, a.data) -      ) +  defp restrict_thread_visibility(query, _, %{skip_thread_containment: true} = _), +    do: query -    query +  defp restrict_thread_visibility( +         query, +         %{"user" => %User{info: %{skip_thread_containment: true}}}, +         _ +       ), +       do: query + +  defp restrict_thread_visibility(query, %{"user" => %User{ap_id: ap_id}}, _) do +    from( +      a in query, +      where: fragment("thread_visibility(?, (?)->>'id') = true", ^ap_id, a.data) +    )    end -  defp restrict_thread_visibility(query, _), do: query +  defp restrict_thread_visibility(query, _, _), do: query    def fetch_user_activities(user, reading_user, params \\ %{}) do      params = @@ -860,6 +865,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do    defp maybe_order(query, _), do: query    def fetch_activities_query(recipients, opts \\ %{}) do +    config = %{ +      skip_thread_containment: Config.get([:instance, :skip_thread_containment]) +    } +      Activity      |> maybe_preload_objects(opts)      |> maybe_preload_bookmarks(opts) @@ -879,7 +888,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do      |> restrict_muted(opts)      |> restrict_media(opts)      |> restrict_visibility(opts) -    |> restrict_thread_visibility(opts) +    |> restrict_thread_visibility(opts, config)      |> restrict_replies(opts)      |> restrict_reblogs(opts)      |> restrict_pinned(opts) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index b8159e9e5..faae7e747 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -794,6 +794,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do      query =        from(          [activity, object: object] in Activity.with_preloaded_object(Activity), +        where: fragment("(?)->>'type' = 'Create'", activity.data),          where: fragment("(?)->>'actor' = ?", activity.data, ^actor),          where:            fragment( diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 85fb32669..536058666 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -132,13 +132,16 @@ defmodule Pleroma.Web.CommonAPI do          Enum.map(choices, fn index ->            answer_data = make_answer_data(user, object, Enum.at(options, index)["name"]) -          ActivityPub.create(%{ -            to: answer_data["to"], -            actor: user, -            context: object.data["context"], -            object: answer_data, -            additional: %{"cc" => answer_data["cc"]} -          }) +          {:ok, activity} = +            ActivityPub.create(%{ +              to: answer_data["to"], +              actor: user, +              context: object.data["context"], +              object: answer_data, +              additional: %{"cc" => answer_data["cc"]} +            }) + +          activity          end)        object = Object.get_cached_by_ap_id(object.data["id"]) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index fe2fdcea1..d825555c6 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -117,7 +117,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do        |> Enum.dedup()      info_params = -      [:no_rich_text, :locked, :hide_followers, :hide_follows, :hide_favorites, :show_role] +      [ +        :no_rich_text, +        :locked, +        :hide_followers, +        :hide_follows, +        :hide_favorites, +        :show_role, +        :skip_thread_containment +      ]        |> Enum.reduce(%{}, fn key, acc ->          add_if_present(acc, params, to_string(key), key, fn value ->            {:ok, ControllerHelper.truthy_param?(value)} diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index dc32a1525..b91726b45 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -124,7 +124,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do          hide_followers: user.info.hide_followers,          hide_follows: user.info.hide_follows,          hide_favorites: user.info.hide_favorites, -        relationship: relationship +        relationship: relationship, +        skip_thread_containment: user.info.skip_thread_containment        }      }      |> maybe_put_role(user, opts[:for]) diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index 133decfc4..a23f80f26 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.Streamer do    use GenServer    require Logger    alias Pleroma.Activity +  alias Pleroma.Config    alias Pleroma.Conversation.Participation    alias Pleroma.Notification    alias Pleroma.Object @@ -224,11 +225,10 @@ defmodule Pleroma.Web.Streamer do          mutes = user.info.mutes || []          reblog_mutes = user.info.muted_reblogs || [] -        parent = Object.normalize(item) - -        unless is_nil(parent) or item.actor in blocks or item.actor in mutes or -                 item.actor in reblog_mutes or not ActivityPub.contain_activity(item, user) or -                 parent.data["actor"] in blocks or parent.data["actor"] in mutes do +        with parent when not is_nil(parent) <- Object.normalize(item), +             true <- Enum.all?([blocks, mutes, reblog_mutes], &(item.actor not in &1)), +             true <- Enum.all?([blocks, mutes], &(parent.data["actor"] not in &1)), +             true <- thread_containment(item, user) do            send(socket.transport_pid, {:text, represent_update(item, user)})          end        else @@ -264,8 +264,8 @@ defmodule Pleroma.Web.Streamer do          blocks = user.info.blocks || []          mutes = user.info.mutes || [] -        unless item.actor in blocks or item.actor in mutes or -                 not ActivityPub.contain_activity(item, user) do +        with true <- Enum.all?([blocks, mutes], &(item.actor not in &1)), +             true <- thread_containment(item, user) do            send(socket.transport_pid, {:text, represent_update(item, user)})          end        else @@ -279,4 +279,15 @@ defmodule Pleroma.Web.Streamer do    end    defp internal_topic(topic, _), do: topic + +  @spec thread_containment(Activity.t(), User.t()) :: boolean() +  defp thread_containment(_activity, %User{info: %{skip_thread_containment: true}}), do: true + +  defp thread_containment(activity, user) do +    if Config.get([:instance, :skip_thread_containment]) do +      true +    else +      ActivityPub.contain_activity(activity, user) +    end +  end  end diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 1b6b33e69..6cf107d17 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -632,7 +632,15 @@ defmodule Pleroma.Web.TwitterAPI.Controller do    defp build_info_cng(user, params) do      info_params = -      ["no_rich_text", "locked", "hide_followers", "hide_follows", "hide_favorites", "show_role"] +      [ +        "no_rich_text", +        "locked", +        "hide_followers", +        "hide_follows", +        "hide_favorites", +        "show_role", +        "skip_thread_containment" +      ]        |> Enum.reduce(%{}, fn key, res ->          if value = params[key] do            Map.put(res, key, value == "true") diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index 550f35f5f..8d8892068 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -118,7 +118,8 @@ defmodule Pleroma.Web.TwitterAPI.UserView do          "pleroma" =>            %{              "confirmation_pending" => user_info.confirmation_pending, -            "tags" => user.tags +            "tags" => user.tags, +            "skip_thread_containment" => user.info.skip_thread_containment            }            |> maybe_with_activation_status(user, for_user)            |> with_notification_settings(user, for_user) @@ -157,7 +157,8 @@ defmodule Pleroma.Mixfile do    #   * the mix environment if different than prod    defp version(version) do      {git_tag, git_pre_release} = -      with {tag, 0} <- System.cmd("git", ["describe", "--tags", "--abbrev=0"]), +      with {tag, 0} <- +             System.cmd("git", ["describe", "--tags", "--abbrev=0"], stderr_to_stdout: true),             tag = String.trim(tag),             {describe, 0} <- System.cmd("git", ["describe", "--tags", "--abbrev=8"]),             describe = String.trim(describe), diff --git a/test/conversation/participation_test.exs b/test/conversation/participation_test.exs index 568953b07..0e60bfca5 100644 --- a/test/conversation/participation_test.exs +++ b/test/conversation/participation_test.exs @@ -86,4 +86,17 @@ defmodule Pleroma.Conversation.ParticipationTest do      assert participation_one.last_activity_id == activity_three.id    end + +  test "Doesn't die when the conversation gets empty" do +    user = insert(:user) + +    {:ok, activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"}) +    [participation] = Participation.for_user_with_last_activity_id(user) + +    assert participation.last_activity_id == activity.id + +    {:ok, _} = CommonAPI.delete(activity.id, user) + +    [] = Participation.for_user_with_last_activity_id(user) +  end  end diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs index c57fae437..de741c64b 100644 --- a/test/web/activity_pub/utils_test.exs +++ b/test/web/activity_pub/utils_test.exs @@ -1,6 +1,7 @@  defmodule Pleroma.Web.ActivityPub.UtilsTest do    use Pleroma.DataCase    alias Pleroma.Activity +  alias Pleroma.Object    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.Utils @@ -204,4 +205,46 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do               ]             }    end + +  describe "get_existing_votes" do +    test "fetches existing votes" do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, activity} = +        CommonAPI.post(user, %{ +          "status" => "How do I pronounce LaTeX?", +          "poll" => %{ +            "options" => ["laytekh", "lahtekh", "latex"], +            "expires_in" => 20, +            "multiple" => true +          } +        }) + +      object = Object.normalize(activity) +      {:ok, votes, object} = CommonAPI.vote(other_user, object, [0, 1]) +      assert Enum.sort(Utils.get_existing_votes(other_user.ap_id, object)) == Enum.sort(votes) +    end + +    test "fetches only Create activities" do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, activity} = +        CommonAPI.post(user, %{ +          "status" => "Are we living in a society?", +          "poll" => %{ +            "options" => ["yes", "no"], +            "expires_in" => 20 +          } +        }) + +      object = Object.normalize(activity) +      {:ok, [vote], object} = CommonAPI.vote(other_user, object, [0]) +      vote_object = Object.normalize(vote) +      {:ok, _activity, _object} = ActivityPub.like(user, vote_object) +      [fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object) +      assert fetched_vote.id == vote.id +    end +  end  end diff --git a/test/web/activity_pub/visibilty_test.exs b/test/web/activity_pub/visibilty_test.exs index 466d980dc..e24df3cab 100644 --- a/test/web/activity_pub/visibilty_test.exs +++ b/test/web/activity_pub/visibilty_test.exs @@ -1,6 +1,7 @@  defmodule Pleroma.Web.ActivityPub.VisibilityTest do    use Pleroma.DataCase +  alias Pleroma.Activity    alias Pleroma.Web.ActivityPub.Visibility    alias Pleroma.Web.CommonAPI    import Pleroma.Factory @@ -121,4 +122,46 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do    test "get_visibility with directMessage flag" do      assert Visibility.get_visibility(%{data: %{"directMessage" => true}}) == "direct"    end + +  describe "entire_thread_visible_for_user?/2" do +    test "returns false if not found activity", %{user: user} do +      refute Visibility.entire_thread_visible_for_user?(%Activity{}, user) +    end + +    test "returns true if activity hasn't 'Create' type", %{user: user} do +      activity = insert(:like_activity) +      assert Visibility.entire_thread_visible_for_user?(activity, user) +    end + +    test "returns false when invalid recipients", %{user: user} do +      author = insert(:user) + +      activity = +        insert(:note_activity, +          note: +            insert(:note, +              user: author, +              data: %{"to" => ["test-user"]} +            ) +        ) + +      refute Visibility.entire_thread_visible_for_user?(activity, user) +    end + +    test "returns true if user following to author" do +      author = insert(:user) +      user = insert(:user, following: [author.ap_id]) + +      activity = +        insert(:note_activity, +          note: +            insert(:note, +              user: author, +              data: %{"to" => [user.ap_id]} +            ) +        ) + +      assert Visibility.entire_thread_visible_for_user?(activity, user) +    end +  end  end diff --git a/test/web/mastodon_api/account_view_test.exs b/test/web/mastodon_api/account_view_test.exs index 1611d937e..e2244dcb7 100644 --- a/test/web/mastodon_api/account_view_test.exs +++ b/test/web/mastodon_api/account_view_test.exs @@ -67,7 +67,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do          hide_favorites: true,          hide_followers: false,          hide_follows: false, -        relationship: %{} +        relationship: %{}, +        skip_thread_containment: false        }      } @@ -132,7 +133,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do          hide_favorites: true,          hide_followers: false,          hide_follows: false, -        relationship: %{} +        relationship: %{}, +        skip_thread_containment: false        }      } @@ -233,7 +235,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do            domain_blocking: false,            showing_reblogs: true,            endorsed: false -        } +        }, +        skip_thread_containment: false        }      } diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs index b0cde649d..8679a083d 100644 --- a/test/web/mastodon_api/mastodon_api_controller_test.exs +++ b/test/web/mastodon_api/mastodon_api_controller_test.exs @@ -2539,6 +2539,19 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do        assert user["pleroma"]["hide_followers"] == true      end +    test "updates the user's skip_thread_containment option", %{conn: conn} do +      user = insert(:user) + +      response = +        conn +        |> assign(:user, user) +        |> patch("/api/v1/accounts/update_credentials", %{skip_thread_containment: "true"}) +        |> json_response(200) + +      assert response["pleroma"]["skip_thread_containment"] == true +      assert refresh_record(user).info.skip_thread_containment +    end +      test "updates the user's hide_follows status", %{conn: conn} do        user = insert(:user) diff --git a/test/web/streamer_test.exs b/test/web/streamer_test.exs index bfe18cb7f..c18b9f9fe 100644 --- a/test/web/streamer_test.exs +++ b/test/web/streamer_test.exs @@ -11,6 +11,16 @@ defmodule Pleroma.Web.StreamerTest do    alias Pleroma.Web.Streamer    import Pleroma.Factory +  setup do +    skip_thread_containment = Pleroma.Config.get([:instance, :skip_thread_containment]) + +    on_exit(fn -> +      Pleroma.Config.put([:instance, :skip_thread_containment], skip_thread_containment) +    end) + +    :ok +  end +    test "it sends to public" do      user = insert(:user)      other_user = insert(:user) @@ -68,6 +78,74 @@ defmodule Pleroma.Web.StreamerTest do      Task.await(task)    end +  describe "thread_containment" do +    test "it doesn't send to user if recipients invalid and thread containment is enabled" do +      Pleroma.Config.put([:instance, :skip_thread_containment], false) +      author = insert(:user) +      user = insert(:user, following: [author.ap_id]) + +      activity = +        insert(:note_activity, +          note: +            insert(:note, +              user: author, +              data: %{"to" => ["TEST-FFF"]} +            ) +        ) + +      task = Task.async(fn -> refute_receive {:text, _}, 1_000 end) +      fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} +      topics = %{"public" => [fake_socket]} +      Streamer.push_to_socket(topics, "public", activity) + +      Task.await(task) +    end + +    test "it sends message if recipients invalid and thread containment is disabled" do +      Pleroma.Config.put([:instance, :skip_thread_containment], true) +      author = insert(:user) +      user = insert(:user, following: [author.ap_id]) + +      activity = +        insert(:note_activity, +          note: +            insert(:note, +              user: author, +              data: %{"to" => ["TEST-FFF"]} +            ) +        ) + +      task = Task.async(fn -> assert_receive {:text, _}, 1_000 end) +      fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} +      topics = %{"public" => [fake_socket]} +      Streamer.push_to_socket(topics, "public", activity) + +      Task.await(task) +    end + +    test "it sends message if recipients invalid and thread containment is enabled but user's thread containment is disabled" do +      Pleroma.Config.put([:instance, :skip_thread_containment], false) +      author = insert(:user) +      user = insert(:user, following: [author.ap_id], info: %{skip_thread_containment: true}) + +      activity = +        insert(:note_activity, +          note: +            insert(:note, +              user: author, +              data: %{"to" => ["TEST-FFF"]} +            ) +        ) + +      task = Task.async(fn -> assert_receive {:text, _}, 1_000 end) +      fake_socket = %{transport_pid: task.pid, assigns: %{user: user}} +      topics = %{"public" => [fake_socket]} +      Streamer.push_to_socket(topics, "public", activity) + +      Task.await(task) +    end +  end +    test "it doesn't send to blocked users" do      user = insert(:user)      blocked_user = insert(:user) diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index bcd0f522d..8187ffd0e 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -1495,7 +1495,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do            "hide_follows" => "false"          }) -      user = Repo.get!(User, user.id) +      user = refresh_record(user)        assert user.info.hide_follows == false        assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})      end @@ -1548,6 +1548,29 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do        assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})      end +    test "it sets and un-sets skip_thread_containment", %{conn: conn} do +      user = insert(:user) + +      response = +        conn +        |> assign(:user, user) +        |> post("/api/account/update_profile.json", %{"skip_thread_containment" => "true"}) +        |> json_response(200) + +      assert response["pleroma"]["skip_thread_containment"] == true +      user = refresh_record(user) +      assert user.info.skip_thread_containment + +      response = +        conn +        |> assign(:user, user) +        |> post("/api/account/update_profile.json", %{"skip_thread_containment" => "false"}) +        |> json_response(200) + +      assert response["pleroma"]["skip_thread_containment"] == false +      refute refresh_record(user).info.skip_thread_containment +    end +      test "it locks an account", %{conn: conn} do        user = insert(:user) diff --git a/test/web/twitter_api/views/user_view_test.exs b/test/web/twitter_api/views/user_view_test.exs index a48fc9b78..70c5a0b7f 100644 --- a/test/web/twitter_api/views/user_view_test.exs +++ b/test/web/twitter_api/views/user_view_test.exs @@ -99,7 +99,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do        "fields" => [],        "pleroma" => %{          "confirmation_pending" => false, -        "tags" => [] +        "tags" => [], +        "skip_thread_containment" => false        },        "rights" => %{"admin" => false, "delete_others_notice" => false},        "role" => "member" @@ -154,7 +155,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do        "fields" => [],        "pleroma" => %{          "confirmation_pending" => false, -        "tags" => [] +        "tags" => [], +        "skip_thread_containment" => false        },        "rights" => %{"admin" => false, "delete_others_notice" => false},        "role" => "member" @@ -199,7 +201,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do        "fields" => [],        "pleroma" => %{          "confirmation_pending" => false, -        "tags" => [] +        "tags" => [], +        "skip_thread_containment" => false        },        "rights" => %{"admin" => false, "delete_others_notice" => false},        "role" => "member" @@ -281,7 +284,8 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do        "fields" => [],        "pleroma" => %{          "confirmation_pending" => false, -        "tags" => [] +        "tags" => [], +        "skip_thread_containment" => false        },        "rights" => %{"admin" => false, "delete_others_notice" => false},        "role" => "member" | 
