Add spec for AccountController.statuses
authorEgor Kislitsyn <egor@kislitsyn.com>
Wed, 8 Apr 2020 18:33:25 +0000 (22:33 +0400)
committerEgor Kislitsyn <egor@kislitsyn.com>
Mon, 13 Apr 2020 14:17:07 +0000 (18:17 +0400)
14 files changed:
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/api_spec.ex
lib/pleroma/web/api_spec/operations/account_operation.ex
lib/pleroma/web/api_spec/schemas/account_update_credentials_request.ex
lib/pleroma/web/api_spec/schemas/boolean_like.ex [new file with mode: 0644]
lib/pleroma/web/api_spec/schemas/poll.ex [new file with mode: 0644]
lib/pleroma/web/api_spec/schemas/status.ex [new file with mode: 0644]
lib/pleroma/web/api_spec/schemas/statuses_response.ex [new file with mode: 0644]
lib/pleroma/web/mastodon_api/controllers/account_controller.ex
lib/pleroma/web/mastodon_api/views/status_view.ex
mix.exs
mix.lock
test/web/api_spec/account_operation_test.exs
test/web/mastodon_api/controllers/account_controller_test.exs

index 86b105b7fe8610f3ac1f0257be4fc5c845768080..1909ce097a06496e44acafa8c7ee2ff4c6e2283f 100644 (file)
@@ -853,7 +853,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
   end
 
   defp exclude_visibility(query, %{"exclude_visibilities" => visibility})
-       when visibility not in @valid_visibilities do
+       when visibility not in [nil | @valid_visibilities] do
     Logger.error("Could not exclude visibility to #{visibility}")
     query
   end
@@ -1060,7 +1060,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     raise "Can't use the child object without preloading!"
   end
 
