Add spec for AccountController.statuses

This commit is contained in:
Egor Kislitsyn 2020-04-08 22:33:25 +04:00
parent 278b3fa0ad
commit 03124c96cc
No known key found for this signature in database
GPG Key ID: 1B49CB15B71E7805
14 changed files with 444 additions and 45 deletions

View File

@ -853,7 +853,7 @@ defp exclude_visibility(query, %{"exclude_visibilities" => visibility})
end end
defp exclude_visibility(query, %{"exclude_visibilities" => visibility}) 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}") Logger.error("Could not exclude visibility to #{visibility}")
query query
end end
@ -1060,7 +1060,7 @@ defp restrict_media(_query, %{"only_media" => _val, "skip_preload" => true}) do
raise "Can't use the child object without preloading!" raise "Can't use the child object without preloading!"
end 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( from(
[_activity, object] in query, [_activity, object] in query,
where: fragment("not (?)->'attachment' = (?)", object.data, ^[]) where: fragment("not (?)->'attachment' = (?)", object.data, ^[])
@ -1069,7 +1069,7 @@ defp restrict_media(query, %{"only_media" => val}) when val == "true" or val ==
defp restrict_media(query, _), do: query 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( from(
[_activity, object] in query, [_activity, object] in query,
where: fragment("?->>'inReplyTo' is null", object.data) where: fragment("?->>'inReplyTo' is null", object.data)
@ -1078,7 +1078,7 @@ defp restrict_replies(query, %{"exclude_replies" => val}) when val == "true" or
defp restrict_replies(query, _), do: query 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)) from(activity in query, where: fragment("?->>'type' != 'Announce'", activity.data))
end end
@ -1157,7 +1157,8 @@ defp restrict_unlisted(query) do
) )
end 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) from(activity in query, where: activity.id in ^ids)
end end

View File

@ -4,6 +4,7 @@
defmodule Pleroma.Web.ApiSpec do defmodule Pleroma.Web.ApiSpec do
alias OpenApiSpex.OpenApi alias OpenApiSpex.OpenApi
alias OpenApiSpex.Operation
alias Pleroma.Web.Endpoint alias Pleroma.Web.Endpoint
alias Pleroma.Web.Router alias Pleroma.Web.Router
@ -24,6 +25,13 @@ def spec do
# populate the paths from a phoenix router # populate the paths from a phoenix router
paths: OpenApiSpex.Paths.from_router(Router), paths: OpenApiSpex.Paths.from_router(Router),
components: %OpenApiSpex.Components{ components: %OpenApiSpex.Components{
parameters: %{
"accountIdOrNickname" =>
Operation.parameter(:id, :path, :string, "Account ID or nickname",
example: "123",
required: true
)
},
securitySchemes: %{ securitySchemes: %{
"oAuth" => %OpenApiSpex.SecurityScheme{ "oAuth" => %OpenApiSpex.SecurityScheme{
type: "oauth2", type: "oauth2",

View File

@ -4,6 +4,7 @@
defmodule Pleroma.Web.ApiSpec.AccountOperation do defmodule Pleroma.Web.ApiSpec.AccountOperation do
alias OpenApiSpex.Operation alias OpenApiSpex.Operation
alias OpenApiSpex.Reference
alias OpenApiSpex.Schema alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Helpers alias Pleroma.Web.ApiSpec.Helpers
alias Pleroma.Web.ApiSpec.Schemas.Account 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.AccountCreateResponse
alias Pleroma.Web.ApiSpec.Schemas.AccountRelationshipsResponse alias Pleroma.Web.ApiSpec.Schemas.AccountRelationshipsResponse
alias Pleroma.Web.ApiSpec.Schemas.AccountUpdateCredentialsRequest 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() @spec open_api_operation(atom) :: Operation.t()
def open_api_operation(action) do def open_api_operation(action) do
@ -91,12 +95,7 @@ def show_operation do
summary: "Account", summary: "Account",
operationId: "AccountController.show", operationId: "AccountController.show",
description: "View information about a profile.", description: "View information about a profile.",
parameters: [ parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
Operation.parameter(:id, :path, :string, "Account ID or nickname",
example: "123",
required: true
)
],
responses: %{ responses: %{
200 => Operation.response("Account", "application/json", Account) 200 => Operation.response("Account", "application/json", Account)
} }
@ -104,7 +103,39 @@ def show_operation do
end end
def statuses_operation do 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 end
def followers_operation do def followers_operation do

View File

@ -38,7 +38,10 @@ defmodule Pleroma.Web.ApiSpec.Schemas.AccountUpdateCredentialsRequest do
description: "Whether manual approval of follow requests is required." description: "Whether manual approval of follow requests is required."
}, },
fields_attributes: %Schema{ 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 # NOTE: `source` field is not supported
# #

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -83,7 +83,14 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
plug( plug(
OpenApiSpex.Plug.CastAndValidate, OpenApiSpex.Plug.CastAndValidate,
[render_error: Pleroma.Web.ApiSpec.RenderError] [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) action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
@ -250,12 +257,14 @@ def show(%{assigns: %{user: for_user}} = conn, %{id: nickname_or_id}) do
@doc "GET /api/v1/accounts/:id/statuses" @doc "GET /api/v1/accounts/:id/statuses"
def statuses(%{assigns: %{user: reading_user}} = conn, params) do 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 true <- User.visible_for?(user, reading_user) do
params = params =
params params
|> Map.put("tag", params["tagged"]) |> Map.delete(:tagged)
|> Map.delete("godmode") |> 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) activities = ActivityPub.fetch_user_activities(user, reading_user, params)

View File

@ -521,11 +521,9 @@ def render_content(object), do: object.data["content"] || ""
""" """
@spec build_tags(list(any())) :: list(map()) @spec build_tags(list(any())) :: list(map())
def build_tags(object_tags) when is_list(object_tags) do def build_tags(object_tags) when is_list(object_tags) do
object_tags = for tag when is_binary(tag) <- object_tags, do: tag object_tags
|> Enum.filter(&is_binary/1)
Enum.reduce(object_tags, [], fn tag, tags -> |> Enum.map(&%{name: &1, url: "/tag/#{URI.encode(&1)}"})
tags ++ [%{name: tag, url: "/tag/#{URI.encode(tag)}"}]
end)
end end
def build_tags(_), do: [] def build_tags(_), do: []

View File

@ -189,7 +189,9 @@ defp deps do
ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"}, ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"},
{:mox, "~> 0.5", only: :test}, {:mox, "~> 0.5", only: :test},
{:restarter, path: "./restarter"}, {: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() ] ++ oauth_deps()
end end

View File

@ -74,7 +74,7 @@
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"}, "nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"},
"nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]}, "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"}, "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"}, "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
"pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.4", "8dd29ed783f2e12195d7e0a4640effc0a7c37e6537da491f1db01839eee6d053", [:mix], [], "hexpm", "595d09db74cb093b1903381c9de423276a931a2480a46a1a5dc7f932a2a6375b"}, "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"}, "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_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_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"}, "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_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_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"}, "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"},

