Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85595406
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
32 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rPUBE pleroma-upstream
Attached
Detach File
Event Timeline
Log In to Comment