Add spec for AccountController.statuses

This commit is contained in:
Egor Kislitsyn 2020-04-08 22:33:25 +04:00
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 @@ 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

View 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",

View 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

View 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
#

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(
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)

View 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: []