It doesn't make sense to like, react, reply, etc to something you cannot see and is unexpected for the author of the interacted with post and might make them believe the reacting user actually _can_ see the post. Wrt to fav, reblog, reaction indexes the missing visibility check was also leaking some (presumably/hopefully) low-severity data. Add full-API test for all modes of interactions with private posts.
803 lines
25 KiB
Elixir
803 lines
25 KiB
Elixir
# Pleroma: A lightweight social networking server
|
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
defmodule Pleroma.Web.ApiSpec.StatusOperation do
|
|
alias OpenApiSpex.Operation
|
|
alias OpenApiSpex.Schema
|
|
alias Pleroma.Web.ApiSpec.AccountOperation
|
|
alias Pleroma.Web.ApiSpec.Schemas.Account
|
|
alias Pleroma.Web.ApiSpec.Schemas.ApiError
|
|
alias Pleroma.Web.ApiSpec.Schemas.Attachment
|
|
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
|
|
alias Pleroma.Web.ApiSpec.Schemas.Emoji
|
|
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
|
|
alias Pleroma.Web.ApiSpec.Schemas.Poll
|
|
alias Pleroma.Web.ApiSpec.Schemas.ScheduledStatus
|
|
alias Pleroma.Web.ApiSpec.Schemas.Status
|
|
alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
|
|
|
|
import Pleroma.Web.ApiSpec.Helpers
|
|
|
|
def open_api_operation(action) do
|
|
operation = String.to_existing_atom("#{action}_operation")
|
|
apply(__MODULE__, operation, [])
|
|
end
|
|
|
|
def index_operation do
|
|
%Operation{
|
|
tags: ["Retrieve status information"],
|
|
summary: "Multiple statuses",
|
|
security: [%{"oAuth" => ["read:statuses"]}],
|
|
parameters: [
|
|
Operation.parameter(
|
|
:ids,
|
|
:query,
|
|
%Schema{type: :array, items: FlakeID},
|
|
"Array of status IDs"
|
|
),
|
|
Operation.parameter(
|
|
:with_muted,
|
|
:query,
|
|
BooleanLike,
|
|
"Include reactions from muted acccounts."
|
|
)
|
|
],
|
|
operationId: "StatusController.index",
|
|
responses: %{
|
|
200 => Operation.response("Array of Status", "application/json", array_of_statuses())
|
|
}
|
|
}
|
|
end
|
|
|
|
def create_operation do
|
|
%Operation{
|
|
tags: ["Status actions"],
|
|
summary: "Publish new status",
|
|
security: [%{"oAuth" => ["write:statuses"]}],
|
|
description: "Post a new status",
|
|
operationId: "StatusController.create",
|
|
requestBody: request_body("Parameters", create_request(), required: true),
|
|
responses: %{
|
|
200 =>
|
|
Operation.response(
|
|
"Status. When `scheduled_at` is present, ScheduledStatus is returned instead",
|
|
"application/json",
|
|
%Schema{anyOf: [Status, ScheduledStatus]}
|
|
),
|
|
422 => Operation.response("Bad Request / MRF Rejection", "application/json", ApiError)
|
|
}
|
|
}
|
|
end
|
|
|
|
def show_operation do
|
|
%Operation{
|
|
tags: ["Retrieve status information"],
|
|
summary: "Status",
|
|
description: "View information about a status",
|
|
operationId: "StatusController.show",
|
|
security: [%{"oAuth" => ["read:statuses"]}],
|
|
parameters: [
|
|
id_param(),
|
|
Operation.parameter(
|
|
:with_muted,
|
|
:query,
|
|
BooleanLike,
|
|
"Include reactions from muted acccounts."
|
|
)
|
|
],
|
|
responses: %{
|
|
200 => status_response(),
|
|
404 => Operation.response("Not Found", "application/json", ApiError)
|
|
}
|
|
}
|
|
end
|
|
|
|
def delete_operation do
|
|
%Operation{
|
|
tags: ["Status actions"],
|
|
summary: "Delete",
|
|
security: [%{"oAuth" => ["write:statuses"]}],
|
|
description: "Delete one of your own statuses",
|
|
operationId: "StatusController.delete",
|
|
parameters: [id_param()],
|
|
responses: %{
|
|
200 => status_response(),
|
|
403 => Operation.response("Forbidden", "application/json", ApiError),
|
|
404 => Operation.response("Not Found", "application/json", ApiError)
|
|
}
|
|
}
|
|
end
|
|
|
|
def reblog_operation do
|
|
%Operation{
|
|
tags: ["Status actions"],
|
|
summary: "Reblog",
|
|
security: [%{"oAuth" => ["write:statuses"]}],
|
|
description: "Share a status",
|
|
operationId: "StatusController.reblog",
|
|
parameters: [id_param()],
|
|
requestBody:
|
|
request_body("Parameters", %Schema{
|
|
type: :object,
|
|
properties: %{
|
|
visibility: %Schema{allOf: [VisibilityScope]}
|
|
}
|
|
}),
|
|
responses: %{
|
|
200 => status_response(),
|
|
404 => Operation.response("Not Found", "application/json", ApiError)
|
|
}
|
|
}
|
|
end
|
|
|
|
def unreblog_operation do
|
|
%Operation{
|
|
tags: ["Status actions"],
|
|
summary: "Undo reblog",
|
|
security: [%{"oAuth" => ["write:statuses"]}],
|
|
description: "Undo a reshare of a status",
|
|
operationId: "StatusController.unreblog",
|
|
parameters: [id_param()],
|
|
responses: %{
|
|
200 => status_response(),
|
|
404 => Operation.response("Not Found", "application/json", ApiError)
|
|
}
|
|
}
|
|
end
|
|
|
|
def favourite_operation do
|
|
%Operation{
|
|
tags: ["Status actions"],
|
|
summary: "Favourite",
|
|
security: [%{"oAuth" => ["write:favourites"]}],
|
|
description: "Add a status to your favourites list",
|
|
operationId: "StatusController.favourite",
|
|
parameters: [id_param()],
|
|
responses: %{
|
|
200 => status_response(),
|
|
403 => Operation.response("Access denied", "application/json", ApiError),
|
|
404 => Operation.response("Not Found", "application/json", ApiError)
|
|
}
|
|
}
|
|
end
|
|
|
|
def unfavourite_operation do
|
|
%Operation{
|
|
tags: ["Status actions"],
|
|
summary: "Undo favourite",
|
|
security: [%{"oAuth" => ["write:favourites"]}],
|
|
description: "Remove a status from your favourites list",
|
|
operationId: "StatusController.unfavourite",
|
|
parameters: [id_param()],
|
|
responses: %{
|
|
200 => status_response(),
|
|
404 => Operation.response("Not Found", "application/json", ApiError)
|
|
}
|
|
}
|
|
end
|
|
|
|
def pin_operation do
|
|
%Operation{
|
|
tags: ["Status actions"],
|
|
summary: "Pin to profile",
|
|
security: [%{"oAuth" => ["write:accounts"]}],
|
|
description: "Feature one of your own public statuses at the top of your profile",
|
|
operationId: "StatusController.pin",
|
|
parameters: [id_param()],
|
|
responses: %{
|
|
200 => status_response(),
|
|
400 =>
|
|
Operation.response("Bad Request", "application/json", %Schema{
|
|
allOf: [ApiError],
|
|
title: "Unprocessable Entity",
|
|
example: %{
|
|
"error" => "You have already pinned the maximum number of statuses"
|
|
}
|
|
}),
|
|
404 =>
|
|
Operation.response("Not found", "application/json", %Schema{
|
|
allOf: [ApiError],
|
|
title: "Unprocessable Entity",
|
|
example: %{
|
|
"error" => "Record not found"
|
|
}
|
|
}),
|
|
422 =>
|
|
Operation.response(
|
|
"Unprocessable Entity",
|
|
"application/json",
|
|
%Schema{
|
|
allOf: [ApiError],
|
|
title: "Unprocessable Entity",
|
|
example: %{
|
|
"error" => "Someone else's status cannot be pinned"
|
|
}
|
|
}
|
|
)
|
|
}
|
|
}
|
|
end
|
|
|
|
def unpin_operation do
|
|
%Operation{
|
|
tags: ["Status actions"],
|
|
summary: "Unpin from profile",
|
|
security: [%{"oAuth" => ["write:accounts"]}],
|
|
description: "Unfeature a status from the top of your profile",
|
|
operationId: "StatusController.unpin",
|
|
parameters: [id_param()],
|
|
responses: %{
|
|
200 => status_response(),
|
|
400 =>
|
|
Operation.response("Bad Request", "application/json", %Schema{
|
|
allOf: [ApiError],
|
|
title: "Unprocessable Entity",
|
|
example: %{
|
|
"error" => "You have already pinned the maximum number of statuses"
|
|
}
|
|
}),
|
|
404 =>
|
|
Operation.response("Not found", "application/json", %Schema{
|
|
allOf: [ApiError],
|
|
title: "Unprocessable Entity",
|
|
example: %{
|
|
"error" => "Record not found"
|
|
}
|
|
})
|
|
}
|
|
}
|
|
end
|
|
|
|
def bookmark_operation do
|
|
%Operation{
|
|
tags: ["Status actions"],
|
|
summary: "Bookmark",
|
|
security: [%{"oAuth" => ["write:bookmarks"]}],
|
|
description: "Privately bookmark a status",
|
|
operationId: "StatusController.bookmark",
|
|
parameters: [id_param()],
|
|
responses: %{
|
|
200 => status_response()
|
|
}
|
|
}
|
|
end
|
|
|
|
def unbookmark_operation do
|
|
%Operation{
|
|
tags: ["Status actions"],
|
|
summary: "Undo bookmark",
|
|
security: [%{"oAuth" => ["write:bookmarks"]}],
|
|
description: "Remove a status from your private bookmarks",
|
|
operationId: "StatusController.unbookmark",
|
|
parameters: [id_param()],
|
|
responses: %{
|
|
200 => status_response()
|
|
}
|
|
}
|
|
end
|
|
|
|
def mute_conversation_operation do
|
|
%Operation{
|
|
tags: ["Status actions"],
|
|
summary: "Mute conversation",
|
|
security: [%{"oAuth" => ["write:mutes"]}],
|
|
description: "Do not receive notifications for the thread that this status is part of.",
|
|
operationId: "StatusController.mute_conversation",
|
|
requestBody:
|
|
request_body("Parameters", %Schema{
|
|
type: :object,
|
|
properties: %{
|
|
expires_in: %Schema{
|
|
type: :integer,
|
|
nullable: true,
|
|
description: "Expire the mute in `expires_in` seconds. Default 0 for infinity",
|
|
default: 0
|
|
}
|
|
}
|
|
}),
|
|
parameters: [
|
|
id_param(),
|
|
Operation.parameter(
|
|
:expires_in,
|
|
:query,
|
|
%Schema{type: :integer, default: 0},
|
|
"Expire the mute in `expires_in` seconds. Default 0 for infinity"
|
|
)
|
|
],
|
|
responses: %{
|
|
200 => status_response(),
|
|
400 => Operation.response("Error", "application/json", ApiError)
|
|
}
|
|
}
|
|
end
|
|
|
|
def unmute_conversation_operation do
|
|
%Operation{
|
|
tags: ["Status actions"],
|
|
summary: "Unmute conversation",
|
|
security: [%{"oAuth" => ["write:mutes"]}],
|
|
description:
|
|
"Start receiving notifications again for the thread that this status is part of",
|
|
operationId: "StatusController.unmute_conversation",
|
|
parameters: [id_param()],
|
|
responses: %{
|
|
200 => status_response(),
|
|
400 => Operation.response("Error", "application/json", ApiError)
|
|
}
|
|
}
|
|
end
|
|
|
|
def favourited_by_operation do
|
|
%Operation{
|
|
tags: ["Retrieve status information"],
|
|
summary: "Favourited by",
|
|
description: "View who favourited a given status",
|
|
operationId: "StatusController.favourited_by",
|
|
security: [%{"oAuth" => ["read:accounts"]}],
|
|
parameters: [id_param()],
|
|
responses: %{
|
|
200 =>
|
|
Operation.response(
|
|
"Array of Accounts",
|
|
"application/json",
|
|
AccountOperation.array_of_accounts()
|
|
),
|
|
404 => Operation.response("Not Found", "application/json", ApiError)
|
|
}
|
|
}
|
|
end
|
|
|
|
def reblogged_by_operation do
|
|
%Operation{
|
|
tags: ["Retrieve status information"],
|
|
summary: "Reblogged by",
|
|
description: "View who reblogged a given status",
|
|
operationId: "StatusController.reblogged_by",
|
|
security: [%{"oAuth" => ["read:accounts"]}],
|
|
parameters: [id_param()],
|
|
responses: %{
|
|
200 =>
|
|
Operation.response(
|
|
"Array of Accounts",
|
|
"application/json",
|
|
AccountOperation.array_of_accounts()
|
|
),
|
|
403 => Operation.response("Access denied", "application/json", ApiError),
|
|
404 => Operation.response("Not Found", "application/json", ApiError)
|
|
}
|
|
}
|
|
end
|
|
|
|
def context_operation do
|
|
%Operation{
|
|
tags: ["Retrieve status information"],
|
|
summary: "Parent and child statuses",
|
|
description: "View statuses above and below this status in the thread",
|
|
operationId: "StatusController.context",
|
|
security: [%{"oAuth" => ["read:statuses"]}],
|
|
parameters: [id_param()],
|
|
responses: %{
|
|
200 => Operation.response("Context", "application/json", context())
|
|
}
|
|
}
|
|
end
|
|
|
|
def favourites_operation do
|
|
%Operation{
|
|
tags: ["Timelines"],
|
|
summary: "Favourited statuses",
|
|
description:
|
|
"Statuses the user has favourited. Please note that you have to use the link headers to paginate this. You can not build the query parameters yourself.",
|
|
operationId: "StatusController.favourites",
|
|
parameters: pagination_params(),
|
|
security: [%{"oAuth" => ["read:favourites"]}],
|
|
responses: %{
|
|
200 => Operation.response("Array of Statuses", "application/json", array_of_statuses())
|
|
}
|
|
}
|
|
end
|
|
|
|
def bookmarks_operation do
|
|
%Operation{
|
|
tags: ["Timelines"],
|
|
summary: "Bookmarked statuses",
|
|
description: "Statuses the user has bookmarked",
|
|
operationId: "StatusController.bookmarks",
|
|
parameters: pagination_params(),
|
|
security: [%{"oAuth" => ["read:bookmarks"]}],
|
|
responses: %{
|
|
200 => Operation.response("Array of Statuses", "application/json", array_of_statuses())
|
|
}
|
|
}
|
|
end
|
|
|
|
def translate_operation do
|
|
%Operation{
|
|
tags: ["Retrieve status translation"],
|
|
summary: "Translate status",
|
|
description: "View the translation of a given status",
|
|
operationId: "StatusController.translation",
|
|
security: [%{"oAuth" => ["read:statuses"]}],
|
|
parameters: [id_param(), language_param(), source_language_param()],
|
|
responses: %{
|
|
200 => Operation.response("Translation", "application/json", translation()),
|
|
400 => Operation.response("Error", "application/json", ApiError),
|
|
404 => Operation.response("Not Found", "application/json", ApiError)
|
|
}
|
|
}
|
|
end
|
|
|
|
def show_history_operation do
|
|
%Operation{
|
|
tags: ["Retrieve status history"],
|
|
summary: "Status history",
|
|
description: "View history of a status",
|
|
operationId: "StatusController.show_history",
|
|
security: [%{"oAuth" => ["read:statuses"]}],
|
|
parameters: [
|
|
id_param()
|
|
],
|
|
responses: %{
|
|
200 => status_history_response(),
|
|
404 => Operation.response("Not Found", "application/json", ApiError)
|
|
}
|
|
}
|
|
end
|
|
|
|
def show_source_operation do
|
|
%Operation{
|
|
tags: ["Retrieve status source"],
|
|
summary: "Status source",
|
|
description: "View source of a status",
|
|
operationId: "StatusController.show_source",
|
|
security: [%{"oAuth" => ["read:statuses"]}],
|
|
parameters: [
|
|
id_param()
|
|
],
|
|
responses: %{
|
|
200 => status_source_response(),
|
|
404 => Operation.response("Not Found", "application/json", ApiError)
|
|
}
|
|
}
|
|
end
|
|
|
|
def update_operation do
|
|
%Operation{
|
|
tags: ["Update status"],
|
|
summary: "Update status",
|
|
description: "Change the content of a status",
|
|
operationId: "StatusController.update",
|
|
security: [%{"oAuth" => ["write:statuses"]}],
|
|
parameters: [
|
|
id_param()
|
|
],
|
|
requestBody: request_body("Parameters", update_request(), required: true),
|
|
responses: %{
|
|
200 => status_response(),
|
|
403 => Operation.response("Forbidden", "application/json", ApiError),
|
|
404 => Operation.response("Not Found", "application/json", ApiError)
|
|
}
|
|
}
|
|
end
|
|
|
|
def array_of_statuses do
|
|
%Schema{type: :array, items: Status, example: [Status.schema().example]}
|
|
end
|
|
|
|
defp create_request do
|
|
%Schema{
|
|
title: "StatusCreateRequest",
|
|
type: :object,
|
|
properties: %{
|
|
status: %Schema{
|
|
type: :string,
|
|
nullable: true,
|
|
description:
|
|
"Text content of the status. If `media_ids` is provided, this becomes optional. Attaching a `poll` is optional while `status` is provided."
|
|
},
|
|
media_ids: %Schema{
|
|
nullable: true,
|
|
type: :array,
|
|
items: %Schema{type: :string},
|
|
description: "Array of Attachment ids to be attached as media."
|
|
},
|
|
poll: poll_params(),
|
|
in_reply_to_id: %Schema{
|
|
nullable: true,
|
|
allOf: [FlakeID],
|
|
description: "ID of the status being replied to, if status is a reply"
|
|
},
|
|
sensitive: %Schema{
|
|
allOf: [BooleanLike],
|
|
nullable: true,
|
|
description: "Mark status and attached media as sensitive?"
|
|
},
|
|
spoiler_text: %Schema{
|
|
type: :string,
|
|
nullable: true,
|
|
description:
|
|
"Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field."
|
|
},
|
|
scheduled_at: %Schema{
|
|
type: :string,
|
|
format: :"date-time",
|
|
nullable: true,
|
|
description:
|
|
"ISO 8601 Datetime at which to schedule a status. Providing this paramter will cause ScheduledStatus to be returned instead of Status. Must be at least 5 minutes in the future."
|
|
},
|
|
language: %Schema{
|
|
type: :string,
|
|
nullable: true,
|
|
description: "ISO 639 language code for this status."
|
|
},
|
|
# Pleroma-specific properties:
|
|
preview: %Schema{
|
|
allOf: [BooleanLike],
|
|
nullable: true,
|
|
description:
|
|
"If set to `true` the post won't be actually posted, but the status entitiy would still be rendered back. This could be useful for previewing rich text/custom emoji, for example"
|
|
},
|
|
content_type: %Schema{
|
|
type: :string,
|
|
nullable: true,
|
|
description:
|
|
"The MIME type of the status, it is transformed into HTML by the backend. You can get the list of the supported MIME types with the nodeinfo endpoint."
|
|
},
|
|
to: %Schema{
|
|
type: :array,
|
|
nullable: true,
|
|
items: %Schema{type: :string},
|
|
description:
|
|
"A list of nicknames (like `lain@soykaf.club` or `lain` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for for post visibility are not affected by this and will still apply"
|
|
},
|
|
visibility: %Schema{
|
|
nullable: true,
|
|
anyOf: [
|
|
VisibilityScope,
|
|
%Schema{type: :string, description: "scope name", example: "unlisted"}
|
|
],
|
|
description: "Visibility of the posted status."
|
|
},
|
|
expires_in: %Schema{
|
|
nullable: true,
|
|
type: :integer,
|
|
description:
|
|
"The number of seconds the posted activity should expire in. When a posted activity expires it will be deleted from the server, and a delete request for it will be federated. This needs to be longer than an hour."
|
|
},
|
|
quote_id: %Schema{
|
|
nullable: true,
|
|
type: :string,
|
|
description: "Will quote a given status."
|
|
}
|
|
},
|
|
example: %{
|
|
"status" => "What time is it?",
|
|
"sensitive" => "false",
|
|
"poll" => %{
|
|
"options" => ["Cofe", "Adventure"],
|
|
"expires_in" => 420
|
|
}
|
|
}
|
|
}
|
|
end
|
|
|
|
defp update_request do
|
|
%Schema{
|
|
title: "StatusUpdateRequest",
|
|
type: :object,
|
|
properties: %{
|
|
status: %Schema{
|
|
type: :string,
|
|
nullable: true,
|
|
description:
|
|
"Text content of the status. If `media_ids` is provided, this becomes optional. Attaching a `poll` is optional while `status` is provided."
|
|
},
|
|
media_ids: %Schema{
|
|
nullable: true,
|
|
type: :array,
|
|
items: %Schema{type: :string},
|
|
description: "Array of Attachment ids to be attached as media."
|
|
},
|
|
poll: poll_params(),
|
|
sensitive: %Schema{
|
|
allOf: [BooleanLike],
|
|
nullable: true,
|
|
description: "Mark status and attached media as sensitive?"
|
|
},
|
|
spoiler_text: %Schema{
|
|
type: :string,
|
|
nullable: true,
|
|
description:
|
|
"Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field."
|
|
},
|
|
content_type: %Schema{
|
|
type: :string,
|
|
nullable: true,
|
|
description:
|
|
"The MIME type of the status, it is transformed into HTML by the backend. You can get the list of the supported MIME types with the nodeinfo endpoint."
|
|
},
|
|
to: %Schema{
|
|
type: :array,
|
|
nullable: true,
|
|
items: %Schema{type: :string},
|
|
description:
|
|
"A list of nicknames (like `lain@soykaf.club` or `lain` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for for post visibility are not affected by this and will still apply"
|
|
}
|
|
},
|
|
example: %{
|
|
"status" => "What time is it?",
|
|
"sensitive" => "false",
|
|
"poll" => %{
|
|
"options" => ["Cofe", "Adventure"],
|
|
"expires_in" => 420
|
|
}
|
|
}
|
|
}
|
|
end
|
|
|
|
def poll_params do
|
|
%Schema{
|
|
nullable: true,
|
|
type: :object,
|
|
required: [:options, :expires_in],
|
|
properties: %{
|
|
options: %Schema{
|
|
type: :array,
|
|
items: %Schema{type: :string},
|
|
description: "Array of possible answers. Must be provided with `poll[expires_in]`."
|
|
},
|
|
expires_in: %Schema{
|
|
type: :integer,
|
|
nullable: true,
|
|
description:
|
|
"Duration the poll should be open, in seconds. Must be provided with `poll[options]`"
|
|
},
|
|
multiple: %Schema{
|
|
allOf: [BooleanLike],
|
|
nullable: true,
|
|
description: "Allow multiple choices?"
|
|
},
|
|
hide_totals: %Schema{
|
|
allOf: [BooleanLike],
|
|
nullable: true,
|
|
description: "Hide vote counts until the poll ends?"
|
|
}
|
|
}
|
|
}
|
|
end
|
|
|
|
def id_param do
|
|
Operation.parameter(:id, :path, FlakeID, "Status ID",
|
|
example: "9umDrYheeY451cQnEe",
|
|
required: true
|
|
)
|
|
end
|
|
|
|
defp language_param do
|
|
Operation.parameter(:language, :path, :string, "ISO 639 language code", example: "en")
|
|
end
|
|
|
|
defp source_language_param do
|
|
Operation.parameter(:from, :query, :string, "ISO 639 language code", example: "en")
|
|
end
|
|
|
|
defp status_response do
|
|
Operation.response("Status", "application/json", Status)
|
|
end
|
|
|
|
defp status_history_response do
|
|
Operation.response(
|
|
"Status History",
|
|
"application/json",
|
|
%Schema{
|
|
title: "Status history",
|
|
description: "Response schema for history of a status",
|
|
type: :array,
|
|
items: %Schema{
|
|
type: :object,
|
|
properties: %{
|
|
account: %Schema{
|
|
allOf: [Account],
|
|
description: "The account that authored this status"
|
|
},
|
|
content: %Schema{
|
|
type: :string,
|
|
format: :html,
|
|
description: "HTML-encoded status content"
|
|
},
|
|
sensitive: %Schema{
|
|
type: :boolean,
|
|
description: "Is this status marked as sensitive content?"
|
|
},
|
|
spoiler_text: %Schema{
|
|
type: :string,
|
|
description:
|
|
"Subject or summary line, below which status content is collapsed until expanded"
|
|
},
|
|
created_at: %Schema{
|
|
type: :string,
|
|
format: "date-time",
|
|
description: "The date when this status was created"
|
|
},
|
|
media_attachments: %Schema{
|
|
type: :array,
|
|
items: Attachment,
|
|
description: "Media that is attached to this status"
|
|
},
|
|
emojis: %Schema{
|
|
type: :array,
|
|
items: Emoji,
|
|
description: "Custom emoji to be used when rendering status content"
|
|
},
|
|
poll: %Schema{
|
|
allOf: [Poll],
|
|
nullable: true,
|
|
description: "The poll attached to the status"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
)
|
|
end
|
|
|
|
defp status_source_response do
|
|
Operation.response(
|
|
"Status Source",
|
|
"application/json",
|
|
%Schema{
|
|
type: :object,
|
|
properties: %{
|
|
id: FlakeID,
|
|
text: %Schema{
|
|
type: :string,
|
|
description: "Raw source of status content"
|
|
},
|
|
spoiler_text: %Schema{
|
|
type: :string,
|
|
description:
|
|
"Subject or summary line, below which status content is collapsed until expanded"
|
|
},
|
|
content_type: %Schema{
|
|
type: :string,
|
|
description: "The content type of the source"
|
|
}
|
|
}
|
|
}
|
|
)
|
|
end
|
|
|
|
defp context do
|
|
%Schema{
|
|
title: "StatusContext",
|
|
description:
|
|
"Represents the tree around a given status. Used for reconstructing threads of statuses.",
|
|
type: :object,
|
|
required: [:ancestors, :descendants],
|
|
properties: %{
|
|
ancestors: array_of_statuses(),
|
|
descendants: array_of_statuses()
|
|
},
|
|
example: %{
|
|
"ancestors" => [Status.schema().example],
|
|
"descendants" => [Status.schema().example]
|
|
}
|
|
}
|
|
end
|
|
|
|
defp translation do
|
|
%Schema{
|
|
title: "StatusTranslation",
|
|
description: "The translation of a status.",
|
|
type: :object,
|
|
required: [:detected_language, :text],
|
|
properties: %{
|
|
detected_language: %Schema{
|
|
type: :string,
|
|
description: "The detected language of the text"
|
|
},
|
|
text: %Schema{type: :string, description: "The translated text"}
|
|
}
|
|
}
|
|
end
|
|
end
|