View File

@ -122,4 +122,20 @@ test "/api/v1/accounts/:id produces Account", %{
assert_schema(resp, "Account", api_spec) assert_schema(resp, "Account", api_spec)
end 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 end

View File

@ -10,9 +10,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.InternalFetchActor alias Pleroma.Web.ActivityPub.InternalFetchActor
alias Pleroma.Web.ApiSpec
alias Pleroma.Web.CommonAPI alias Pleroma.Web.CommonAPI
alias Pleroma.Web.OAuth.Token alias Pleroma.Web.OAuth.Token
import OpenApiSpex.TestAssertions
import Pleroma.Factory import Pleroma.Factory
describe "account fetching" do describe "account fetching" do
@ -245,22 +247,23 @@ test "respects blocks", %{user: user_one, conn: conn} do
{:ok, activity} = CommonAPI.post(user_two, %{"status" => "User one sux0rz"}) {:ok, activity} = CommonAPI.post(user_two, %{"status" => "User one sux0rz"})
{:ok, repeat, _} = CommonAPI.repeat(activity.id, user_three) {:ok, repeat, _} = CommonAPI.repeat(activity.id, user_three)
resp = get(conn, "/api/v1/accounts/#{user_two.id}/statuses") assert resp = get(conn, "/api/v1/accounts/#{user_two.id}/statuses") |> json_response(200)
assert [%{"id" => id}] = resp
assert [%{"id" => id}] = json_response(resp, 200) assert_schema(resp, "StatusesResponse", ApiSpec.spec())
assert id == activity.id assert id == activity.id
# Even a blocked user will deliver the full user timeline, there would be # Even a blocked user will deliver the full user timeline, there would be
# no point in looking at a blocked users timeline otherwise # no point in looking at a blocked users timeline otherwise
resp = get(conn, "/api/v1/accounts/#{user_two.id}/statuses") assert resp = get(conn, "/api/v1/accounts/#{user_two.id}/statuses") |> json_response(200)
assert [%{"id" => id}] = resp
assert [%{"id" => id}] = json_response(resp, 200)
assert id == activity.id assert id == activity.id
assert_schema(resp, "StatusesResponse", ApiSpec.spec())
# Third user's timeline includes the repeat when viewed by unauthenticated user # Third user's timeline includes the repeat when viewed by unauthenticated user
resp = get(build_conn(), "/api/v1/accounts/#{user_three.id}/statuses") resp = get(build_conn(), "/api/v1/accounts/#{user_three.id}/statuses") |> json_response(200)
assert [%{"id" => id}] = json_response(resp, 200) assert [%{"id" => id}] = resp
assert id == repeat.id 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 # 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") resp = get(conn, "/api/v1/accounts/#{user_three.id}/statuses")
@ -286,30 +289,34 @@ test "gets users statuses", %{conn: conn} do
{:ok, private_activity} = {:ok, private_activity} =
CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"}) CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
resp = get(conn, "/api/v1/accounts/#{user_one.id}/statuses") resp = get(conn, "/api/v1/accounts/#{user_one.id}/statuses") |> json_response(200)
assert [%{"id" => id}] = resp
assert [%{"id" => id}] = json_response(resp, 200)
assert id == to_string(activity.id) assert id == to_string(activity.id)
assert_schema(resp, "StatusesResponse", ApiSpec.spec())
resp = resp =
conn conn
|> assign(:user, user_two) |> assign(:user, user_two)
|> assign(:token, insert(:oauth_token, user: user_two, scopes: ["read:statuses"])) |> assign(:token, insert(:oauth_token, user: user_two, scopes: ["read:statuses"]))
|> get("/api/v1/accounts/#{user_one.id}/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_one == to_string(direct_activity.id)
assert id_two == to_string(activity.id) assert id_two == to_string(activity.id)
assert_schema(resp, "StatusesResponse", ApiSpec.spec())
resp = resp =
conn conn
|> assign(:user, user_three) |> assign(:user, user_three)
|> assign(:token, insert(:oauth_token, user: user_three, scopes: ["read:statuses"])) |> assign(:token, insert(:oauth_token, user: user_three, scopes: ["read:statuses"]))
|> get("/api/v1/accounts/#{user_one.id}/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_one == to_string(private_activity.id)
assert id_two == to_string(activity.id) assert id_two == to_string(activity.id)
assert_schema(resp, "StatusesResponse", ApiSpec.spec())
end end
test "unimplemented pinned statuses feature", %{conn: conn} do test "unimplemented pinned statuses feature", %{conn: conn} do
@ -335,40 +342,45 @@ test "gets an users media", %{conn: conn} do
{:ok, image_post} = CommonAPI.post(user, %{"status" => "cofe", "media_ids" => [media_id]}) {: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" => id}] = json_response(conn, 200)
assert id == to_string(image_post.id) 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" => id}] = json_response(conn, 200)
assert id == to_string(image_post.id) assert id == to_string(image_post.id)
assert_schema(json_response(conn, 200), "StatusesResponse", ApiSpec.spec())
end end
test "gets a user's statuses without reblogs", %{user: user, conn: conn} do test "gets a user's statuses without reblogs", %{user: user, conn: conn} do
{:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"}) {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
{:ok, _, _} = CommonAPI.repeat(post.id, user) {: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" => id}] = json_response(conn, 200)
assert id == to_string(post.id) 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" => id}] = json_response(conn, 200)
assert id == to_string(post.id) assert id == to_string(post.id)
assert_schema(json_response(conn, 200), "StatusesResponse", ApiSpec.spec())
end end
test "filters user's statuses by a hashtag", %{user: user, conn: conn} do 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"})
{: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" => id}] = json_response(conn, 200)
assert id == to_string(post.id) assert id == to_string(post.id)
assert_schema(json_response(conn, 200), "StatusesResponse", ApiSpec.spec())
end end
test "the user views their own timelines and excludes direct messages", %{ test "the user views their own timelines and excludes direct messages", %{
@ -378,11 +390,11 @@ test "the user views their own timelines and excludes direct messages", %{
{:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"}) {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
{:ok, _direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"}) {:ok, _direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
conn = conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_visibilities[]=direct")
get(conn, "/api/v1/accounts/#{user.id}/statuses", %{"exclude_visibilities" => ["direct"]})
assert [%{"id" => id}] = json_response(conn, 200) assert [%{"id" => id}] = json_response(conn, 200)
assert id == to_string(public_activity.id) assert id == to_string(public_activity.id)
assert_schema(json_response(conn, 200), "StatusesResponse", ApiSpec.spec())
end end
end end
@ -420,9 +432,11 @@ test "if user is authenticated", %{local: local, remote: remote} do
res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses") res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
assert length(json_response(res_conn, 200)) == 1 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") res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
assert length(json_response(res_conn, 200)) == 1 assert length(json_response(res_conn, 200)) == 1
assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
end end
end end
@ -441,6 +455,7 @@ test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} d
res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses") res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
assert length(json_response(res_conn, 200)) == 1 assert length(json_response(res_conn, 200)) == 1
assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
end end
test "if user is authenticated", %{local: local, remote: remote} do test "if user is authenticated", %{local: local, remote: remote} do
@ -448,9 +463,11 @@ test "if user is authenticated", %{local: local, remote: remote} do
res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses") res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
assert length(json_response(res_conn, 200)) == 1 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") res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
assert length(json_response(res_conn, 200)) == 1 assert length(json_response(res_conn, 200)) == 1
assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
end end
end end
@ -463,6 +480,7 @@ test "if user is authenticated", %{local: local, remote: remote} do
test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses") res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
assert length(json_response(res_conn, 200)) == 1 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") res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
@ -476,9 +494,11 @@ test "if user is authenticated", %{local: local, remote: remote} do
res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses") res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
assert length(json_response(res_conn, 200)) == 1 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") res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
assert length(json_response(res_conn, 200)) == 1 assert length(json_response(res_conn, 200)) == 1
assert_schema(json_response(res_conn, 200), "StatusesResponse", ApiSpec.spec())
end end
end end