Federate user profile background

Currently our own frontend doesn’t show backgrounds of other users, this
property is already publicly readable via REST API and likely was always
intended to be shown and federated.

Recently Sharkey added support for profile backgrounds and
immediately made them federate and be displayed to others.
We use the same AP field as Sharkey here which should make
it interoperable both ways out-of-the-box.

Ref.: 4e64397635
This commit is contained in:
Oneric 2024-02-09 21:03:02 +01:00
parent 0ed815b8a1
commit 7622aa27ca
6 changed files with 29 additions and 3 deletions

View file

@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- OTP builds are now built on erlang OTP26 - OTP builds are now built on erlang OTP26
- The base Phoenix framework is now updated to 1.7 - The base Phoenix framework is now updated to 1.7
- An `outbox` field has been added to actor profiles to comply with AP spec - An `outbox` field has been added to actor profiles to comply with AP spec
- User profile backgrounds do now federate with other Akkoma instances and Sharkey
## Fixed ## Fixed
- Documentation issue in which a non-existing nginx file was referenced - Documentation issue in which a non-existing nginx file was referenced

View file

@ -382,6 +382,10 @@ defmodule Pleroma.User do
do_optional_url(user.banner, "#{Endpoint.url()}/images/banner.png", options) do_optional_url(user.banner, "#{Endpoint.url()}/images/banner.png", options)
end end
def background_url(user) do
do_optional_url(user.background, nil, no_default: true)
end
defp do_optional_url(field, default, options) do defp do_optional_url(field, default, options) do
case field do case field do
%{"url" => [%{"href" => href} | _]} when is_binary(href) -> %{"url" => [%{"href" => href} | _]} when is_binary(href) ->
@ -466,6 +470,7 @@ defmodule Pleroma.User do
:avatar, :avatar,
:ap_enabled, :ap_enabled,
:banner, :banner,
:background,
:is_locked, :is_locked,
:last_refreshed_at, :last_refreshed_at,
:uri, :uri,

View file

@ -1603,6 +1603,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
uri: get_actor_url(data["url"]), uri: get_actor_url(data["url"]),
ap_enabled: true, ap_enabled: true,
banner: normalize_image(data["image"]), banner: normalize_image(data["image"]),
background: normalize_image(data["backgroundUrl"]),
fields: fields, fields: fields,
emoji: emojis, emoji: emojis,
is_locked: is_locked, is_locked: is_locked,

View file

@ -112,6 +112,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do
} }
|> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user)) |> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user))
|> Map.merge(maybe_make_image(&User.banner_url/2, "image", user)) |> Map.merge(maybe_make_image(&User.banner_url/2, "image", user))
# Yes, the key is named ...Url eventhough it is a whole 'Image' object
|> Map.merge(maybe_insert_image("backgroundUrl", User.background_url(user)))
|> Map.merge(Utils.make_json_ld_header()) |> Map.merge(Utils.make_json_ld_header())
end end
@ -287,7 +289,12 @@ defmodule Pleroma.Web.ActivityPub.UserView do
end end
defp maybe_make_image(func, key, user) do defp maybe_make_image(func, key, user) do
if image = func.(user, no_default: true) do image = func.(user, no_default: true)
maybe_insert_image(key, image)
end
defp maybe_insert_image(key, image) do
if image do
%{ %{
key => %{ key => %{
"type" => "Image", "type" => "Image",

View file

@ -155,7 +155,13 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
user = insert(:user, local: false) user = insert(:user, local: false)
{:ok, update_data, []} = {:ok, update_data, []} =
Builder.update(user, %{"id" => user.ap_id, "type" => "Person", "name" => "new name!"}) Builder.update(user, %{
"id" => user.ap_id,
"type" => "Person",
"name" => "new name!",
"icon" => %{"type" => "Image", "url" => "https://example.org/icon.png"},
"backgroundUrl" => %{"type" => "Image", "url" => "https://example.org/bg.jxl"}
})
{:ok, update, _meta} = ActivityPub.persist(update_data, local: true) {:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
@ -165,7 +171,10 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
test "it updates the user", %{user: user, update: update} do test "it updates the user", %{user: user, update: update} do
{:ok, _, _} = SideEffects.handle(update) {:ok, _, _} = SideEffects.handle(update)
user = User.get_by_id(user.id) user = User.get_by_id(user.id)
assert user.name == "new name!" assert user.name == "new name!"
assert [%{"href" => "https://example.org/icon.png"}] = user.avatar["url"]
assert [%{"href" => "https://example.org/bg.jxl"}] = user.background["url"]
end end
test "it uses a given changeset to update", %{user: user, update: update} do test "it uses a given changeset to update", %{user: user, update: update} do

View file

@ -58,16 +58,19 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
result = UserView.render("user.json", %{user: user}) result = UserView.render("user.json", %{user: user})
refute result["icon"] refute result["icon"]
refute result["image"] refute result["image"]
refute result["backgroundUrl"]
user = user =
insert(:user, insert(:user,
avatar: %{"url" => [%{"href" => "https://someurl"}]}, avatar: %{"url" => [%{"href" => "https://someurl"}]},
banner: %{"url" => [%{"href" => "https://somebanner"}]} banner: %{"url" => [%{"href" => "https://somebanner"}]},
background: %{"url" => [%{"href" => "https://somebackground"}]}
) )
result = UserView.render("user.json", %{user: user}) result = UserView.render("user.json", %{user: user})
assert result["icon"]["url"] == "https://someurl" assert result["icon"]["url"] == "https://someurl"
assert result["image"]["url"] == "https://somebanner" assert result["image"]["url"] == "https://somebanner"
assert result["backgroundUrl"]["url"] == "https://somebackground"
end end
test "renders an invisible user with the invisible property set to true" do test "renders an invisible user with the invisible property set to true" do