Add OpenAPI spec for PollController See merge request pleroma/pleroma!24762168-media-preview-proxy
@@ -0,0 +1,76 @@ | |||
# 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.PollOperation do | |||
alias OpenApiSpex.Operation | |||
alias OpenApiSpex.Schema | |||
alias Pleroma.Web.ApiSpec.Schemas.ApiError | |||
alias Pleroma.Web.ApiSpec.Schemas.FlakeID | |||
alias Pleroma.Web.ApiSpec.Schemas.Poll | |||
import Pleroma.Web.ApiSpec.Helpers | |||
def open_api_operation(action) do | |||
operation = String.to_existing_atom("#{action}_operation") | |||
apply(__MODULE__, operation, []) | |||
end | |||
def show_operation do | |||
%Operation{ | |||
tags: ["Polls"], | |||
summary: "View a poll", | |||
security: [%{"oAuth" => ["read:statuses"]}], | |||
parameters: [id_param()], | |||
operationId: "PollController.show", | |||
responses: %{ | |||
200 => Operation.response("Poll", "application/json", Poll), | |||
404 => Operation.response("Error", "application/json", ApiError) | |||
} | |||
} | |||
end | |||
def vote_operation do | |||
%Operation{ | |||
tags: ["Polls"], | |||
summary: "Vote on a poll", | |||
parameters: [id_param()], | |||
operationId: "PollController.vote", | |||
requestBody: vote_request(), | |||
security: [%{"oAuth" => ["write:statuses"]}], | |||
responses: %{ | |||
200 => Operation.response("Poll", "application/json", Poll), | |||
422 => Operation.response("Error", "application/json", ApiError), | |||
404 => Operation.response("Error", "application/json", ApiError) | |||
} | |||
} | |||
end | |||
defp id_param do | |||
Operation.parameter(:id, :path, FlakeID, "Poll ID", | |||
example: "123", | |||
required: true | |||
) | |||
end | |||
defp vote_request do | |||
request_body( | |||
"Parameters", | |||
%Schema{ | |||
type: :object, | |||
properties: %{ | |||
choices: %Schema{ | |||
type: :array, | |||
items: %Schema{type: :integer}, | |||
description: "Array of own votes containing index for each option (starting from 0)" | |||
} | |||
}, | |||
required: [:choices] | |||
}, | |||
required: true, | |||
example: %{ | |||
"choices" => [0, 1, 2] | |||
} | |||
) | |||
end | |||
end |
@@ -11,26 +11,72 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Poll do | |||
OpenApiSpex.schema(%{ | |||
title: "Poll", | |||
description: "Response schema for account custom fields", | |||
description: "Represents a poll attached to a status", | |||
type: :object, | |||
properties: %{ | |||
id: FlakeID, | |||
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: Emoji}, | |||
expires_at: %Schema{ | |||
type: :string, | |||
format: :"date-time", | |||
nullable: true, | |||
description: "When the poll ends" | |||
}, | |||
expired: %Schema{type: :boolean, description: "Is the poll currently expired?"}, | |||
multiple: %Schema{ | |||
type: :boolean, | |||
description: "Does the poll allow multiple-choice answers?" | |||
}, | |||
votes_count: %Schema{ | |||
type: :integer, | |||
nullable: true, | |||
description: "How many votes have been received. Number, or null if `multiple` is false." | |||
}, | |||
voted: %Schema{ | |||
type: :boolean, | |||
nullable: true, | |||
description: | |||
"When called with a user token, has the authorized user voted? Boolean, or null if no current user." | |||
}, | |||
emojis: %Schema{ | |||
type: :array, | |||
items: Emoji, | |||
description: "Custom emoji to be used for rendering poll options." | |||
}, | |||
options: %Schema{ | |||
type: :array, | |||
items: %Schema{ | |||
title: "PollOption", | |||
type: :object, | |||
properties: %{ | |||
title: %Schema{type: :string}, | |||
votes_count: %Schema{type: :integer} | |||
} | |||
} | |||
}, | |||
description: "Possible answers for the poll." | |||
} | |||
}, | |||
example: %{ | |||
id: "34830", | |||
expires_at: "2019-12-05T04:05:08.302Z", | |||
expired: true, | |||
multiple: false, | |||
votes_count: 10, | |||
voters_count: nil, | |||
voted: true, | |||
own_votes: [ | |||
1 | |||
], | |||
options: [ | |||
%{ | |||
title: "accept", | |||
votes_count: 6 | |||
}, | |||
%{ | |||
title: "deny", | |||
votes_count: 4 | |||
} | |||
], | |||
emojis: [] | |||
} | |||
}) | |||
end |
@@ -15,6 +15,8 @@ defmodule Pleroma.Web.MastodonAPI.PollController do | |||
action_fallback(Pleroma.Web.MastodonAPI.FallbackController) | |||
plug(Pleroma.Web.ApiSpec.CastAndValidate) | |||
plug( | |||
OAuthScopesPlug, | |||
%{scopes: ["read:statuses"], fallback: :proceed_unauthenticated} when action == :show | |||
@@ -22,8 +24,10 @@ defmodule Pleroma.Web.MastodonAPI.PollController do | |||
plug(OAuthScopesPlug, %{scopes: ["write:statuses"]} when action == :vote) | |||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PollOperation | |||
@doc "GET /api/v1/polls/:id" | |||
def show(%{assigns: %{user: user}} = conn, %{"id" => id}) do | |||
def show(%{assigns: %{user: user}} = conn, %{id: id}) do | |||
with %Object{} = object <- Object.get_by_id_and_maybe_refetch(id, interval: 60), | |||
%Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]), | |||
true <- Visibility.visible_for_user?(activity, user) do | |||
@@ -35,7 +39,7 @@ defmodule Pleroma.Web.MastodonAPI.PollController do | |||
end | |||
@doc "POST /api/v1/polls/:id/votes" | |||
def vote(%{assigns: %{user: user}} = conn, %{"id" => id, "choices" => choices}) do | |||
def vote(%{assigns: %{user: user}, body_params: %{choices: choices}} = conn, %{id: id}) do | |||
with %Object{data: %{"type" => "Question"}} = object <- Object.get_by_id(id), | |||
%Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]), | |||
true <- Visibility.visible_for_user?(activity, user), | |||
@@ -24,7 +24,7 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do | |||
conn = get(conn, "/api/v1/polls/#{object.id}") | |||
response = json_response(conn, 200) | |||
response = json_response_and_validate_schema(conn, 200) | |||
id = to_string(object.id) | |||
assert %{"id" => ^id, "expired" => false, "multiple" => false} = response | |||
end | |||
@@ -43,7 +43,7 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do | |||
conn = get(conn, "/api/v1/polls/#{object.id}") | |||
assert json_response(conn, 404) | |||
assert json_response_and_validate_schema(conn, 404) | |||
end | |||
end | |||
@@ -65,9 +65,12 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do | |||
object = Object.normalize(activity) | |||
conn = post(conn, "/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]}) | |||
conn = | |||
conn | |||
|> put_req_header("content-type", "application/json") | |||
|> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]}) | |||
assert json_response(conn, 200) | |||
assert json_response_and_validate_schema(conn, 200) | |||
object = Object.get_by_id(object.id) | |||
assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} -> | |||
@@ -85,8 +88,9 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do | |||
object = Object.normalize(activity) | |||
assert conn | |||
|> put_req_header("content-type", "application/json") | |||
|> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]}) | |||
|> json_response(422) == %{"error" => "Poll's author can't vote"} | |||
|> json_response_and_validate_schema(422) == %{"error" => "Poll's author can't vote"} | |||
object = Object.get_by_id(object.id) | |||
@@ -105,8 +109,9 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do | |||
object = Object.normalize(activity) | |||
assert conn | |||
|> put_req_header("content-type", "application/json") | |||
|> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]}) | |||
|> json_response(422) == %{"error" => "Too many choices"} | |||
|> json_response_and_validate_schema(422) == %{"error" => "Too many choices"} | |||
object = Object.get_by_id(object.id) | |||
@@ -126,15 +131,21 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do | |||
object = Object.normalize(activity) | |||
conn = post(conn, "/api/v1/polls/#{object.id}/votes", %{"choices" => [2]}) | |||
conn = | |||
conn | |||
|> put_req_header("content-type", "application/json") | |||
|> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]}) | |||
assert json_response(conn, 422) == %{"error" => "Invalid indices"} | |||
assert json_response_and_validate_schema(conn, 422) == %{"error" => "Invalid indices"} | |||
end | |||
test "returns 404 error when object is not exist", %{conn: conn} do | |||
conn = post(conn, "/api/v1/polls/1/votes", %{"choices" => [0]}) | |||
conn = | |||
conn | |||
|> put_req_header("content-type", "application/json") | |||
|> post("/api/v1/polls/1/votes", %{"choices" => [0]}) | |||
assert json_response(conn, 404) == %{"error" => "Record not found"} | |||
assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"} | |||
end | |||
test "returns 404 when poll is private and not available for user", %{conn: conn} do | |||
@@ -149,9 +160,12 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do | |||
object = Object.normalize(activity) | |||
conn = post(conn, "/api/v1/polls/#{object.id}/votes", %{"choices" => [0]}) | |||
conn = | |||
conn | |||
|> put_req_header("content-type", "application/json") | |||
|> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]}) | |||
assert json_response(conn, 404) == %{"error" => "Record not found"} | |||
assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"} | |||
end | |||
end | |||
end |