Page MenuHomePhorge

No OneTemporary

Authored By
Unknown
Size
16 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/pleroma/web/api_spec/operations/list_operation.ex b/lib/pleroma/web/api_spec/operations/list_operation.ex
index c88ed5dd0..15039052e 100644
--- a/lib/pleroma/web/api_spec/operations/list_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/list_operation.ex
@@ -1,188 +1,196 @@
# 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.ListOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Schemas.Account
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
alias Pleroma.Web.ApiSpec.Schemas.List
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: ["Lists"],
summary: "Show user's lists",
description: "Fetch all lists that the user owns",
security: [%{"oAuth" => ["read:lists"]}],
operationId: "ListController.index",
responses: %{
200 => Operation.response("Array of List", "application/json", array_of_lists())
}
}
end
def create_operation do
%Operation{
tags: ["Lists"],
summary: "Create a list",
description: "Fetch the list with the given ID. Used for verifying the title of a list.",
operationId: "ListController.create",
requestBody: create_update_request(),
security: [%{"oAuth" => ["write:lists"]}],
responses: %{
200 => Operation.response("List", "application/json", List),
400 => Operation.response("Error", "application/json", ApiError),
404 => Operation.response("Error", "application/json", ApiError)
}
}
end
def show_operation do
%Operation{
tags: ["Lists"],
summary: "Show a single list",
description: "Fetch the list with the given ID. Used for verifying the title of a list.",
operationId: "ListController.show",
parameters: [id_param()],
security: [%{"oAuth" => ["read:lists"]}],
responses: %{
200 => Operation.response("List", "application/json", List),
404 => Operation.response("Error", "application/json", ApiError)
}
}
end
def update_operation do
%Operation{
tags: ["Lists"],
summary: "Update a list",
description: "Change the title of a list",
operationId: "ListController.update",
parameters: [id_param()],
requestBody: create_update_request(),
security: [%{"oAuth" => ["write:lists"]}],
responses: %{
200 => Operation.response("List", "application/json", List),
422 => Operation.response("Error", "application/json", ApiError)
}
}
end
def delete_operation do
%Operation{
tags: ["Lists"],
summary: "Delete a list",
operationId: "ListController.delete",
parameters: [id_param()],
security: [%{"oAuth" => ["write:lists"]}],
responses: %{
200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
}
}
end
def list_accounts_operation do
%Operation{
tags: ["Lists"],
summary: "View accounts in list",
operationId: "ListController.list_accounts",
parameters: [id_param()],
security: [%{"oAuth" => ["read:lists"]}],
responses: %{
200 =>
Operation.response("Array of Account", "application/json", %Schema{
type: :array,
items: Account
})
}
}
end
def add_to_list_operation do
%Operation{
tags: ["Lists"],
summary: "Add accounts to list",
description: "Add accounts to the given list.",
operationId: "ListController.add_to_list",
parameters: [id_param()],
- requestBody: add_remove_accounts_request(),
+ requestBody: add_remove_accounts_request(true),
security: [%{"oAuth" => ["write:lists"]}],
responses: %{
200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
}
}
end
def remove_from_list_operation do
%Operation{
tags: ["Lists"],
summary: "Remove accounts from list",
operationId: "ListController.remove_from_list",
- parameters: [id_param()],
- requestBody: add_remove_accounts_request(),
+ parameters: [
+ id_param(),
+ Operation.parameter(
+ :account_ids,
+ :query,
+ %Schema{type: :array, items: %Schema{type: :string}},
+ "Array of account IDs"
+ )
+ ],
+ requestBody: add_remove_accounts_request(false),
security: [%{"oAuth" => ["write:lists"]}],
responses: %{
200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
}
}
end
defp array_of_lists do
%Schema{
title: "ArrayOfLists",
description: "Response schema for lists",
type: :array,
items: List,
example: [
%{"id" => "123", "title" => "my list"},
%{"id" => "1337", "title" => "another list"}
]
}
end
defp id_param do
Operation.parameter(:id, :path, :string, "List ID",
example: "123",
required: true
)
end
defp create_update_request do
request_body(
"Parameters",
%Schema{
description: "POST body for creating or updating a List",
type: :object,
properties: %{
title: %Schema{type: :string, description: "List title"}
},
required: [:title]
},
required: true
)
end
- defp add_remove_accounts_request do
+ defp add_remove_accounts_request(required) when is_boolean(required) do
request_body(
"Parameters",
%Schema{
description: "POST body for adding/removing accounts to/from a List",
type: :object,
properties: %{
account_ids: %Schema{type: :array, description: "Array of account IDs", items: FlakeID}
},
- required: [:account_ids]
+ required: required && [:account_ids]
},
- required: true
+ required: required
)
end
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/list_controller.ex b/lib/pleroma/web/mastodon_api/controllers/list_controller.ex
index acdc76fd2..4df13cb81 100644
--- a/lib/pleroma/web/mastodon_api/controllers/list_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/list_controller.ex
@@ -1,95 +1,108 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ListController do
use Pleroma.Web, :controller
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.User
alias Pleroma.Web.MastodonAPI.AccountView
@oauth_read_actions [:index, :show, :list_accounts]
plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(:list_by_id_and_user when action not in [:index, :create])
plug(OAuthScopesPlug, %{scopes: ["read:lists"]} when action in @oauth_read_actions)
plug(OAuthScopesPlug, %{scopes: ["write:lists"]} when action not in @oauth_read_actions)
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.ListOperation
# GET /api/v1/lists
def index(%{assigns: %{user: user}} = conn, opts) do
lists = Pleroma.List.for_user(user, opts)
render(conn, "index.json", lists: lists)
end
# POST /api/v1/lists
def create(%{assigns: %{user: user}, body_params: %{title: title}} = conn, _) do
with {:ok, %Pleroma.List{} = list} <- Pleroma.List.create(title, user) do
render(conn, "show.json", list: list)
end
end
# GET /api/v1/lists/:id
def show(%{assigns: %{list: list}} = conn, _) do
render(conn, "show.json", list: list)
end
# PUT /api/v1/lists/:id
def update(%{assigns: %{list: list}, body_params: %{title: title}} = conn, _) do
with {:ok, list} <- Pleroma.List.rename(list, title) do
render(conn, "show.json", list: list)
end
end
# DELETE /api/v1/lists/:id
def delete(%{assigns: %{list: list}} = conn, _) do
with {:ok, _list} <- Pleroma.List.delete(list) do
json(conn, %{})
end
end
# GET /api/v1/lists/:id/accounts
def list_accounts(%{assigns: %{user: user, list: list}} = conn, _) do
with {:ok, users} <- Pleroma.List.get_following(list) do
conn
|> put_view(AccountView)
|> render("index.json", for: user, users: users, as: :user)
end
end
# POST /api/v1/lists/:id/accounts
def add_to_list(%{assigns: %{list: list}, body_params: %{account_ids: account_ids}} = conn, _) do
Enum.each(account_ids, fn account_id ->
with %User{} = followed <- User.get_cached_by_id(account_id) do
Pleroma.List.follow(list, followed)
end
end)
json(conn, %{})
end
# DELETE /api/v1/lists/:id/accounts
def remove_from_list(
%{assigns: %{list: list}, body_params: %{account_ids: account_ids}} = conn,
_
) do
Enum.each(account_ids, fn account_id ->
with %User{} = followed <- User.get_cached_by_id(account_id) do
Pleroma.List.unfollow(list, followed)
end
end)
json(conn, %{})
end
+ def remove_from_list(
+ %{assigns: %{list: list}, params: %{account_ids: account_ids}} = conn,
+ _
+ ) do
+ Enum.each(account_ids, fn account_id ->
+ with %User{} = followed <- User.get_cached_by_id(account_id) do
+ Pleroma.List.unfollow(list, followed)
+ end
+ end)
+
+ json(conn, %{})
+ end
+
defp list_by_id_and_user(%{assigns: %{user: user}, params: %{id: id}} = conn, _) do
case Pleroma.List.get(id, user) do
%Pleroma.List{} = list -> assign(conn, :list, list)
nil -> conn |> render_error(:not_found, "List not found") |> halt()
end
end
end
diff --git a/test/web/mastodon_api/controllers/list_controller_test.exs b/test/web/mastodon_api/controllers/list_controller_test.exs
index 57a9ef4a4..091ec006c 100644
--- a/test/web/mastodon_api/controllers/list_controller_test.exs
+++ b/test/web/mastodon_api/controllers/list_controller_test.exs
@@ -1,158 +1,176 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ListControllerTest do
use Pleroma.Web.ConnCase
alias Pleroma.Repo
import Pleroma.Factory
test "creating a list" do
%{conn: conn} = oauth_access(["write:lists"])
assert %{"title" => "cuties"} =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/lists", %{"title" => "cuties"})
|> json_response_and_validate_schema(:ok)
end
test "renders error for invalid params" do
%{conn: conn} = oauth_access(["write:lists"])
conn =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/lists", %{"title" => nil})
assert %{"error" => "title - null value where string expected."} =
json_response_and_validate_schema(conn, 400)
end
test "listing a user's lists" do
%{conn: conn} = oauth_access(["read:lists", "write:lists"])
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/lists", %{"title" => "cuties"})
|> json_response_and_validate_schema(:ok)
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/lists", %{"title" => "cofe"})
|> json_response_and_validate_schema(:ok)
conn = get(conn, "/api/v1/lists")
assert [
%{"id" => _, "title" => "cofe"},
%{"id" => _, "title" => "cuties"}
] = json_response_and_validate_schema(conn, :ok)
end
test "adding users to a list" do
%{user: user, conn: conn} = oauth_access(["write:lists"])
other_user = insert(:user)
{:ok, list} = Pleroma.List.create("name", user)
assert %{} ==
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
|> json_response_and_validate_schema(:ok)
%Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
assert following == [other_user.follower_address]
end
- test "removing users from a list" do
+ test "removing users from a list, body params" do
%{user: user, conn: conn} = oauth_access(["write:lists"])
other_user = insert(:user)
third_user = insert(:user)
{:ok, list} = Pleroma.List.create("name", user)
{:ok, list} = Pleroma.List.follow(list, other_user)
{:ok, list} = Pleroma.List.follow(list, third_user)
assert %{} ==
conn
|> put_req_header("content-type", "application/json")
|> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
|> json_response_and_validate_schema(:ok)
%Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
assert following == [third_user.follower_address]
end
+ test "removing users from a list, query params" do
+ %{user: user, conn: conn} = oauth_access(["write:lists"])
+ other_user = insert(:user)
+ third_user = insert(:user)
+ {:ok, list} = Pleroma.List.create("name", user)
+ {:ok, list} = Pleroma.List.follow(list, other_user)
+ {:ok, list} = Pleroma.List.follow(list, third_user)
+
+ assert %{} ==
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> delete("/api/v1/lists/#{list.id}/accounts?account_ids[]=#{other_user.id}")
+ |> json_response_and_validate_schema(:ok)
+
+ %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
+ assert following == [third_user.follower_address]
+ end
+
test "listing users in a list" do
%{user: user, conn: conn} = oauth_access(["read:lists"])
other_user = insert(:user)
{:ok, list} = Pleroma.List.create("name", user)
{:ok, list} = Pleroma.List.follow(list, other_user)
conn =
conn
|> assign(:user, user)
|> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
assert [%{"id" => id}] = json_response_and_validate_schema(conn, 200)
assert id == to_string(other_user.id)
end
test "retrieving a list" do
%{user: user, conn: conn} = oauth_access(["read:lists"])
{:ok, list} = Pleroma.List.create("name", user)
conn =
conn
|> assign(:user, user)
|> get("/api/v1/lists/#{list.id}")
assert %{"id" => id} = json_response_and_validate_schema(conn, 200)
assert id == to_string(list.id)
end
test "renders 404 if list is not found" do
%{conn: conn} = oauth_access(["read:lists"])
conn = get(conn, "/api/v1/lists/666")
assert %{"error" => "List not found"} = json_response_and_validate_schema(conn, :not_found)
end
test "renaming a list" do
%{user: user, conn: conn} = oauth_access(["write:lists"])
{:ok, list} = Pleroma.List.create("name", user)
assert %{"title" => "newname"} =
conn
|> put_req_header("content-type", "application/json")
|> put("/api/v1/lists/#{list.id}", %{"title" => "newname"})
|> json_response_and_validate_schema(:ok)
end
test "validates title when renaming a list" do
%{user: user, conn: conn} = oauth_access(["write:lists"])
{:ok, list} = Pleroma.List.create("name", user)
conn =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/json")
|> put("/api/v1/lists/#{list.id}", %{"title" => " "})
assert %{"error" => "can't be blank"} ==
json_response_and_validate_schema(conn, :unprocessable_entity)
end
test "deleting a list" do
%{user: user, conn: conn} = oauth_access(["write:lists"])
{:ok, list} = Pleroma.List.create("name", user)
conn = delete(conn, "/api/v1/lists/#{list.id}")
assert %{} = json_response_and_validate_schema(conn, 200)
assert is_nil(Repo.get(Pleroma.List, list.id))
end
end

File Metadata

Mime Type
text/x-diff
Expires
Thu, Oct 29, 12:50 PM (1 d, 3 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1798110
Default Alt Text
(16 KB)

Event Timeline