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:
parent
0ed815b8a1
commit
7622aa27ca
6 changed files with 29 additions and 3 deletions
|
@ -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
|
||||||
|
|
|
@ -382,6 +382,10 @@ def banner_url(user, options \\ []) 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 @@ def remote_user_changeset(struct \\ %User{local: false}, params) do
|
||||||
:avatar,
|
:avatar,
|
||||||
:ap_enabled,
|
:ap_enabled,
|
||||||
:banner,
|
:banner,
|
||||||
|
:background,
|
||||||
:is_locked,
|
:is_locked,
|
||||||
:last_refreshed_at,
|
:last_refreshed_at,
|
||||||
:uri,
|
:uri,
|
||||||
|
|
|
@ -1603,6 +1603,7 @@ defp object_to_user_data(data, additional) 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,
|
||||||
|
|
|
@ -112,6 +112,8 @@ def render("user.json", %{user: user}) 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 @@ def collection(collection, iri, page, show_items \\ true, total \\ nil) 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",
|
||||||
|
|
|
@ -155,7 +155,13 @@ test "it blocks but does not unfollow if the relevant setting is set", %{
|
||||||
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 @@ test "it blocks but does not unfollow if the relevant setting is set", %{
|
||||||
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
|
||||||
|
|
|
@ -58,16 +58,19 @@ test "Does not add an avatar image if the user hasn't set one" 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
|
||||||
|
|
Loading…
Reference in a new issue