Merge branch 'develop' into 'fix/2411-mutes-api'
authorfeld <feld@feld.me>
Tue, 2 Feb 2021 17:57:58 +0000 (17:57 +0000)
committerfeld <feld@feld.me>
Tue, 2 Feb 2021 17:57:58 +0000 (17:57 +0000)
# Conflicts:
#   CHANGELOG.md
#   docs/development/API/differences_in_mastoapi_responses.md

1  2 
CHANGELOG.md
docs/development/API/differences_in_mastoapi_responses.md
lib/pleroma/web/api_spec/operations/account_operation.ex
test/pleroma/web/mastodon_api/controllers/account_controller_test.exs

diff --combined CHANGELOG.md
index b2b7e5671718ac9d3c492cd69220a3cd341f4d5d,f4f3bddb7400cb6216923b68292f35ef2da28a93..504ba2fb85eadbede9d4dd87ccbb6c2637facfef
@@@ -49,7 -49,8 +49,9 @@@ The format is based on [Keep a Changelo
  - Admin API: An endpoint to manage frontends.
  - Streaming API: Add follow relationships updates.
  - WebPush: Introduce `pleroma:chat_mention` and `pleroma:emoji_reaction` notification types.
+ - Mastodon API: Add monthly active users to `/api/v1/instance` (`pleroma.stats.mau`).
+ - Mastodon API: Home, public, hashtag & list timelines accept `only_media`, `remote` & `local` parameters for filtration.
 +- Mastodon API: `/api/v1/accounts/:id` & `/api/v1/mutes` endpoints accept `with_relationships` parameter and return filled `pleroma.relationship` field.
  </details>
  
  ### Fixed
@@@ -59,6 -60,7 +61,7 @@@
  - Creating incorrect IPv4 address-style HTTP links when encountering certain numbers.
  - Reblog API Endpoint: Do not set visibility parameter to public by default and let CommonAPI to infer it from status, so a user can reblog their private status without explicitly setting reblog visibility to private.
  - Tag URLs in statuses are now absolute
+ - Removed duplicate jobs to purge expired activities
  
  <details>
    <summary>API Changes</summary>
index b532d14eddb99347787e1b4bffec7abbffc44c9d,c83be2faac38659053e9aaf9160c48d5b844db09..38d70fa78e188757590423639a73f38165cf9478
@@@ -16,6 -16,12 +16,12 @@@ Adding the parameter `reply_visibility
  
  Adding the parameter `instance=lain.com` to the public timeline will show only statuses originating from `lain.com` (or any remote instance).
  
+ Home, public, hashtag & list timelines accept these parameters:
+ - `only_media`: show only statuses with media attached
+ - `local`: show only local statuses
+ - `remote`: show only remote statuses
  ## Statuses
  
  - `visibility`: has additional possible values `list` and `local` (for local-only statuses)
@@@ -54,13 -60,16 +60,23 @@@ The `id` parameter can also be the `nic
  - `/api/v1/accounts/:id`
  - `/api/v1/accounts/:id/statuses`
  
+ `/api/v1/accounts/:id/statuses` endpoint accepts these parameters:
+ - `pinned`: include only pinned statuses
+ - `tagged`: with tag
+ - `only_media`: include only statuses with media attached
+ - `with_muted`: include statuses/reactions from muted accounts
+ - `exclude_reblogs`: exclude reblogs
+ - `exclude_replies`: exclude replies
+ - `exclude_visibilities`: exclude visibilities
 +Endpoints which accept `with_relationships` parameter:
 +
 +- `/api/v1/accounts/:id`
 +- `/api/v1/accounts/:id/followers`
 +- `/api/v1/accounts/:id/following`
 +- `/api/v1/mutes`
 +
  Has these additional fields under the `pleroma` object:
  
  - `ap_id`: nullable URL string, ActivityPub id of the user
index d7e01f55b36e10ba30b6001aa51b78472e1ff841,a301ce090fa45c0cd55473e3c5f532710f4f514c..3d451cd5af5e23d5cc3b76912fc176f54d0ae8e8
@@@ -99,10 -99,7 +99,10 @@@ defmodule Pleroma.Web.ApiSpec.AccountOp
        summary: "Account",
        operationId: "AccountController.show",
        description: "View information about a profile.",
 -      parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
 +      parameters: [
 +        %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
 +        with_relationships_param()
 +      ],
        responses: %{
          200 => Operation.response("Account", "application/json", Account),
          401 => Operation.response("Error", "application/json", ApiError),
              :with_muted,
              :query,
              BooleanLike,
-             "Include statuses from muted acccounts."
+             "Include statuses from muted accounts."
            ),
            Operation.parameter(:exclude_reblogs, :query, BooleanLike, "Exclude reblogs"),
            Operation.parameter(:exclude_replies, :query, BooleanLike, "Exclude replies"),
              :with_muted,
              :query,
              BooleanLike,
-             "Include reactions from muted acccounts."
+             "Include reactions from muted accounts."
            )
          ] ++ pagination_params(),
        responses: %{
        operationId: "AccountController.mutes",
        description: "Accounts the user has muted.",
        security: [%{"oAuth" => ["follow", "read:mutes"]}],
 -      parameters: pagination_params(),
 +      parameters: [with_relationships_param() | pagination_params()],
        responses: %{
          200 => Operation.response("Accounts", "application/json", array_of_accounts())
        }
index e5020fecaefd06887a16d20fae221cb057fa97ac,b7a3edd4b2bf6222095642a103092edf2471c407..a327c0d1df62a04599ce4535ea1846d42dcfe1de
@@@ -29,45 -29,6 +29,45 @@@ defmodule Pleroma.Web.MastodonAPI.Accou
                 |> json_response_and_validate_schema(404)
      end
  
 +    test "relationship field" do
 +      %{conn: conn, user: user} = oauth_access(["read"])
 +
 +      other_user = insert(:user)
 +
 +      response =
 +        conn
 +        |> get("/api/v1/accounts/#{other_user.id}")
 +        |> json_response_and_validate_schema(200)
 +
 +      assert response["id"] == other_user.id
 +      assert response["pleroma"]["relationship"] == %{}
 +
 +      assert %{"pleroma" => %{"relationship" => %{"following" => false, "followed_by" => false}}} =
 +               conn
 +               |> get("/api/v1/accounts/#{other_user.id}?with_relationships=true")
 +               |> json_response_and_validate_schema(200)
 +
 +      {:ok, _, %{id: other_id}} = User.follow(user, other_user)
 +
 +      assert %{
 +               "id" => ^other_id,
 +               "pleroma" => %{"relationship" => %{"following" => true, "followed_by" => false}}
 +             } =
 +               conn
 +               |> get("/api/v1/accounts/#{other_id}?with_relationships=true")
 +               |> json_response_and_validate_schema(200)
 +
 +      {:ok, _, _} = User.follow(other_user, user)
 +
 +      assert %{
 +               "id" => ^other_id,
 +               "pleroma" => %{"relationship" => %{"following" => true, "followed_by" => true}}
 +             } =
 +               conn
 +               |> get("/api/v1/accounts/#{other_id}?with_relationships=true")
 +               |> json_response_and_validate_schema(200)
 +    end
 +
      test "works by nickname" do
        user = insert(:user)
  
        assert [%{"id" => ^user_id}] = json_response_and_validate_schema(conn, 200)
      end
  
 +    test "following with relationship", %{conn: conn, user: user} do
 +      other_user = insert(:user)
 +      {:ok, %{id: id}, _} = User.follow(other_user, user)
 +
 +      assert [
 +               %{
 +                 "id" => ^id,
 +                 "pleroma" => %{
 +                   "relationship" => %{
 +                     "id" => ^id,
 +                     "following" => false,
 +                     "followed_by" => true
 +                   }
 +                 }
 +               }
 +             ] =
 +               conn
 +               |> get("/api/v1/accounts/#{user.id}/followers?with_relationships=true")
 +               |> json_response_and_validate_schema(200)
 +
 +      {:ok, _, _} = User.follow(user, other_user)
 +
 +      assert [
 +               %{
 +                 "id" => ^id,
 +                 "pleroma" => %{
 +                   "relationship" => %{
 +                     "id" => ^id,
 +                     "following" => true,
 +                     "followed_by" => true
 +                   }
 +                 }
 +               }
 +             ] =
 +               conn
 +               |> get("/api/v1/accounts/#{user.id}/followers?with_relationships=true")
 +               |> json_response_and_validate_schema(200)
 +    end
 +
      test "getting followers, hide_followers", %{user: user, conn: conn} do
        other_user = insert(:user, hide_followers: true)
        {:ok, _user, _other_user} = User.follow(user, other_user)
        assert id == to_string(other_user.id)
      end
  
 +    test "following with relationship", %{conn: conn, user: user} do
 +      other_user = insert(:user)
 +      {:ok, user, other_user} = User.follow(user, other_user)
 +
 +      conn = get(conn, "/api/v1/accounts/#{user.id}/following?with_relationships=true")
 +
 +      id = other_user.id
 +
 +      assert [
 +               %{
 +                 "id" => ^id,
 +                 "pleroma" => %{
 +                   "relationship" => %{"id" => ^id, "following" => true, "followed_by" => false}
 +                 }
 +               }
 +             ] = json_response_and_validate_schema(conn, 200)
 +    end
 +
      test "getting following, hide_follows, other user requesting" do
        user = insert(:user, hide_follows: true)
        other_user = insert(:user)
        assert %{"error" => "{\"email\":[\"Invalid email\"]}"} =
                 json_response_and_validate_schema(conn, 400)
  
-       Pleroma.Config.put([User, :email_blacklist], [])
+       clear_config([User, :email_blacklist], [])
  
        conn =
          build_conn()
  
      result =
        conn
 -      |> assign(:user, user)
        |> get("/api/v1/mutes")
        |> json_response_and_validate_schema(200)
  
  
      result =
        conn
 -      |> assign(:user, user)
        |> get("/api/v1/mutes?limit=1")
        |> json_response_and_validate_schema(200)
  
  
      result =
        conn
 -      |> assign(:user, user)
        |> get("/api/v1/mutes?since_id=#{id1}")
        |> json_response_and_validate_schema(200)
  
  
      result =
        conn
 -      |> assign(:user, user)
        |> get("/api/v1/mutes?since_id=#{id1}&max_id=#{id3}")
        |> json_response_and_validate_schema(200)
  
  
      result =
        conn
 -      |> assign(:user, user)
        |> get("/api/v1/mutes?since_id=#{id1}&limit=1")
        |> json_response_and_validate_schema(200)
  
      assert [%{"id" => ^id2}] = result
    end
  
 +  test "list of mutes with with_relationships parameter" do
 +    %{user: user, conn: conn} = oauth_access(["read:mutes"])
 +    %{id: id1} = other_user1 = insert(:user)
 +    %{id: id2} = other_user2 = insert(:user)
 +    %{id: id3} = other_user3 = insert(:user)
 +
 +    {:ok, _, _} = User.follow(other_user1, user)
 +    {:ok, _, _} = User.follow(other_user2, user)
 +    {:ok, _, _} = User.follow(other_user3, user)
 +
 +    {:ok, _} = User.mute(user, other_user1)
 +    {:ok, _} = User.mute(user, other_user2)
 +    {:ok, _} = User.mute(user, other_user3)
 +
 +    assert [
 +             %{
 +               "id" => ^id1,
 +               "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
 +             },
 +             %{
 +               "id" => ^id2,
 +               "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
 +             },
 +             %{
 +               "id" => ^id3,
 +               "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
 +             }
 +           ] =
 +             conn
 +             |> get("/api/v1/mutes?with_relationships=true")
 +             |> json_response_and_validate_schema(200)
 +  end
 +
    test "getting a list of blocks" do
      %{user: user, conn: conn} = oauth_access(["read:blocks"])
      %{id: id1} = other_user1 = insert(:user)