1
0
Fork 0
mirror of https://git.pleroma.social/pleroma/pleroma.git synced 2026-02-15 17:16:57 +00:00

Support isCat and speakAsCat

Signed-off-by: Nicole Mikołajczyk <git@mkljczk.pl>
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
Nicole Mikołajczyk 2025-04-03 11:14:06 +02:00 committed by nicole mikołajczyk
parent 8f9a139ba1
commit 327ad3f932
14 changed files with 207 additions and 12 deletions

1
changelog.d/cat-ears.add Normal file
View file

@ -0,0 +1 @@
Support `isCat` and `speakAsCat`

View file

@ -162,6 +162,8 @@ defmodule Pleroma.User do
field(:birthday, :date)
field(:show_birthday, :boolean, default: false)
field(:language, :string)
field(:is_cat, :boolean, default: false)
field(:speak_as_cat, :boolean, default: false)
embeds_one(
:notification_settings,
@ -527,7 +529,9 @@ defmodule Pleroma.User do
:accepts_chat_messages,
:pinned_objects,
:birthday,
:show_birthday
:show_birthday,
:is_cat,
:speak_as_cat
]
)
|> cast(params, [:name], empty_values: [])
@ -590,7 +594,9 @@ defmodule Pleroma.User do
:accepts_chat_messages,
:disclose_client,
:birthday,
:show_birthday
:show_birthday,
:is_cat,
:speak_as_cat
]
)
|> validate_min_age()

View file

@ -1635,6 +1635,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
show_birthday = !!birthday
is_cat = Map.get(data, "isCat", false)
speak_as_cat = Map.get(data, "speakAsCat", is_cat)
# if WebFinger request was already done, we probably have acct, otherwise
# we request WebFinger here
nickname = additional[:nickname_from_acct] || generate_nickname(data)
@ -1663,7 +1666,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
birthday: birthday,
show_birthday: show_birthday,
pinned_objects: pinned_objects,
nickname: nickname
nickname: nickname,
is_cat: is_cat,
speak_as_cat: speak_as_cat
}
end

View file

@ -128,7 +128,9 @@ defmodule Pleroma.Web.ActivityPub.UserView do
"alsoKnownAs" => user.also_known_as,
"vcard:bday" => birthday,
"webfinger" => "acct:#{User.full_nickname(user)}",
"published" => Pleroma.Web.CommonAPI.Utils.to_masto_date(user.inserted_at)
"published" => Pleroma.Web.CommonAPI.Utils.to_masto_date(user.inserted_at),
"isCat" => user.is_cat,
"speakAsCat" => user.speak_as_cat
}
|> Map.merge(
maybe_make_image(

View file

@ -838,6 +838,16 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
type: :string,
nullable: true,
description: "Header image description."
},
is_cat: %Schema{
type: :boolean,
nullable: true,
description: "Whether the user is a cat"
},
speak_as_cat: %Schema{
type: :boolean,
nullable: true,
description: "Whether the user speaks as a cat"
}
},
example: %{

View file

@ -114,7 +114,17 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
description: "Favicon image of the user's instance"
},
avatar_description: %Schema{type: :string},
header_description: %Schema{type: :string}
header_description: %Schema{type: :string},
is_cat: %Schema{
type: :boolean,
nullable: true,
description: "Whether the user is a cat"
},
speak_as_cat: %Schema{
type: :boolean,
nullable: true,
description: "Whether the user speaks as a cat"
}
}
},
source: %Schema{
@ -211,7 +221,9 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
"settings_store" => %{
"pleroma-fe" => %{}
},
"birthday" => "2001-02-12"
"birthday" => "2001-02-12",
"is_cat" => true,
"speak_as_cat" => true
},
"source" => %{
"fields" => [],

View file

@ -202,7 +202,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
:allow_following_move,
:also_known_as,
:accepts_chat_messages,
:show_birthday
:show_birthday,
:is_cat,
:speak_as_cat
]
|> Enum.reduce(%{}, fn key, acc ->
Maps.put_if_present(acc, key, params[key], &{:ok, Params.truthy_param?(&1)})

View file

@ -325,7 +325,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
accepts_chat_messages: user.accepts_chat_messages,
favicon: favicon,
avatar_description: avatar_description,
header_description: header_description
header_description: header_description,
is_cat: user.is_cat,
speak_as_cat: user.speak_as_cat
}
}
|> maybe_put_role(user, opts[:for])

View file

@ -158,7 +158,8 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
if Pleroma.Language.LanguageDetector.configured?() do
"pleroma:language_detection"
end,
"pleroma:block_expiration"
"pleroma:block_expiration",
"pleroma:is_cat"
]
|> Enum.filter(& &1)
end

View file

@ -0,0 +1,10 @@
defmodule Pleroma.Repo.Migrations.AddIsCatToUsers do
use Ecto.Migration
def change do
alter table(:users) do
add_if_not_exists(:is_cat, :boolean, default: false)
add_if_not_exists(:speak_as_cat, :boolean, default: false)
end
end
end

View file