-  defp restrict_media(query, %{"only_media" => val}) when val == "true" or val == "1" do
+  defp restrict_media(query, %{"only_media" => val}) when val in [true, "true", "1"] do
     from(
       [_activity, object] in query,
       where: fragment("not (?)->'attachment' = (?)", object.data, ^[])
@@ -1069,7 +1069,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
 
   defp restrict_media(query, _), do: query
 
-  defp restrict_replies(query, %{"exclude_replies" => val}) when val == "true" or val == "1" do
+  defp restrict_replies(query, %{"exclude_replies" => val}) when val in [true, "true", "1"] do
     from(
       [_activity, object] in query,
       where: fragment("?->>'inReplyTo' is null", object.data)
@@ -1078,7 +1078,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
 
   defp restrict_replies(query, _), do: query
 
-  defp restrict_reblogs(query, %{"exclude_reblogs" => val}) when val == "true" or val == "1" do
+  defp restrict_reblogs(query, %{"exclude_reblogs" => val}) when val in [true, "true", "1"] do
     from(activity in query, where: fragment("?->>'type' != 'Announce'", activity.data))
   end
 
@@ -1157,7 +1157,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     )
   end
 
-  defp restrict_pinned(query, %{"pinned" => "true", "pinned_activity_ids" => ids}) do
+  defp restrict_pinned(query, %{"pinned" => pinned, "pinned_activity_ids" => ids})
+       when pinned in [true, "true", "1"] do
     from(activity in query, where: activity.id in ^ids)
   end
 
index c85fe30d1888cac4bb2983b846fd90646f7fb1d2..d11e776d08bd3d2c84fff5f4ea5ec9566dfb0658 100644 (file)
@@ -4,6 +4,7 @@
 
 defmodule Pleroma.Web.ApiSpec do
   alias OpenApiSpex.OpenApi
+  alias OpenApiSpex.Operation
   alias Pleroma.Web.Endpoint
   alias Pleroma.Web.Router
 
@@ -24,6 +25,13 @@ defmodule Pleroma.Web.ApiSpec do
       # populate the paths from a phoenix router
       paths: OpenApiSpex.Paths.from_router(Router),
       components: %OpenApiSpex.Components{
+        parameters: %{
+          "accountIdOrNickname" =>
+            Operation.parameter(:id, :path, :string, "Account ID or nickname",
+              example: "123",
+              required: true
+            )
+        },
         securitySchemes: %{
           "oAuth" => %OpenApiSpex.SecurityScheme{
             type: "oauth2",
index 5b1b2eb4c5e37cd05a96e6e0967712ff4521a08e..09e6d24eda1175372f54538f8b50e30c491940c4 100644 (file)
@@ -4,6 +4,7 @@
 
 defmodule Pleroma.Web.ApiSpec.AccountOperation do
   alias OpenApiSpex.Operation
+  alias OpenApiSpex.Reference
   alias OpenApiSpex.Schema
   alias Pleroma.Web.ApiSpec.Helpers
   alias Pleroma.Web.ApiSpec.Schemas.Account
@@ -11,6 +12,9 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
   alias Pleroma.Web.ApiSpec.Schemas.AccountCreateResponse
   alias Pleroma.Web.ApiSpec.Schemas.AccountRelationshipsResponse
   alias Pleroma.Web.ApiSpec.Schemas.AccountUpdateCredentialsRequest
+  alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
+  alias Pleroma.Web.ApiSpec.Schemas.StatusesResponse
+  alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
 
   @spec open_api_operation(atom) :: Operation.t()
   def open_api_operation(action) do
@@ -91,12 +95,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
       summary: "Account",
       operationId: "AccountController.show",
       description: "View information about a profile.",
-      parameters: [
-        Operation.parameter(:id, :path, :string, "Account ID or nickname",
-          example: "123",
-          required: true
-        )
-      ],
+      parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
       responses: %{
         200 => Operation.response("Account", "application/json", Account)
       }
@@ -104,7 +103,39 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
   end
 
   def statuses_operation do
-    :ok
+    %Operation{
+      tags: ["accounts"],
+      summary: "Statuses",
+      operationId: "AccountController.statuses",
+      description:
+        "Statuses posted to the given account. Public (for public statuses only), or user token + `read:statuses` (for private statuses the user is authorized to see)",
+      parameters: [
+        %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
+        Operation.parameter(:pinned, :query, BooleanLike, "Pinned"),
+        Operation.parameter(:tagged, :query, :string, "With tag"),
+        Operation.parameter(:only_media, :query, BooleanLike, "Only meadia"),
+        Operation.parameter(:with_muted, :query, BooleanLike, "With muted"),
+        Operation.parameter(:exclude_reblogs, :query, BooleanLike, "Exclude reblobs"),
+        Operation.parameter(
+          :exclude_visibilities,
+          :query,
+          %Schema{type: :array, items: VisibilityScope},
+          "Exclude visibilities"
+        ),
+        Operation.parameter(:max_id, :query, :string, "Max ID"),
+        Operation.parameter(:min_id, :query, :string, "Mix ID"),
+        Operation.parameter(:since_id, :query, :string, "Since ID"),
+        Operation.parameter(
+          :limit,
+          :query,
+          %Schema{type: :integer, default: 20, maximum: 40},
+          "Limit"
+        )
+      ],
+      responses: %{
+        200 => Operation.response("Statuses", "application/json", StatusesResponse)
+      }
+    }
   end
 
   def followers_operation do
index 6ab48193edf577828b81823ef4f9761d4a977882..35220c78a3d7450ab597f6efb30545c81f150139 100644 (file)
@@ -38,7 +38,10 @@ defmodule Pleroma.Web.ApiSpec.Schemas.AccountUpdateCredentialsRequest do
         description: "Whether manual approval of follow requests is required."
       },
       fields_attributes: %Schema{
-        oneOf: [%Schema{type: :array, items: AccountAttributeField}, %Schema{type: :object}]
+        oneOf: [
+          %Schema{type: :array, items: AccountAttributeField},
+          %Schema{type: :object, additionalProperties: %Schema{type: AccountAttributeField}}
+        ]
       },
       # NOTE: `source` field is not supported
       #
diff --git a/lib/pleroma/web/api_spec/schemas/boolean_like.ex b/lib/pleroma/web/api_spec/schemas/boolean_like.ex
new file mode 100644 (file)
index 0000000..f3bfb74
--- /dev/null
@@ -0,0 +1,36 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Schemas.BooleanLike do
+  alias OpenApiSpex.Schema
+
+  require OpenApiSpex
+
+  OpenApiSpex.schema(%{
+    title: "BooleanLike",
+    description: """
+    The following values will be treated as `false`:
+      - false
+      - 0
+      - "0",
+      - "f",
+      - "F",
+      - "false",
+      - "FALSE",
+      - "off",
+      - "OFF"
+
+    All other non-null values will be treated as `true`
+    """,
+    anyOf: [
+      %Schema{type: :boolean},
+      %Schema{type: :string},
+      %Schema{type: :integer}
+    ]
+  })
+
+  def after_cast(value, _schmea) do
+    {:ok, Pleroma.Web.ControllerHelper.truthy_param?(value)}
+  end
+end
diff --git a/lib/pleroma/web/api_spec/schemas/poll.ex b/lib/pleroma/web/api_spec/schemas/poll.ex
new file mode 100644 (file)
index 0000000..2a9975f
--- /dev/null
@@ -0,0 +1,35 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Schemas.Poll do
+  alias OpenApiSpex.Schema
+  alias Pleroma.Web.ApiSpec.Schemas.AccountEmoji
+
+  require OpenApiSpex
+
+  OpenApiSpex.schema(%{
+    title: "Poll",
+    description: "Response schema for account custom fields",
+    type: :object,
+    properties: %{
+      id: %Schema{type: :string},
+      expires_at: %Schema{type: :string, format: "date-time"},
+      expired: %Schema{type: :boolean},
+      multiple: %Schema{type: :boolean},
+      votes_count: %Schema{type: :integer},
+      voted: %Schema{type: :boolean},
+      emojis: %Schema{type: :array, items: AccountEmoji},
+      options: %Schema{
+        type: :array,
+        items: %Schema{
+          type: :object,
+          properties: %{
+            title: %Schema{type: :string},
+            votes_count: %Schema{type: :integer}
+          }
+        }
+      }
+    }
+  })
+end
diff --git a/lib/pleroma/web/api_spec/schemas/status.ex b/lib/pleroma/web/api_spec/schemas/status.ex
new file mode 100644 (file)
index 0000000..486c3a0
--- /dev/null
@@ -0,0 +1,227 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Schemas.Status do
+  alias OpenApiSpex.Schema
+  alias Pleroma.Web.ApiSpec.Schemas.Account
+  alias Pleroma.Web.ApiSpec.Schemas.AccountEmoji
+  alias Pleroma.Web.ApiSpec.Schemas.Poll
+  alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
+
+  require OpenApiSpex
+
+  OpenApiSpex.schema(%{
+    title: "Status",
+    description: "Response schema for a status",
+    type: :object,
+    properties: %{
+      account: Account,
+      application: %Schema{
+        type: :object,
+        properties: %{
+          name: %Schema{type: :string},
+          website: %Schema{type: :string, nullable: true}
+        }
+      },
+      bookmarked: %Schema{type: :boolean},
+      card: %Schema{
+        type: :object,
+        nullable: true,
+        properties: %{
+          type: %Schema{type: :string},
+          provider_name: %Schema{type: :string},
+          provider_url: %Schema{type: :string},
+          url: %Schema{type: :string},
+          image: %Schema{type: :string},
+          title: %Schema{type: :string},
+          description: %Schema{type: :string}
+        }
+      },
+      content: %Schema{type: :string},
+      created_at: %Schema{type: :string, format: "date-time"},
+      emojis: %Schema{type: :array, items: AccountEmoji},
+      favourited: %Schema{type: :boolean},
+      favourites_count: %Schema{type: :integer},
+      id: %Schema{type: :string},
+      in_reply_to_account_id: %Schema{type: :string, nullable: true},
+      in_reply_to_id: %Schema{type: :string, nullable: true},
+      language: %Schema{type: :string, nullable: true},
+      media_attachments: %Schema{
+        type: :array,
+        items: %Schema{
+          type: :object,
+          properties: %{
+            id: %Schema{type: :string},
+            url: %Schema{type: :string},
+            remote_url: %Schema{type: :string},
+            preview_url: %Schema{type: :string},
+            text_url: %Schema{type: :string},
+            description: %Schema{type: :string},
+            type: %Schema{type: :string, enum: ["image", "video", "audio", "unknown"]},
+            pleroma: %Schema{
+              type: :object,
+              properties: %{mime_type: %Schema{type: :string}}
+            }
+          }
+        }
+      },
+      mentions: %Schema{
+        type: :array,
+        items: %Schema{
+          type: :object,
+          properties: %{
+            id: %Schema{type: :string},
+            acct: %Schema{type: :string},
+            username: %Schema{type: :string},
+            url: %Schema{type: :string}
+          }
+        }
+      },
+      muted: %Schema{type: :boolean},
+      pinned: %Schema{type: :boolean},
+      pleroma: %Schema{
+        type: :object,
+        properties: %{
+          content: %Schema{type: :object, additionalProperties: %Schema{type: :string}},
+          conversation_id: %Schema{type: :integer},
+          direct_conversation_id: %Schema{type: :string, nullable: true},
+          emoji_reactions: %Schema{
+            type: :array,
+            items: %Schema{
+              type: :object,
+              properties: %{
+                name: %Schema{type: :string},
+                count: %Schema{type: :integer},
+                me: %Schema{type: :boolean}
+              }
+            }
+          },
+          expires_at: %Schema{type: :string, format: "date-time", nullable: true},
+          in_reply_to_account_acct: %Schema{type: :string, nullable: true},
+          local: %Schema{type: :boolean},
+          spoiler_text: %Schema{type: :object, additionalProperties: %Schema{type: :string}},
+          thread_muted: %Schema{type: :boolean}
+        }
+      },
+      poll: %Schema{type: Poll, nullable: true},
+      reblog: %Schema{
+        allOf: [%OpenApiSpex.Reference{"$ref": "#/components/schemas/Status"}],
+        nullable: true
+      },
+      reblogged: %Schema{type: :boolean},
+      reblogs_count: %Schema{type: :integer},
+      replies_count: %Schema{type: :integer},
+      sensitive: %Schema{type: :boolean},
+      spoiler_text: %Schema{type: :string},
+      tags: %Schema{
+        type: :array,
+        items: %Schema{
+          type: :object,
+          properties: %{
+            name: %Schema{type: :string},
+            url: %Schema{type: :string}
+          }
+        }
+      },
+      uri: %Schema{type: :string},
+      url: %Schema{type: :string},
+      visibility: VisibilityScope
+    },
+    example: %{
+      "JSON" => %{
+        "account" => %{
+          "acct" => "nick6",
+          "avatar" => "http://localhost:4001/images/avi.png",
+          "avatar_static" => "http://localhost:4001/images/avi.png",
+          "bot" => false,
+          "created_at" => "2020-04-07T19:48:51.000Z",
+          "display_name" => "Test テスト User 6",
+          "emojis" => [],
+          "fields" => [],
+          "followers_count" => 1,
+          "following_count" => 0,
+          "header" => "http://localhost:4001/images/banner.png",
+          "header_static" => "http://localhost:4001/images/banner.png",
+          "id" => "9toJCsKN7SmSf3aj5c",
+          "locked" => false,
+          "note" => "Tester Number 6",
+          "pleroma" => %{
+            "background_image" => nil,
+            "confirmation_pending" => false,
+            "hide_favorites" => true,
+            "hide_followers" => false,
+            "hide_followers_count" => false,
+            "hide_follows" => false,
+            "hide_follows_count" => false,
+            "is_admin" => false,
+            "is_moderator" => false,
+            "relationship" => %{
+              "blocked_by" => false,
+              "blocking" => false,
+              "domain_blocking" => false,
+              "endorsed" => false,
+              "followed_by" => false,
+              "following" => true,
+              "id" => "9toJCsKN7SmSf3aj5c",
+              "muting" => false,
+              "muting_notifications" => false,
+              "requested" => false,
+              "showing_reblogs" => true,
+              "subscribing" => false
+            },
+            "skip_thread_containment" => false,
+            "tags" => []
+          },
+          "source" => %{
+            "fields" => [],
+            "note" => "Tester Number 6",
+            "pleroma" => %{"actor_type" => "Person", "discoverable" => false},
+            "sensitive" => false
+          },
+          "statuses_count" => 1,
+          "url" => "http://localhost:4001/users/nick6",
+          "username" => "nick6"
+        },
+        "application" => %{"name" => "Web", "website" => nil},
+        "bookmarked" => false,
+        "card" => nil,
+        "content" => "foobar",
+        "created_at" => "2020-04-07T19:48:51.000Z",
+        "emojis" => [],
+        "favourited" => false,
+        "favourites_count" => 0,
+        "id" => "9toJCu5YZW7O7gfvH6",
+        "in_reply_to_account_id" => nil,
+        "in_reply_to_id" => nil,
+        "language" => nil,
+        "media_attachments" => [],
+        "mentions" => [],
+        "muted" => false,
+        "pinned" => false,
+        "pleroma" => %{
+          "content" => %{"text/plain" => "foobar"},
+          "conversation_id" => 345_972,
+          "direct_conversation_id" => nil,
+          "emoji_reactions" => [],
+          "expires_at" => nil,
+          "in_reply_to_account_acct" => nil,
+          "local" => true,
+          "spoiler_text" => %{"text/plain" => ""},
+          "thread_muted" => false
+        },
+        "poll" => nil,
+        "reblog" => nil,
+        "reblogged" => false,
+        "reblogs_count" => 0,
+        "replies_count" => 0,
+        "sensitive" => false,
+        "spoiler_text" => "",
+        "tags" => [],
+        "uri" => "http://localhost:4001/objects/0f5dad44-0e9e-4610-b377-a2631e499190",
+        "url" => "http://localhost:4001/notice/9toJCu5YZW7O7gfvH6",
+        "visibility" => "private"
+      }
+    }
+  })
+end
diff --git a/lib/pleroma/web/api_spec/schemas/statuses_response.ex b/lib/pleroma/web/api_spec/schemas/statuses_response.ex
new file mode 100644 (file)
index 0000000..fb7c7e0
--- /dev/null
@@ -0,0 +1,13 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Schemas.StatusesResponse do
+  require OpenApiSpex
+
+  OpenApiSpex.schema(%{
+    title: "StatusesResponse",
+    type: :array,
+    items: Pleroma.Web.ApiSpec.Schemas.Status
+  })
+end
index 67375f31c8a0e7c0577d651cdbeee3c7f11567e9..208df569884b4e6d9997b7de5b26ca6a88356212 100644 (file)
@@ -83,7 +83,14 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
   plug(
     OpenApiSpex.Plug.CastAndValidate,
     [render_error: Pleroma.Web.ApiSpec.RenderError]
-    when action in [:create, :verify_credentials, :update_credentials, :relationships, :show]
+    when action in [
+           :create,
+           :verify_credentials,
+           :update_credentials,
+           :relationships,
+           :show,
+           :statuses
+         ]
   )
 
   action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
@@ -250,12 +257,14 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
 
   @doc "GET /api/v1/accounts/:id/statuses"
   def statuses(%{assigns: %{user: reading_user}} = conn, params) do
-    with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user),
+    with %User{} = user <- User.get_cached_by_nickname_or_id(params.id, for: reading_user),
          true <- User.visible_for?(user, reading_user) do
       params =
         params
-        |> Map.put("tag", params["tagged"])
-        |> Map.delete("godmode")
+        |> Map.delete(:tagged)
+        |> Enum.filter(&(not is_nil(&1)))
+        |> Map.new(fn {key, value} -> {to_string(key), value} end)
+        |> Map.put("tag", params[:tagged])
 
       activities = ActivityPub.fetch_user_activities(user, reading_user, params)
 
index b5850e1ae8aa1a9a1320faf22e876c4cc63001b5..ba40fd63ee646b1a0eafd03bebfa8fab6ee676ce 100644 (file)
@@ -521,11 +521,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
   """
   @spec build_tags(list(any())) :: list(map())
   def build_tags(object_tags) when is_list(object_tags) do
-    object_tags = for tag when is_binary(tag) <- object_tags, do: tag
-
-    Enum.reduce(object_tags, [], fn tag, tags ->
-      tags ++ [%{name: tag, url: "/tag/#{URI.encode(tag)}"}]
-    end)
+    object_tags
+    |> Enum.filter(&is_binary/1)
+    |> Enum.map(&%{name: &1, url: "/tag/#{URI.encode(&1)}"})
   end
 
   def build_tags(_), do: []
diff --git a/mix.exs b/mix.exs
index c781995e0dc271f41ed153d43fd2efa07b039ac7..ec69d70c037cb4a56dccd66aa7ab3b2c4328a717 100644 (file)
--- a/mix.exs
+++ b/mix.exs
@@ -189,7 +189,9 @@ defmodule Pleroma.Mixfile do
        ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"},
       {:mox, "~> 0.5", only: :test},
       {:restarter, path: "./restarter"},
-      {:open_api_spex, "~> 3.6"}
+      {:open_api_spex,
+       git: "https://git.pleroma.social/pleroma/elixir-libraries/open_api_spex.git",
+       ref: "b862ebd78de0df95875cf46feb6e9607130dc2a8"}
     ] ++ oauth_deps()
   end
 
index ba4e3ac4422923362e7ece777c9a570ff185380d..779be4f874b99f30c77d2a26201a31c75dd68bc0 100644 (file)
--- a/mix.lock
+++ b/mix.lock
@@ -74,7 +74,7 @@
   "nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"},
   "nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
   "oban": {:hex, :oban, "1.2.0", "7cca94d341be43d220571e28f69131c4afc21095b25257397f50973d3fc59b07", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ba5f8b3f7d76967b3e23cf8014f6a13e4ccb33431e4808f036709a7f822362ee"},
-  "open_api_spex": {:hex, :open_api_spex, "3.6.0", "64205aba9f2607f71b08fd43e3351b9c5e9898ec5ef49fc0ae35890da502ade9", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.1", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm", "126ba3473966277132079cb1d5bf1e3df9e36fe2acd00166e75fd125cecb59c5"},
+  "open_api_spex": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/open_api_spex.git", "b862ebd78de0df95875cf46feb6e9607130dc2a8", [ref: "b862ebd78de0df95875cf46feb6e9607130dc2a8"]},
   "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
   "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.4", "8dd29ed783f2e12195d7e0a4640effc0a7c37e6537da491f1db01839eee6d053", [:mix], [], "hexpm", "595d09db74cb093b1903381c9de423276a931a2480a46a1a5dc7f932a2a6375b"},
   "phoenix": {:hex, :phoenix, "1.4.13", "67271ad69b51f3719354604f4a3f968f83aa61c19199343656c9caee057ff3b8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ab765a0feddb81fc62e2116c827b5f068df85159c162bee760745276ad7ddc1b"},
@@ -82,7 +82,7 @@
   "phoenix_html": {:hex, :phoenix_html, "2.14.0", "d8c6bc28acc8e65f8ea0080ee05aa13d912c8758699283b8d3427b655aabe284", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "b0bb30eda478a06dbfbe96728061a93833db3861a49ccb516f839ecb08493fbb"},
   "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm", "1f13f9f0f3e769a667a6b6828d29dec37497a082d195cc52dbef401a9b69bf38"},
   "phoenix_swoosh": {:hex, :phoenix_swoosh, "0.2.0", "a7e0b32077cd6d2323ae15198839b05d9caddfa20663fd85787479e81f89520e", [:mix], [{:phoenix, "~> 1.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.2", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 0.1", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "ebf1bfa7b3c1c850c04929afe02e2e0d7ab135e0706332c865de03e761676b1f"},
-  "plug": {:hex, :plug, "1.9.0", "8d7c4e26962283ff9f8f3347bd73838e2413fbc38b7bb5467d5924f68f3a5a4a", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "9902eda2c52ada2a096434682e99a2493f5d06a94d6ac6bcfff9805f952350f1"},
+  "plug": {:hex, :plug, "1.10.0", "6508295cbeb4c654860845fb95260737e4a8838d34d115ad76cd487584e2fc4d", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "422a9727e667be1bf5ab1de03be6fa0ad67b775b2d84ed908f3264415ef29d4a"},
   "plug_cowboy": {:hex, :plug_cowboy, "2.1.2", "8b0addb5908c5238fac38e442e81b6fcd32788eaa03246b4d55d147c47c5805e", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "7d722581ce865a237e14da6d946f92704101740a256bd13ec91e63c0b122fc70"},
   "plug_crypto": {:hex, :plug_crypto, "1.1.2", "bdd187572cc26dbd95b87136290425f2b580a116d3fb1f564216918c9730d227", [:mix], [], "hexpm", "6b8b608f895b6ffcfad49c37c7883e8df98ae19c6a28113b02aa1e9c5b22d6b5"},
   "plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"},
index 6cc08ee0e988229e66e0dafc4db37a82f52f7aef..892ade71c4005f4a908c0ce17c1f086c1a76065c 100644 (file)
@@ -122,4 +122,20 @@ defmodule Pleroma.Web.ApiSpec.AccountOperationTest do
 
     assert_schema(resp, "Account", api_spec)
   end
+
+  test "/api/v1/accounts/:id/statuses produces StatusesResponse", %{
+    conn: conn
+  } do
+    user = insert(:user)
+    Pleroma.Web.CommonAPI.post(user, %{"status" => "foobar"})
+
+    api_spec = ApiSpec.spec()
+
+    assert resp =
+             conn
+             |> get("/api/v1/accounts/#{user.id}/statuses")
+             |> json_response(:ok)
+
+    assert_schema(resp, "StatusesResponse", api_spec)
+  end
 end
index 060a7c1cd26522aa22b31637995e77196a1902ca..969256fa42d44d455ac7252a7cf2e42712cb5c47 100644 (file)
@@ -10,9 +10,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.ActivityPub.InternalFetchActor
+  alias Pleroma.Web.ApiSpec
   alias Pleroma.Web.CommonAPI
   alias Pleroma.Web.OAuth.Token
 
+  import OpenApiSpex.TestAssertions
   import Pleroma.Factory
 
   describe "account fetching" do
@@ -245,22 +247,23 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
       {:ok, activity} = CommonAPI.post(user_two, %{"status" => "User one sux0rz"})
       {:ok, repeat, _} = CommonAPI.repeat(activity.id, user_three)
 
-      resp = get(conn, "/api/v1/accounts/#{user_two.id}/statuses")
-
-      assert [%{"id" => id}] = json_response(resp, 200)
+      assert resp = get(conn, "/api/v1/accounts/#{user_two.id}/statuses") |> json_response(200)
+      assert [%{"id" => id}] = resp
+      assert_schema(resp, "StatusesResponse", ApiSpec.spec())
       assert id == activity.id
 
       # Even a blocked user will deliver the full user timeline, there would be
       #   no point in looking at a blocked users timeline otherwise
-      resp = get(conn, "/api/v1/accounts/#{user_two.id}/statuses")
-
-      assert [%{"id" => id}] = json_response(resp, 200)
+      assert resp = get(conn, "/api/v1/accounts/#{user_two.id}/statuses") |> json_response(200)
+      assert [%{"id" => id}] = resp
       assert id == activity.id
+      assert_schema(resp, "StatusesResponse", ApiSpec.spec())
 
       # Third user's timeline includes the repeat when viewed by unauthenticated user
-      resp = get(build_conn(), "/api/v1/accounts/#{user_three.id}/statuses")
-      assert [%{"id" => id}] = json_response(resp, 200)
+      resp = get(build_conn(), "/api/v1/accounts/#{user_three.id}/statuses") |> json_response(200)
+      assert [%{"id" => id}] = resp
       assert id == repeat.id
+      assert_schema(resp, "StatusesResponse", ApiSpec.spec())
 
       # When viewing a third user's timeline, the blocked users' statuses will NOT be shown
       resp = get(conn, "/api/v1/accounts/#{user_three.id}/statuses")
@@ -286,30 +289,34 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
       {:ok, private_activity} =
         CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
 
-      resp = get(conn, "/api/v1/accounts/#{user_one.id}/statuses")
-
-      assert [%{"id" => id}] = json_response(resp, 200)
+      resp = get(conn, "/api/v1/accounts/#{user_one.id}/statuses") |> json_response(200)
+      assert [%{"id" => id}] = resp
       assert id == to_string(activity.id)
+      assert_schema(resp, "StatusesResponse", ApiSpec.spec())
 
       resp =
         conn
         |> assign(:user, user_two)
         |> assign(:token, insert(:oauth_token, user: user_two, scopes: ["read:statuses"]))
         |> get("/api/v1/accounts/#{user_one.id}/statuses")
+        |> json_response(200)
 
-      assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
+      assert [%{"id" => id_one}, %{"id" => id_two}] = resp
       assert id_one == to_string(direct_activity.id)
       assert id_two == to_string(activity.id)
+      assert_schema(resp, "StatusesResponse", ApiSpec.spec())
 
       resp =
         conn
         |> assign(:user, user_three)
         |> assign(:token, insert(:oauth_token, user: user_three, scopes: ["read:statuses"]))
         |> get("/api/v1/accounts/#{user_one.id}/statuses")
+        |> json_response(200)
 
-      assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
+      assert [%{"id" => id_one}, %{"id" => id_two}] = resp
       assert id_one == to_string(private_activity.id)
       assert id_two == to_string(activity.id)
+      assert_schema(resp, "StatusesResponse", ApiSpec.spec())
     end
 
     test "unimplemented pinned statuses feature", %{conn: conn} do
@@ -335,40 +342,45 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
 
       {:ok, image_post} = CommonAPI.post(user, %{"status" => "cofe", "media_ids" => [media_id]})
 
-      conn = get(conn, "/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
+      conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?only_media=true")
 
       assert [%{"id" => id}] = json_response(conn, 200)
       assert id == to_string(image_post.id)
+      assert_schema(json_response(conn, 200), "StatusesResponse", ApiSpec.spec())
 
-      conn = get(build_conn(), "/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
+      conn = get(build_conn(), "/api/v1/accounts/#{user.id}/statuses?only_media=1")
 
       assert [%{"id" => id}] = json_response(conn, 200)
       assert id == to_string(image_post.id)
+      assert_schema(json_response(conn, 200), "StatusesResponse", ApiSpec.spec())
     end
 
     test "gets a user's statuses without reblogs", %{user: user, conn: conn} do
       {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
       {:ok, _, _} = CommonAPI.repeat(post.id, user)
 
-      conn = get(conn, "/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
+      conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=true")
 
       assert [%{"id" => id}] = json_response(conn, 200)
       assert id == to_string(post.id)
+      assert_schema(json_response(conn, 200), "StatusesResponse", ApiSpec.spec())
 
-      conn = get(conn, "/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
+      conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=1")
 
       assert [%{"id" => id}] = json_response(conn, 200)
       assert id == to_string(post.id)
+      assert_schema(json_response(conn, 200), "StatusesResponse", ApiSpec.spec())
     end
 
     test "filters user's statuses by a hashtag", %{user: user, conn: conn} do
       {:ok, post} = CommonAPI.post(user, %{"status" => "#hashtag"})
       {:ok, _post} = CommonAPI.post(user, %{"status" => "hashtag"})
 
-      conn = get(conn, "/api/v1/accounts/#{user.id}/statuses", %{"tagged" => "hashtag"})
+      conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?tagged=hashtag")
 
       assert [%{"id" => id}] = json_response(conn, 200)
       assert id == to_string(post.id)
+      assert_schema(json_response(conn, 200), "StatusesResponse", ApiSpec.spec())
     end
 
     test "the user views their own timelines and excludes direct messages", %{
@@ -378,11 +390,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
       {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
       {:ok, _direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
 
-      conn =
-        get(conn, "/api/v1/accounts/#{user.id}/statuses", %{"exclude_visibilities" => ["direct"]})
+      conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_visibilities[]=direct")
 
       assert [%{"id" => id}] = json_response(conn, 200)
       assert id == to_string(public_activity.id)
+      assert_schema(json_response(conn, 200), "StatusesResponse", ApiSpec.spec())
     end
   end
 
@@ -420,9 +432,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
 
       res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
       assert length(json_response(res_conn, 200)) == 1
+      assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
 
       res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
       assert length(json_response(res_conn, 200)) == 1
+      assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
     end
   end
 
@@ -441,6 +455,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
 
       res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
       assert length(json_response(res_conn, 200)) == 1
+      assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
     end
 
     test "if user is authenticated", %{local: local, remote: remote} do
@@ -448,9 +463,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
 
       res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
       assert length(json_response(res_conn, 200)) == 1
+      assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
 
       res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
       assert length(json_response(res_conn, 200)) == 1
+      assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
     end
   end
 
@@ -463,6 +480,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
     test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
       res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
       assert length(json_response(res_conn, 200)) == 1
+      assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
 
       res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
 
@@ -476,9 +494,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
 
       res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
       assert length(json_response(res_conn, 200)) == 1
+      assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
 
       res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
       assert length(json_response(res_conn, 200)) == 1
+      assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
     end
   end