diff options
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | docs/api/differences_in_mastoapi_responses.md | 4 | ||||
| -rw-r--r-- | lib/pleroma/user/info.ex | 14 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/views/user_view.ex | 32 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/views/account_view.ex | 14 | ||||
| -rw-r--r-- | test/web/activity_pub/views/user_view_test.exs | 24 | ||||
| -rw-r--r-- | test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs | 16 | ||||
| -rw-r--r-- | test/web/mastodon_api/views/account_view_test.exs | 31 | 
9 files changed, 117 insertions, 21 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 9de978e19..906aa985e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).  - Mastodon API: added `/auth/password` endpoint for password reset with rate limit.  - Mastodon API: /api/v1/accounts/:id/statuses now supports nicknames or user id  - Mastodon API: Improve support for the user profile custom fields +- Mastodon API: follower/following counters are nullified when `hide_follows`/`hide_followers` and `hide_follows_count`/`hide_followers_count` are set  - Admin API: Return users' tags when querying reports  - Admin API: Return avatar and display name when querying users  - Admin API: Allow querying user by ID diff --git a/docs/api/differences_in_mastoapi_responses.md b/docs/api/differences_in_mastoapi_responses.md index 9b32baf3a..3c7f5dad7 100644 --- a/docs/api/differences_in_mastoapi_responses.md +++ b/docs/api/differences_in_mastoapi_responses.md @@ -50,6 +50,8 @@ Has these additional fields under the `pleroma` object:  - `confirmation_pending`: boolean, true if a new user account is waiting on email confirmation to be activated  - `hide_followers`: boolean, true when the user has follower hiding enabled  - `hide_follows`: boolean, true when the user has follow hiding enabled +- `hide_followers_count`: boolean, true when the user has follower stat hiding enabled +- `hide_follows_count`: boolean, true when the user has follow stat hiding enabled  - `settings_store`: A generic map of settings for frontends. Opaque to the backend. Only returned in `verify_credentials` and `update_credentials`  - `chat_token`: The token needed for Pleroma chat. Only returned in `verify_credentials`  - `deactivated`: boolean, true when the user is deactivated @@ -112,6 +114,8 @@ Additional parameters can be added to the JSON body/Form data:  - `no_rich_text` - if true, html tags are stripped from all statuses requested from the API  - `hide_followers` - if true, user's followers will be hidden  - `hide_follows` - if true, user's follows will be hidden +- `hide_followers_count` - if true, user's follower count will be hidden +- `hide_follows_count` - if true, user's follow count will be hidden  - `hide_favorites` - if true, user's favorites timeline will be hidden  - `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 diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 151e025de..b150a57cd 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -41,6 +41,8 @@ defmodule Pleroma.User.Info do      field(:topic, :string, default: nil)      field(:hub, :string, default: nil)      field(:salmon, :string, default: nil) +    field(:hide_followers_count, :boolean, default: false) +    field(:hide_follows_count, :boolean, default: false)      field(:hide_followers, :boolean, default: false)      field(:hide_follows, :boolean, default: false)      field(:hide_favorites, :boolean, default: true) @@ -262,6 +264,8 @@ defmodule Pleroma.User.Info do        :salmon,        :hide_followers,        :hide_follows, +      :hide_followers_count, +      :hide_follows_count,        :follower_count,        :fields,        :following_count @@ -281,7 +285,9 @@ defmodule Pleroma.User.Info do        :following_count,        :hide_follows,        :fields, -      :hide_followers +      :hide_followers, +      :hide_followers_count, +      :hide_follows_count      ])      |> validate_fields(remote?)    end @@ -295,6 +301,8 @@ defmodule Pleroma.User.Info do        :banner,        :hide_follows,        :hide_followers, +      :hide_followers_count, +      :hide_follows_count,        :hide_favorites,        :background,        :show_role, @@ -458,7 +466,9 @@ defmodule Pleroma.User.Info do        :hide_followers,        :hide_follows,        :follower_count, -      :following_count +      :following_count, +      :hide_followers_count, +      :hide_follows_count      ])    end  end diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 7be734b26..164b973d0 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -118,30 +118,34 @@ defmodule Pleroma.Web.ActivityPub.UserView do    end    def render("following.json", %{user: user, page: page} = opts) do -    showing = (opts[:for] && opts[:for] == user) || !user.info.hide_follows +    showing_items = (opts[:for] && opts[:for] == user) || !user.info.hide_follows +    showing_count = showing_items || !user.info.hide_follows_count +      query = User.get_friends_query(user)      query = from(user in query, select: [:ap_id])      following = Repo.all(query)      total = -      if showing do +      if showing_count do          length(following)        else          0        end -    collection(following, "#{user.ap_id}/following", page, showing, total) +    collection(following, "#{user.ap_id}/following", page, showing_items, total)      |> Map.merge(Utils.make_json_ld_header())    end    def render("following.json", %{user: user} = opts) do -    showing = (opts[:for] && opts[:for] == user) || !user.info.hide_follows +    showing_items = (opts[:for] && opts[:for] == user) || !user.info.hide_follows +    showing_count = showing_items || !user.info.hide_follows_count +      query = User.get_friends_query(user)      query = from(user in query, select: [:ap_id])      following = Repo.all(query)      total = -      if showing do +      if showing_count do          length(following)        else          0 @@ -152,7 +156,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do        "type" => "OrderedCollection",        "totalItems" => total,        "first" => -        if showing do +        if showing_items do            collection(following, "#{user.ap_id}/following", 1, !user.info.hide_follows)          else            "#{user.ap_id}/following?page=1" @@ -162,32 +166,34 @@ defmodule Pleroma.Web.ActivityPub.UserView do    end    def render("followers.json", %{user: user, page: page} = opts) do -    showing = (opts[:for] && opts[:for] == user) || !user.info.hide_followers +    showing_items = (opts[:for] && opts[:for] == user) || !user.info.hide_followers +    showing_count = showing_items || !user.info.hide_followers_count      query = User.get_followers_query(user)      query = from(user in query, select: [:ap_id])      followers = Repo.all(query)      total = -      if showing do +      if showing_count do          length(followers)        else          0        end -    collection(followers, "#{user.ap_id}/followers", page, showing, total) +    collection(followers, "#{user.ap_id}/followers", page, showing_items, total)      |> Map.merge(Utils.make_json_ld_header())    end    def render("followers.json", %{user: user} = opts) do -    showing = (opts[:for] && opts[:for] == user) || !user.info.hide_followers +    showing_items = (opts[:for] && opts[:for] == user) || !user.info.hide_followers +    showing_count = showing_items || !user.info.hide_followers_count      query = User.get_followers_query(user)      query = from(user in query, select: [:ap_id])      followers = Repo.all(query)      total = -      if showing do +      if showing_count do          length(followers)        else          0 @@ -198,8 +204,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do        "type" => "OrderedCollection",        "totalItems" => total,        "first" => -        if showing do -          collection(followers, "#{user.ap_id}/followers", 1, showing, total) +        if showing_items do +          collection(followers, "#{user.ap_id}/followers", 1, showing_items, total)          else            "#{user.ap_id}/followers?page=1"          end diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex index 970cfd8db..37eeb2ac3 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -147,6 +147,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do        [          :no_rich_text,          :locked, +        :hide_followers_count, +        :hide_follows_count,          :hide_followers,          :hide_follows,          :hide_favorites, diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 169116d0d..195dd124b 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -74,10 +74,18 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do      user_info = User.get_cached_user_info(user)      following_count = -      ((!user.info.hide_follows or opts[:for] == user) && user_info.following_count) || 0 +      if !user.info.hide_follows_count or !user.info.hide_follows or opts[:for] == user do +        user_info.following_count +      else +        0 +      end      followers_count = -      ((!user.info.hide_followers or opts[:for] == user) && user_info.follower_count) || 0 +      if !user.info.hide_followers_count or !user.info.hide_followers or opts[:for] == user do +        user_info.follower_count +      else +        0 +      end      bot = (user.info.source_data["type"] || "Person") in ["Application", "Service"] @@ -138,6 +146,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do        pleroma: %{          confirmation_pending: user_info.confirmation_pending,          tags: user.tags, +        hide_followers_count: user.info.hide_followers_count, +        hide_follows_count: user.info.hide_follows_count,          hide_followers: user.info.hide_followers,          hide_follows: user.info.hide_follows,          hide_favorites: user.info.hide_favorites, diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index fb7fd9e79..2b4a04afd 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -105,10 +105,20 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do        other_user = insert(:user)        {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)        assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user}) -      info = Map.put(user.info, :hide_followers, true) +      info = Map.merge(user.info, %{hide_followers_count: true, hide_followers: true})        user = Map.put(user, :info, info)        assert %{"totalItems" => 0} = UserView.render("followers.json", %{user: user})      end + +    test "sets correct totalItems when followers are hidden but the follower counter is not" do +      user = insert(:user) +      other_user = insert(:user) +      {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) +      assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user}) +      info = Map.merge(user.info, %{hide_followers_count: false, hide_followers: true}) +      user = Map.put(user, :info, info) +      assert %{"totalItems" => 1} = UserView.render("followers.json", %{user: user}) +    end    end    describe "following" do @@ -117,9 +127,19 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do        other_user = insert(:user)        {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user)        assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) -      info = Map.put(user.info, :hide_follows, true) +      info = Map.merge(user.info, %{hide_follows_count: true, hide_follows: true})        user = Map.put(user, :info, info)        assert %{"totalItems" => 0} = UserView.render("following.json", %{user: user})      end + +    test "sets correct totalItems when follows are hidden but the follow counter is not" do +      user = insert(:user) +      other_user = insert(:user) +      {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user) +      assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) +      info = Map.merge(user.info, %{hide_follows_count: false, hide_follows: true}) +      user = Map.put(user, :info, info) +      assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user}) +    end    end  end diff --git a/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs b/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs index 87ee82050..89d4ca37e 100644 --- a/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs +++ b/test/web/mastodon_api/controllers/mastodon_api_controller/update_credentials_test.exs @@ -128,6 +128,22 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do        assert user["pleroma"]["hide_followers"] == true      end +    test "updates the user's hide_followers_count and hide_follows_count", %{conn: conn} do +      user = insert(:user) + +      conn = +        conn +        |> assign(:user, user) +        |> patch("/api/v1/accounts/update_credentials", %{ +          hide_followers_count: "true", +          hide_follows_count: "true" +        }) + +      assert user = json_response(conn, 200) +      assert user["pleroma"]["hide_followers_count"] == true +      assert user["pleroma"]["hide_follows_count"] == true +    end +      test "updates the user's skip_thread_containment option", %{conn: conn} do        user = insert(:user) diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs index 1d8b28339..8ff6751d3 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -79,6 +79,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do          hide_favorites: true,          hide_followers: false,          hide_follows: false, +        hide_followers_count: false, +        hide_follows_count: false,          relationship: %{},          skip_thread_containment: false        } @@ -147,6 +149,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do          hide_favorites: true,          hide_followers: false,          hide_follows: false, +        hide_followers_count: false, +        hide_follows_count: false,          relationship: %{},          skip_thread_containment: false        } @@ -318,6 +322,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do          hide_favorites: true,          hide_followers: false,          hide_follows: false, +        hide_followers_count: false, +        hide_follows_count: false,          relationship: %{            id: to_string(user.id),            following: false, @@ -361,8 +367,16 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do    end    describe "hiding follows/following" do -    test "shows when follows/following are hidden and sets follower/following count to 0" do -      user = insert(:user, info: %{hide_followers: true, hide_follows: true}) +    test "shows when follows/followers stats are hidden and sets follow/follower count to 0" do +      info = %{ +        hide_followers: true, +        hide_followers_count: true, +        hide_follows: true, +        hide_follows_count: true +      } + +      user = insert(:user, info: info) +        other_user = insert(:user)        {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user)        {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) @@ -370,6 +384,19 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do        assert %{                 followers_count: 0,                 following_count: 0, +               pleroma: %{hide_follows_count: true, hide_followers_count: true} +             } = AccountView.render("account.json", %{user: user}) +    end + +    test "shows when follows/followers are hidden" do +      user = insert(:user, info: %{hide_followers: true, hide_follows: true}) +      other_user = insert(:user) +      {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) +      {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) + +      assert %{ +               followers_count: 1, +               following_count: 1,                 pleroma: %{hide_follows: true, hide_followers: true}               } = AccountView.render("account.json", %{user: user})      end  | 