@ -43,7 +43,11 @@
"vcard": "http://www.w3.org/2006/vcard/ns#",
"formerRepresentations": "litepub:formerRepresentations",
"sm": "http://smithereen.software/ns#",
"nonAnonymous": "sm:nonAnonymous"
"nonAnonymous": "sm:nonAnonymous",
"misskey": "https://misskey-hub.net/ns#",
"isCat": "misskey:isCat",
"firefish": "https://joinfirefish.org/ns#",
"speakAsCat": "firefish:speakAsCat"
}
]
}

View file

@ -2754,4 +2754,112 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
"first" => "https://social.example/users/alice/collections/featured?page=true"
})
end
describe "cat ears" do
test "it respects isCat and speakAsCat" do
cat_id = "https://example.com/users/cat"
cat_data =
"test/fixtures/users_mock/user.json"
|> File.read!()
|> String.replace("{{nickname}}", "cat")
|> Jason.decode!()
|> Map.delete("featured")
|> Map.put("isCat", true)
|> Map.put("speakAsCat", true)
|> Jason.encode!()
dog_id = "https://example.com/users/dog"
dog_data =
"test/fixtures/users_mock/user.json"
|> File.read!()
|> String.replace("{{nickname}}", "dog")
|> Jason.decode!()
|> Map.delete("featured")
|> Map.put("isCat", false)
|> Map.put("speakAsCat", false)
|> Jason.encode!()
Tesla.Mock.mock(fn
%{
method: :get,
url: ^cat_id
} ->
%Tesla.Env{
status: 200,
body: cat_data,
headers: [{"content-type", "application/activity+json"}]
}
%{
method: :get,
url: ^dog_id
} ->
%Tesla.Env{
status: 200,
body: dog_data,
headers: [{"content-type", "application/activity+json"}]
}
end)
{:ok, cat} = ActivityPub.make_user_from_ap_id(cat_id)
{:ok, dog} = ActivityPub.make_user_from_ap_id(dog_id)
assert %{is_cat: true, speak_as_cat: true} = cat
assert %{is_cat: false, speak_as_cat: false} = dog
end
test "it infers speakAsCat from isCat, when missing" do
cat_id = "https://example.com/users/cat"
cat_data =
"test/fixtures/users_mock/user.json"
|> File.read!()
|> String.replace("{{nickname}}", "cat")
|> Jason.decode!()
|> Map.delete("featured")
|> Map.put("isCat", true)
|> Jason.encode!()
dog_id = "https://example.com/users/dog"
dog_data =
"test/fixtures/users_mock/user.json"
|> File.read!()
|> String.replace("{{nickname}}", "dog")
|> Jason.decode!()
|> Map.delete("featured")
|> Map.put("isCat", false)
|> Jason.encode!()
Tesla.Mock.mock(fn
%{
method: :get,
url: ^cat_id
} ->
%Tesla.Env{
status: 200,
body: cat_data,
headers: [{"content-type", "application/activity+json"}]
}
%{
method: :get,
url: ^dog_id
} ->
%Tesla.Env{
status: 200,
body: dog_data,
headers: [{"content-type", "application/activity+json"}]
}
end)
{:ok, cat} = ActivityPub.make_user_from_ap_id(cat_id)
{:ok, dog} = ActivityPub.make_user_from_ap_id(dog_id)
assert %{is_cat: true, speak_as_cat: true} = cat
assert %{is_cat: false, speak_as_cat: false} = dog
end
end
end

View file

@ -823,4 +823,19 @@ defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do
assert account["source"]["pleroma"]["actor_type"] == "Group"
end
end
describe "cat ears" do
setup do: oauth_access(["write:accounts"])
setup :request_content_type
test "sets cat ears preferences", %{conn: conn} do
account =
conn
|> patch("/api/v1/accounts/update_credentials", %{is_cat: true, speak_as_cat: false})
|> json_response_and_validate_schema(200)
assert account["pleroma"]["is_cat"]
assert not account["pleroma"]["speak_as_cat"]
end
end
end

View file

@ -98,7 +98,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
skip_thread_containment: false,
accepts_chat_messages: nil,
avatar_description: "",
header_description: ""
header_description: "",
is_cat: false,
speak_as_cat: false
}
}
@ -344,7 +346,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
skip_thread_containment: false,
accepts_chat_messages: nil,
avatar_description: "",
header_description: ""
header_description: "",
is_cat: false,
speak_as_cat: false
}
}
@ -845,4 +849,17 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
DateTime.utc_now() |> DateTime.add(24 * 60 * 60)
) in -3..3
end
test "renders isCat and speakAsCat" do
cat = insert(:user, is_cat: true, speak_as_cat: true)
dog = insert(:user, is_cat: false, speak_as_cat: false)
%{
pleroma: %{is_cat: true, speak_as_cat: true}
} = AccountView.render("show.json", %{user: cat, skip_visibility_check: true})
%{
pleroma: %{is_cat: false, speak_as_cat: false}
} = AccountView.render("show.json", %{user: dog, skip_visibility_check: true})
end
end