Page MenuHomePhorge

No OneTemporary

Size
32 KB
Referenced Files
None
Subscribers
None
diff --git a/changelog.d/list-emoji.add b/changelog.d/list-emoji.add
new file mode 100644
index 000000000..dce4874d3
--- /dev/null
+++ b/changelog.d/list-emoji.add
@@ -0,0 +1 @@
+Allow attaching emojis to user lists
diff --git a/lib/pleroma/list.ex b/lib/pleroma/list.ex
index cd23bd0a9..3e8a83342 100644
--- a/lib/pleroma/list.ex
+++ b/lib/pleroma/list.ex
@@ -1,163 +1,203 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.List do
use Ecto.Schema
import Ecto.Query
import Ecto.Changeset
alias Pleroma.Activity
+ alias Pleroma.Emoji
alias Pleroma.Repo
alias Pleroma.User
schema "lists" do
belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
field(:title, :string)
field(:following, {:array, :string}, default: [])
field(:ap_id, :string)
field(:exclusive, :boolean, default: false)
+ field(:emoji, :string)
timestamps()
end
def update_changeset(list, attrs \\ %{}) do
list
- |> cast(attrs, [:title, :exclusive])
+ |> cast(attrs, [:title, :exclusive, :emoji])
|> validate_required([:title])
+ |> fix_emoji()
+ |> validate_emoji()
+ end
+
+ defp fix_emoji(changeset) do
+ with {:emoji_field, emoji} when is_binary(emoji) <-
+ {:emoji_field, get_field(changeset, :emoji)},
+ {:fixed_emoji, emoji} <-
+ {:fixed_emoji,
+ emoji
+ |> Emoji.fully_qualify_emoji()
+ |> Emoji.maybe_quote()} do
+ put_change(changeset, :emoji, emoji)
+ else
+ {:emoji_field, _} -> changeset
+ end
+ end
+
+ defp validate_emoji(changeset) do
+ validate_change(changeset, :emoji, fn
+ :emoji, nil ->
+ []
+
+ :emoji, emoji ->
+ if Emoji.unicode?(emoji) or valid_local_custom_emoji?(emoji) do
+ []
+ else
+ [emoji: "Invalid emoji"]
+ end
+ end)
+ end
+
+ defp valid_local_custom_emoji?(emoji) do
+ with %{file: _path} <- Emoji.get(emoji) do
+ true
+ else
+ _ -> false
+ end
end
def follow_changeset(list, attrs \\ %{}) do
list
|> cast(attrs, [:following])
|> validate_required([:following])
end
def for_user(user, _opts) do
query =
from(
l in Pleroma.List,
where: l.user_id == ^user.id,
order_by: [desc: l.id],
limit: 50
)
Repo.all(query)
end
def get(id, %{id: user_id} = _user) do
query =
from(
l in Pleroma.List,
where: l.id == ^id,
where: l.user_id == ^user_id
)
Repo.one(query)
end
def get_by_ap_id(ap_id) do
Repo.get_by(__MODULE__, ap_id: ap_id)
end
def get_following(%Pleroma.List{following: following} = _list) do
q =
from(
u in User,
where: u.follower_address in ^following
)
{:ok, Repo.all(q)}
end
# Get lists the activity should be streamed to.
def get_lists_from_activity(%Activity{actor: ap_id}) do
actor = User.get_cached_by_ap_id(ap_id)
query =
from(
l in Pleroma.List,
where: fragment("? && ?", l.following, ^[actor.follower_address])
)
Repo.all(query)
end
# Get lists to which the account belongs.
def get_lists_account_belongs(%User{} = owner, user) do
Pleroma.List
|> where([l], l.user_id == ^owner.id)
|> where([l], fragment("? = ANY(?)", ^user.follower_address, l.following))
|> Repo.all()
end
def update(%Pleroma.List{} = list, params) do
list
|> update_changeset(params)
|> Repo.update()
end
def create(params, %User{} = creator) do
changeset = update_changeset(%Pleroma.List{user_id: creator.id}, params)
if changeset.valid? do
Repo.transaction(fn ->
list = Repo.insert!(changeset)
list
|> change(ap_id: "#{creator.ap_id}/lists/#{list.id}")
|> Repo.update!()
end)
else
{:error, changeset}
end
end
def follow(%Pleroma.List{id: id}, %User{} = followed) do
list = Repo.get(Pleroma.List, id)
%{following: following} = list
update_follows(list, %{following: Enum.uniq([followed.follower_address | following])})
end
def unfollow(%Pleroma.List{id: id}, %User{} = unfollowed) do
list = Repo.get(Pleroma.List, id)
%{following: following} = list
update_follows(list, %{following: List.delete(following, unfollowed.follower_address)})
end
def delete(%Pleroma.List{} = list) do
Repo.delete(list)
end
def update_follows(%Pleroma.List{} = list, attrs) do
list
|> follow_changeset(attrs)
|> Repo.update()
end
def memberships(%User{follower_address: follower_address}) do
Pleroma.List
|> where([l], ^follower_address in l.following)
|> select([l], l.ap_id)
|> Repo.all()
end
def memberships(_), do: []
def member?(%Pleroma.List{following: following}, %User{follower_address: follower_address}) do
Enum.member?(following, follower_address)
end
def member?(_, _), do: false
def get_exclusive_list_members(%User{id: user_id}) do
Pleroma.List
|> where([l], l.user_id == ^user_id)
|> where([l], l.exclusive == true)
|> select([l], l.following)
|> Repo.all()
|> List.flatten()
|> Enum.uniq()
end
end
diff --git a/lib/pleroma/web/api_spec/operations/list_operation.ex b/lib/pleroma/web/api_spec/operations/list_operation.ex
index 87189edc2..8aec1c352 100644
--- a/lib/pleroma/web/api_spec/operations/list_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/list_operation.ex
@@ -1,217 +1,220 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 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: "Retrieve a list of 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_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)
+ 404 => Operation.response("Error", "application/json", ApiError),
+ 422 => Operation.response("Error", "application/json", ApiError)
}
}
end
def show_operation do
%Operation{
tags: ["Lists"],
summary: "Retrieve a 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: 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: "Retrieve 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(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(),
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_request do
request_body(
"Parameters",
%Schema{
description: "POST body for creating a List",
type: :object,
properties: %{
title: %Schema{type: :string, description: "List title"},
exclusive: %Schema{
type: :boolean,
description: "Whether members of the list should be removed from the “Home” feed"
- }
+ },
+ emoji: %Schema{type: :string, description: "List emoji", nullable: true}
},
required: [:title]
},
required: true
)
end
defp update_request do
request_body(
"Parameters",
%Schema{
description: "PUT body for updating a List",
type: :object,
properties: %{
title: %Schema{type: :string, description: "List title"},
exclusive: %Schema{
type: :boolean,
description: "Whether members of the list should be removed from the “Home” feed"
- }
+ },
+ emoji: %Schema{type: :string, description: "List emoji", nullable: true}
}
},
required: true
)
end
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: required
)
end
end
diff --git a/lib/pleroma/web/api_spec/schemas/list.ex b/lib/pleroma/web/api_spec/schemas/list.ex
index 5df674894..ff52b1def 100644
--- a/lib/pleroma/web/api_spec/schemas/list.ex
+++ b/lib/pleroma/web/api_spec/schemas/list.ex
@@ -1,27 +1,42 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ApiSpec.Schemas.List do
alias OpenApiSpex.Schema
require OpenApiSpex
OpenApiSpex.schema(%{
title: "List",
description: "Represents a list of users",
type: :object,
properties: %{
id: %Schema{type: :string, description: "The internal database ID of the list"},
title: %Schema{type: :string, description: "The user-defined title of the list"},
exclusive: %Schema{
type: :boolean,
description: "Whether members of the list should be removed from the “Home” feed"
+ },
+ pleroma: %Schema{
+ type: :object,
+ properties: %{
+ emoji: %Schema{type: :string, description: "List emoji", nullable: true},
+ emoji_url: %Schema{
+ type: :string,
+ description: "URL of the list emoji if it's a custom emoji, null otherwise",
+ nullable: true
+ }
+ }
}
},
example: %{
"id" => "12249",
- "title" => "Friends"
+ "title" => "Friends",
+ "pleroma" => %{
+ "emoji" => nil,
+ "emoji_url" => nil
+ }
}
})
end
diff --git a/lib/pleroma/web/mastodon_api/views/list_view.ex b/lib/pleroma/web/mastodon_api/views/list_view.ex
index 740f458d4..508169fc1 100644
--- a/lib/pleroma/web/mastodon_api/views/list_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/list_view.ex
@@ -1,20 +1,41 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ListView do
use Pleroma.Web, :view
+
+ alias Pleroma.Emoji
alias Pleroma.Web.MastodonAPI.ListView
def render("index.json", %{lists: lists} = opts) do
render_many(lists, ListView, "show.json", opts)
end
def render("show.json", %{list: list}) do
+ {emoji, emoji_url} = get_emoji(list.emoji)
+
%{
id: to_string(list.id),
title: list.title,
- exclusive: list.exclusive
+ exclusive: list.exclusive,
+ pleroma: %{
+ emoji: emoji,
+ emoji_url: emoji_url
+ }
}
end
+
+ defp get_emoji(nil), do: {nil, nil}
+
+ defp get_emoji(emoji) do
+ if Emoji.unicode?(emoji) do
+ {emoji, nil}
+ else
+ case Emoji.get(emoji) do
+ nil -> {nil, nil}
+ emoji_data -> {emoji, Emoji.local_url(emoji_data.file)}
+ end
+ end
+ end
end
diff --git a/priv/repo/migrations/20260623000000_add_emoji_to_lists.exs b/priv/repo/migrations/20260623000000_add_emoji_to_lists.exs
new file mode 100644
index 000000000..b72ff0c13
--- /dev/null
+++ b/priv/repo/migrations/20260623000000_add_emoji_to_lists.exs
@@ -0,0 +1,9 @@
+defmodule Pleroma.Repo.Migrations.AddEmojiToLists do
+ use Ecto.Migration
+
+ def change do
+ alter table(:lists) do
+ add(:emoji, :string)
+ end
+ end
+end
diff --git a/test/pleroma/list_test.exs b/test/pleroma/list_test.exs
index d44310689..32121b8fd 100644
--- a/test/pleroma/list_test.exs
+++ b/test/pleroma/list_test.exs
@@ -1,163 +1,186 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ListTest do
alias Pleroma.Repo
use Pleroma.DataCase, async: true
import Pleroma.Factory
test "creating a list" do
user = insert(:user)
{:ok, %Pleroma.List{} = list} = Pleroma.List.create(%{title: "title"}, user)
%Pleroma.List{title: title, exclusive: exclusive} = Pleroma.List.get(list.id, user)
assert title == "title"
assert exclusive == false
end
test "validates title" do
user = insert(:user)
assert {:error, changeset} = Pleroma.List.create(%{title: ""}, user)
assert changeset.errors == [title: {"can't be blank", [validation: :required]}]
end
+ test "creating a list with an emoji" do
+ user = insert(:user)
+ {:ok, %Pleroma.List{} = list} = Pleroma.List.create(%{title: "title", emoji: "🕓"}, user)
+ %Pleroma.List{emoji: emoji} = Pleroma.List.get(list.id, user)
+ assert emoji == "🕓"
+ end
+
+ test "validates emoji" do
+ user = insert(:user)
+
+ assert {:error, changeset} =
+ Pleroma.List.create(%{title: "title", emoji: "not an emoji"}, user)
+
+ assert changeset.errors == [emoji: {"Invalid emoji", []}]
+ end
+
+ test "updating a list's emoji" do
+ user = insert(:user)
+ {:ok, list} = Pleroma.List.create(%{title: "title"}, user)
+ {:ok, %{emoji: emoji}} = Pleroma.List.update(list, %{emoji: "🕓"})
+ assert "🕓" == emoji
+ end
+
test "getting a list not belonging to the user" do
user = insert(:user)
other_user = insert(:user)
{:ok, %Pleroma.List{} = list} = Pleroma.List.create(%{title: "title"}, user)
ret = Pleroma.List.get(list.id, other_user)
assert is_nil(ret)
end
test "adding an user to a list" do
user = insert(:user)
other_user = insert(:user)
{:ok, list} = Pleroma.List.create(%{title: "title"}, user)
{:ok, %{following: following}} = Pleroma.List.follow(list, other_user)
assert [other_user.follower_address] == following
end
test "removing an user from a list" do
user = insert(:user)
other_user = insert(:user)
{:ok, list} = Pleroma.List.create(%{title: "title"}, user)
{:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
{:ok, %{following: following}} = Pleroma.List.unfollow(list, other_user)
assert [] == following
end
test "renaming a list" do
user = insert(:user)
{:ok, list} = Pleroma.List.create(%{title: "title"}, user)
{:ok, %{title: title}} = Pleroma.List.update(list, %{title: "new"})
assert "new" == title
end
test "updating a list exclusivity" do
user = insert(:user)
{:ok, %{exclusive: exclusive} = list} =
Pleroma.List.create(%{title: "title", exclusive: true}, user)
assert exclusive == true
{:ok, %{exclusive: exclusive} = list} = Pleroma.List.update(list, %{exclusive: false})
assert exclusive == false
{:ok, %{exclusive: exclusive}} = Pleroma.List.update(list, %{exclusive: true})
assert exclusive == true
end
test "deleting a list" do
user = insert(:user)
{:ok, list} = Pleroma.List.create(%{title: "title"}, user)
{:ok, list} = Pleroma.List.delete(list)
assert is_nil(Repo.get(Pleroma.List, list.id))
end
test "getting users in a list" do
user = insert(:user)
other_user = insert(:user)
third_user = insert(:user)
{:ok, list} = Pleroma.List.create(%{title: "title"}, user)
{:ok, list} = Pleroma.List.follow(list, other_user)
{:ok, list} = Pleroma.List.follow(list, third_user)
{:ok, following} = Pleroma.List.get_following(list)
assert other_user in following
assert third_user in following
end
test "getting all lists by an user" do
user = insert(:user)
other_user = insert(:user)
{:ok, list_one} = Pleroma.List.create(%{title: "title"}, user)
{:ok, list_two} = Pleroma.List.create(%{title: "other title"}, user)
{:ok, list_three} = Pleroma.List.create(%{title: "third title"}, other_user)
lists = Pleroma.List.for_user(user, %{})
assert list_one in lists
assert list_two in lists
refute list_three in lists
end
test "getting all lists the user is a member of" do
user = insert(:user)
other_user = insert(:user)
{:ok, list_one} = Pleroma.List.create(%{title: "title"}, user)
{:ok, list_two} = Pleroma.List.create(%{title: "other title"}, user)
{:ok, list_three} = Pleroma.List.create(%{title: "third title"}, other_user)
{:ok, list_one} = Pleroma.List.follow(list_one, other_user)
{:ok, list_two} = Pleroma.List.follow(list_two, other_user)
{:ok, list_three} = Pleroma.List.follow(list_three, user)
lists = Pleroma.List.get_lists_from_activity(%Pleroma.Activity{actor: other_user.ap_id})
assert list_one in lists
assert list_two in lists
refute list_three in lists
end
test "getting own lists a given user belongs to" do
owner = insert(:user)
not_owner = insert(:user)
member_1 = insert(:user)
member_2 = insert(:user)
{:ok, owned_list} = Pleroma.List.create(%{title: "owned"}, owner)
{:ok, not_owned_list} = Pleroma.List.create(%{title: "not owned"}, not_owner)
{:ok, owned_list} = Pleroma.List.follow(owned_list, member_1)
{:ok, owned_list} = Pleroma.List.follow(owned_list, member_2)
{:ok, not_owned_list} = Pleroma.List.follow(not_owned_list, member_1)
{:ok, not_owned_list} = Pleroma.List.follow(not_owned_list, member_2)
lists_1 = Pleroma.List.get_lists_account_belongs(owner, member_1)
assert owned_list in lists_1
refute not_owned_list in lists_1
lists_2 = Pleroma.List.get_lists_account_belongs(owner, member_2)
assert owned_list in lists_2
refute not_owned_list in lists_2
end
test "get by ap_id" do
user = insert(:user)
{:ok, list} = Pleroma.List.create(%{title: "foo"}, user)
assert Pleroma.List.get_by_ap_id(list.ap_id) == list
end
test "memberships" do
user = insert(:user)
member = insert(:user)
{:ok, list} = Pleroma.List.create(%{title: "foo"}, user)
{:ok, list} = Pleroma.List.follow(list, member)
assert Pleroma.List.memberships(member) == [list.ap_id]
end
test "member?" do
user = insert(:user)
member = insert(:user)
{:ok, list} = Pleroma.List.create(%{title: "foo"}, user)
{:ok, list} = Pleroma.List.follow(list, member)
assert Pleroma.List.member?(list, member)
refute Pleroma.List.member?(list, user)
end
end
diff --git a/test/pleroma/web/mastodon_api/controllers/list_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/list_controller_test.exs
index bfda48be4..2845f67ed 100644
--- a/test/pleroma/web/mastodon_api/controllers/list_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/list_controller_test.exs
@@ -1,185 +1,218 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ListControllerTest do
use Pleroma.Web.ConnCase, async: true
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 "creating a list with an emoji" do
+ %{conn: conn} = oauth_access(["write:lists"])
+
+ assert %{"title" => "cuties", "pleroma" => %{"emoji" => "🕓", "emoji_url" => nil}} =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/lists", %{"title" => "cuties", "emoji" => "🕓"})
+ |> 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 "renders error for an invalid emoji" do
+ %{conn: conn} = oauth_access(["write:lists"])
+
+ conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/lists", %{"title" => "cuties", "emoji" => "not an emoji"})
+
+ assert %{"error" => "Invalid emoji"} =
+ json_response_and_validate_schema(conn, :unprocessable_entity)
+ 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)
third_user = insert(:user)
{:ok, list} = Pleroma.List.create(%{title: "name"}, user)
assert %{} ==
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/lists/#{list.id}/accounts", %{
"account_ids" => [other_user.id, third_user.id]
})
|> json_response_and_validate_schema(:ok)
%Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
assert length(following) == 2
assert other_user.follower_address in following
assert third_user.follower_address in following
end
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)
fourth_user = insert(:user)
{:ok, list} = Pleroma.List.create(%{title: "name"}, user)
{:ok, list} = Pleroma.List.follow(list, other_user)
{:ok, list} = Pleroma.List.follow(list, third_user)
{:ok, list} = Pleroma.List.follow(list, fourth_user)
assert %{} ==
conn
|> put_req_header("content-type", "application/json")
|> delete("/api/v1/lists/#{list.id}/accounts", %{
"account_ids" => [other_user.id, fourth_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(%{title: "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(%{title: "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(%{title: "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(%{title: "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 "updating a list's emoji" do
+ %{user: user, conn: conn} = oauth_access(["write:lists"])
+ {:ok, list} = Pleroma.List.create(%{title: "name"}, user)
+
+ assert %{"pleroma" => %{"emoji" => "🕓", "emoji_url" => nil}} =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> put("/api/v1/lists/#{list.id}", %{"title" => "name", "emoji" => "🕓"})
+ |> 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(%{title: "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(%{title: "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
diff --git a/test/pleroma/web/mastodon_api/views/list_view_test.exs b/test/pleroma/web/mastodon_api/views/list_view_test.exs
index ae0593b6b..86f461ded 100644
--- a/test/pleroma/web/mastodon_api/views/list_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/list_view_test.exs
@@ -1,36 +1,52 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ListViewTest do
use Pleroma.DataCase, async: true
import Pleroma.Factory
alias Pleroma.Web.MastodonAPI.ListView
test "show" do
user = insert(:user)
title = "mortal enemies"
{:ok, list} = Pleroma.List.create(%{title: title}, user)
expected = %{
id: to_string(list.id),
title: title,
- exclusive: false
+ exclusive: false,
+ pleroma: %{
+ emoji: nil,
+ emoji_url: nil
+ }
}
assert expected == ListView.render("show.json", %{list: list})
end
+ test "show with a unicode emoji" do
+ user = insert(:user)
+ {:ok, list} = Pleroma.List.create(%{title: "mortal enemies", emoji: "🕓"}, user)
+
+ assert %{
+ pleroma: %{
+ emoji: "🕓",
+ emoji_url: nil
+ }
+ } = ListView.render("show.json", %{list: list})
+ end
+
test "index" do
user = insert(:user)
{:ok, list} = Pleroma.List.create(%{title: "my list", exclusive: false}, user)
{:ok, list2} = Pleroma.List.create(%{title: "cofe", exclusive: true}, user)
assert [
%{id: _, title: "my list", exclusive: false},
%{id: _, title: "cofe", exclusive: true}
] =
ListView.render("index.json", lists: [list, list2])
end
end

File Metadata

Mime Type
text/x-diff
Expires
Sat, Jul 18, 11:52 PM (1 d, 8 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1695165
Default Alt Text
(32 KB)

Event Timeline