From f6d09fafee83514889bbcf6531e0bc01e33b0b16 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sun, 1 Mar 2020 09:48:32 +0100 Subject: [PATCH 1/6] Add support for remote favicons --- lib/pleroma/user.ex | 30 +++++++++++++++++++ .../web/mastodon_api/views/account_view.ex | 3 +- test/support/http_request_mock.ex | 4 +++ .../mastodon_api/views/account_view_test.exs | 2 ++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index e98332744..25ea112a2 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -2253,4 +2253,34 @@ def sanitize_html(%User{} = user, filter) do |> Map.put(:bio, HTML.filter_tags(user.bio, filter)) |> Map.put(:fields, fields) end + + def get_cached_favicon(%User{} = user) do + key = "favicon:#{user.ap_id}" + Cachex.fetch!(:user_cache, key, fn _ -> get_favicon(user) end) + end + + def get_cached_favicon(_user) do + nil + end + + def get_favicon(user) do + try do + with url <- user.ap_id, + true <- is_binary(url), + {:ok, %Tesla.Env{body: html}} <- Pleroma.HTTP.get(url), + favicon_rel <- + html + |> Floki.parse_document!() + |> Floki.attribute("link[rel=icon]", "href") + |> List.first(), + favicon_url <- URI.merge(URI.parse(url), favicon_rel) |> to_string(), + true <- is_binary(favicon_url) do + favicon_url + else + _ -> nil + end + rescue + _ -> nil + end + end end diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index a6e64b4ab..efe835e3c 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -245,7 +245,8 @@ defp do_render("show.json", %{user: user} = opts) do hide_favorites: user.hide_favorites, relationship: relationship, skip_thread_containment: user.skip_thread_containment, - background_image: image_url(user.background) |> MediaProxy.url() + background_image: image_url(user.background) |> MediaProxy.url(), + favicon: User.get_cached_favicon(user) |> MediaProxy.url() } } |> maybe_put_role(user, opts[:for]) diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index da04ac6f1..4d33c6250 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -1342,6 +1342,10 @@ def get("https://relay.mastodon.host/actor", _, _, _) do {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/relay/relay.json")}} end + def get("http://localhost:4001/users/" <> _, _, _, _) do + {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/7369654.html")}} + end + def get(url, query, body, headers) do {:error, "Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{ diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs index 80b1f734c..e01a7c1ee 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -75,6 +75,7 @@ test "Represent a user account" do pleroma: %{ ap_id: user.ap_id, background_image: "https://example.com/images/asuka_hospital.png", + favicon: nil, confirmation_pending: false, tags: [], is_admin: false, @@ -152,6 +153,7 @@ test "Represent a Service(bot) account" do pleroma: %{ ap_id: user.ap_id, background_image: nil, + favicon: nil, confirmation_pending: false, tags: [], is_admin: false, From 6a679d80c9030afa8327377928f8ac2fcf1a4a0e Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Mon, 2 Mar 2020 05:38:25 +0100 Subject: [PATCH 2/6] Move get_favicon to Pleroma.Instances, use / --- lib/pleroma/application.ex | 1 + lib/pleroma/instances.ex | 28 ++ lib/pleroma/user.ex | 30 -- .../web/mastodon_api/views/account_view.ex | 11 +- .../https___osada.macgirvin.com.html | 301 ++++++++++++++++++ test/support/http_request_mock.ex | 10 +- .../mastodon_api/views/account_view_test.exs | 6 +- 7 files changed, 353 insertions(+), 34 deletions(-) create mode 100644 test/fixtures/tesla_mock/https___osada.macgirvin.com.html diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 9615af122..c7fc95f75 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -150,6 +150,7 @@ defp cachex_children do build_cachex("emoji_packs", expiration: emoji_packs_expiration(), limit: 10), build_cachex("failed_proxy_url", limit: 2500), build_cachex("banned_urls", default_ttl: :timer.hours(24 * 30), limit: 5_000) + build_cachex("instances", default_ttl: 25_000, ttl_interval: 1000, limit: 2500) ] end diff --git a/lib/pleroma/instances.ex b/lib/pleroma/instances.ex index 557e8decf..c9b1ed4ce 100644 --- a/lib/pleroma/instances.ex +++ b/lib/pleroma/instances.ex @@ -37,4 +37,32 @@ def host(url_or_host) when is_binary(url_or_host) do url_or_host end end + + def get_cached_favicon(instance_url) when is_binary(instance_url) do + Cachex.fetch!(:instances_cache, instance_url, fn _ -> get_favicon(instance_url) end) + end + + def get_cached_favicon(_instance_url) do + nil + end + + def get_favicon(instance_url) when is_binary(instance_url) do + try do + with {:ok, %Tesla.Env{body: html}} <- + Pleroma.HTTP.get(instance_url, [{:Accept, "text/html"}]), + favicon_rel <- + html + |> Floki.parse_document!() + |> Floki.attribute("link[rel=icon]", "href") + |> List.first(), + favicon_url <- URI.merge(URI.parse(instance_url), favicon_rel) |> to_string(), + true <- is_binary(favicon_url) do + favicon_url + else + _ -> nil + end + rescue + _ -> nil + end + end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 25ea112a2..e98332744 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -2253,34 +2253,4 @@ def sanitize_html(%User{} = user, filter) do |> Map.put(:bio, HTML.filter_tags(user.bio, filter)) |> Map.put(:fields, fields) end - - def get_cached_favicon(%User{} = user) do - key = "favicon:#{user.ap_id}" - Cachex.fetch!(:user_cache, key, fn _ -> get_favicon(user) end) - end - - def get_cached_favicon(_user) do - nil - end - - def get_favicon(user) do - try do - with url <- user.ap_id, - true <- is_binary(url), - {:ok, %Tesla.Env{body: html}} <- Pleroma.HTTP.get(url), - favicon_rel <- - html - |> Floki.parse_document!() - |> Floki.attribute("link[rel=icon]", "href") - |> List.first(), - favicon_url <- URI.merge(URI.parse(url), favicon_rel) |> to_string(), - true <- is_binary(favicon_url) do - favicon_url - else - _ -> nil - end - rescue - _ -> nil - end - end end diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index efe835e3c..3ee50dfd0 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -204,6 +204,15 @@ defp do_render("show.json", %{user: user} = opts) do %{} end + favicon = + user + |> Map.get(:ap_id, "") + |> URI.parse() + |> URI.merge("/") + |> to_string() + |> Pleroma.Instances.get_cached_favicon() + |> MediaProxy.url() + %{ id: to_string(user.id), username: username_from_nickname(user.nickname), @@ -246,7 +255,7 @@ defp do_render("show.json", %{user: user} = opts) do relationship: relationship, skip_thread_containment: user.skip_thread_containment, background_image: image_url(user.background) |> MediaProxy.url(), - favicon: User.get_cached_favicon(user) |> MediaProxy.url() + favicon: favicon } } |> maybe_put_role(user, opts[:for]) diff --git a/test/fixtures/tesla_mock/https___osada.macgirvin.com.html b/test/fixtures/tesla_mock/https___osada.macgirvin.com.html new file mode 100644 index 000000000..880273d74 --- /dev/null +++ b/test/fixtures/tesla_mock/https___osada.macgirvin.com.html @@ -0,0 +1,301 @@ + + + + Osada + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +

Welcome to Osada

+ +
+
+
+ + + +
+
+ + +
+
+ +
+ +
+ +
+ +
+ Remote Authentication +
+ +
+ + + +
+
+ +
+
+ + + + \ No newline at end of file diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index 4d33c6250..19a202654 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -1342,10 +1342,18 @@ def get("https://relay.mastodon.host/actor", _, _, _) do {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/relay/relay.json")}} end - def get("http://localhost:4001/users/" <> _, _, _, _) do + def get("http://localhost:4001/", _, "", Accept: "text/html") do {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/7369654.html")}} end + def get("https://osada.macgirvin.com/", _, "", Accept: "text/html") do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/https___osada.macgirvin.com.html") + }} + end + def get(url, query, body, headers) do {:error, "Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{ diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs index e01a7c1ee..c4341cb28 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -75,7 +75,8 @@ test "Represent a user account" do pleroma: %{ ap_id: user.ap_id, background_image: "https://example.com/images/asuka_hospital.png", - favicon: nil, + favicon: + "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png", confirmation_pending: false, tags: [], is_admin: false, @@ -153,7 +154,8 @@ test "Represent a Service(bot) account" do pleroma: %{ ap_id: user.ap_id, background_image: nil, - favicon: nil, + favicon: + "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png", confirmation_pending: false, tags: [], is_admin: false, From 013e2c505786dff311bcc8bf23631d6a1a1636ef Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 7 Jul 2020 11:13:38 +0200 Subject: [PATCH 3/6] Use instances table instead of Cachex --- lib/pleroma/application.ex | 1 - lib/pleroma/instances.ex | 28 ---------- lib/pleroma/instances/instance.ex | 55 ++++++++++++++++++- .../web/mastodon_api/views/account_view.ex | 3 +- .../20200707112859_instances_add_favicon.exs | 10 ++++ 5 files changed, 65 insertions(+), 32 deletions(-) create mode 100644 priv/repo/migrations/20200707112859_instances_add_favicon.exs diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index c7fc95f75..9615af122 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -150,7 +150,6 @@ defp cachex_children do build_cachex("emoji_packs", expiration: emoji_packs_expiration(), limit: 10), build_cachex("failed_proxy_url", limit: 2500), build_cachex("banned_urls", default_ttl: :timer.hours(24 * 30), limit: 5_000) - build_cachex("instances", default_ttl: 25_000, ttl_interval: 1000, limit: 2500) ] end diff --git a/lib/pleroma/instances.ex b/lib/pleroma/instances.ex index c9b1ed4ce..557e8decf 100644 --- a/lib/pleroma/instances.ex +++ b/lib/pleroma/instances.ex @@ -37,32 +37,4 @@ def host(url_or_host) when is_binary(url_or_host) do url_or_host end end - - def get_cached_favicon(instance_url) when is_binary(instance_url) do - Cachex.fetch!(:instances_cache, instance_url, fn _ -> get_favicon(instance_url) end) - end - - def get_cached_favicon(_instance_url) do - nil - end - - def get_favicon(instance_url) when is_binary(instance_url) do - try do - with {:ok, %Tesla.Env{body: html}} <- - Pleroma.HTTP.get(instance_url, [{:Accept, "text/html"}]), - favicon_rel <- - html - |> Floki.parse_document!() - |> Floki.attribute("link[rel=icon]", "href") - |> List.first(), - favicon_url <- URI.merge(URI.parse(instance_url), favicon_rel) |> to_string(), - true <- is_binary(favicon_url) do - favicon_url - else - _ -> nil - end - rescue - _ -> nil - end - end end diff --git a/lib/pleroma/instances/instance.ex b/lib/pleroma/instances/instance.ex index 74458c09a..b97e229e5 100644 --- a/lib/pleroma/instances/instance.ex +++ b/lib/pleroma/instances/instance.ex @@ -17,6 +17,8 @@ defmodule Pleroma.Instances.Instance do schema "instances" do field(:host, :string) field(:unreachable_since, :naive_datetime_usec) + field(:favicon, :string) + field(:favicon_updated_at, :naive_datetime) timestamps() end @@ -25,7 +27,7 @@ defmodule Pleroma.Instances.Instance do def changeset(struct, params \\ %{}) do struct - |> cast(params, [:host, :unreachable_since]) + |> cast(params, [:host, :unreachable_since, :favicon, :favicon_updated_at]) |> validate_required([:host]) |> unique_constraint(:host) end @@ -120,4 +122,55 @@ defp parse_datetime(datetime) when is_binary(datetime) do end defp parse_datetime(datetime), do: datetime + + def get_or_update_favicon(%URI{host: host} = instance_uri) do + existing_record = Repo.get_by(Instance, %{host: host}) + now = NaiveDateTime.utc_now() + + if existing_record && existing_record.favicon && + NaiveDateTime.diff(now, existing_record.favicon_updated_at) < 86_400 do + existing_record.favicon + else + favicon = scrape_favicon(instance_uri) + + cond do + is_binary(favicon) && existing_record -> + existing_record + |> changeset(%{favicon: favicon, favicon_updated_at: now}) + |> Repo.update() + + favicon + + is_binary(favicon) -> + %Instance{} + |> changeset(%{host: host, favicon: favicon, favicon_updated_at: now}) + |> Repo.insert() + + favicon + + true -> + nil + end + end + end + + defp scrape_favicon(%URI{} = instance_uri) do + try do + with {:ok, %Tesla.Env{body: html}} <- + Pleroma.HTTP.get(to_string(instance_uri), [{:Accept, "text/html"}]), + favicon_rel <- + html + |> Floki.parse_document!() + |> Floki.attribute("link[rel=icon]", "href") + |> List.first(), + favicon <- URI.merge(instance_uri, favicon_rel) |> to_string(), + true <- is_binary(favicon) do + favicon + else + _ -> nil + end + rescue + _ -> nil + end + end end diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 3ee50dfd0..db5739254 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -209,8 +209,7 @@ defp do_render("show.json", %{user: user} = opts) do |> Map.get(:ap_id, "") |> URI.parse() |> URI.merge("/") - |> to_string() - |> Pleroma.Instances.get_cached_favicon() + |> Pleroma.Instances.Instance.get_or_update_favicon() |> MediaProxy.url() %{ diff --git a/priv/repo/migrations/20200707112859_instances_add_favicon.exs b/priv/repo/migrations/20200707112859_instances_add_favicon.exs new file mode 100644 index 000000000..5538749dc --- /dev/null +++ b/priv/repo/migrations/20200707112859_instances_add_favicon.exs @@ -0,0 +1,10 @@ +defmodule Pleroma.Repo.Migrations.InstancesAddFavicon do + use Ecto.Migration + + def change do + alter table(:instances) do + add(:favicon, :string) + add(:favicon_updated_at, :naive_datetime) + end + end +end From 8c9df2d2e6a5a3639f6b411cd3e9b57248a0650c Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 7 Jul 2020 12:07:30 +0200 Subject: [PATCH 4/6] instance: Prevent loop of updates --- lib/pleroma/instances/instance.ex | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/lib/pleroma/instances/instance.ex b/lib/pleroma/instances/instance.ex index b97e229e5..a1f935232 100644 --- a/lib/pleroma/instances/instance.ex +++ b/lib/pleroma/instances/instance.ex @@ -127,30 +127,23 @@ def get_or_update_favicon(%URI{host: host} = instance_uri) do existing_record = Repo.get_by(Instance, %{host: host}) now = NaiveDateTime.utc_now() - if existing_record && existing_record.favicon && + if existing_record && existing_record.favicon_updated_at && NaiveDateTime.diff(now, existing_record.favicon_updated_at) < 86_400 do existing_record.favicon else favicon = scrape_favicon(instance_uri) - cond do - is_binary(favicon) && existing_record -> - existing_record - |> changeset(%{favicon: favicon, favicon_updated_at: now}) - |> Repo.update() - - favicon - - is_binary(favicon) -> - %Instance{} - |> changeset(%{host: host, favicon: favicon, favicon_updated_at: now}) - |> Repo.insert() - - favicon - - true -> - nil + if existing_record do + existing_record + |> changeset(%{favicon: favicon, favicon_updated_at: now}) + |> Repo.update() + else + %Instance{} + |> changeset(%{host: host, favicon: favicon, favicon_updated_at: now}) + |> Repo.insert() end + + favicon end end From 312fc55f14e1b7f88ec43b72c577bf5df595beac Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Wed, 8 Jul 2020 05:56:24 +0200 Subject: [PATCH 5/6] Add [:instances_favicons, :enabled] setting, defaults to false --- config/config.exs | 2 ++ config/description.exs | 13 ++++++++++++ config/test.exs | 2 ++ docs/configuration/cheatsheet.md | 6 ++++++ .../web/mastodon_api/views/account_view.ex | 16 +++++++++------ .../mastodon_api/views/account_view_test.exs | 20 +++++++++++++++++++ 6 files changed, 53 insertions(+), 6 deletions(-) diff --git a/config/config.exs b/config/config.exs index 458d3a99a..3577cd101 100644 --- a/config/config.exs +++ b/config/config.exs @@ -706,6 +706,8 @@ config :ex_aws, http_client: Pleroma.HTTP.ExAws +config :pleroma, :instances_favicons, enabled: false + # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. import_config "#{Mix.env()}.exs" diff --git a/config/description.exs b/config/description.exs index 650610fbe..7c432d67d 100644 --- a/config/description.exs +++ b/config/description.exs @@ -3447,5 +3447,18 @@ suggestions: [false] } ] + }, + %{ + group: :pleroma, + key: :instances_favicons, + type: :group, + description: "Control favicons for instances", + children: [ + %{ + key: :enabled, + type: :boolean, + description: "Allow/disallow displaying and getting instances favicons" + } + ] } ] diff --git a/config/test.exs b/config/test.exs index e38b9967d..e6596e0bc 100644 --- a/config/test.exs +++ b/config/test.exs @@ -111,6 +111,8 @@ config :pleroma, Pleroma.Web.ApiSpec.CastAndValidate, strict: true +config :pleroma, :instances_favicons, enabled: true + if File.exists?("./config/test.secret.exs") do import_config "test.secret.exs" else diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 6b640cebc..7a3200e01 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -987,3 +987,9 @@ Restrict access for unauthenticated users to timelines (public and federate), us ## Pleroma.Web.ApiSpec.CastAndValidate * `:strict` a boolean, enables strict input validation (useful in development, not recommended in production). Defaults to `false`. + +## :instances_favicons + +Control favicons for instances. + +* `enabled`: Allow/disallow displaying and getting instances favicons diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index db5739254..2feba4778 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -205,12 +205,16 @@ defp do_render("show.json", %{user: user} = opts) do end favicon = - user - |> Map.get(:ap_id, "") - |> URI.parse() - |> URI.merge("/") - |> Pleroma.Instances.Instance.get_or_update_favicon() - |> MediaProxy.url() + if Pleroma.Config.get([:instances_favicons, :enabled]) do + user + |> Map.get(:ap_id, "") + |> URI.parse() + |> URI.merge("/") + |> Pleroma.Instances.Instance.get_or_update_favicon() + |> MediaProxy.url() + else + nil + end %{ id: to_string(user.id), diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs index c4341cb28..ac6d50e3a 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -5,6 +5,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do use Pleroma.DataCase + alias Pleroma.Config alias Pleroma.User alias Pleroma.UserRelationship alias Pleroma.Web.CommonAPI @@ -18,6 +19,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do :ok end + setup do: clear_config([:instances_favicons, :enabled]) + test "Represent a user account" do background_image = %{ "url" => [%{"href" => "https://example.com/images/asuka_hospital.png"}] @@ -94,6 +97,23 @@ test "Represent a user account" do assert expected == AccountView.render("show.json", %{user: user}) end + test "Favicon is nil when :instances_favicons is disabled" do + user = insert(:user) + + Config.put([:instances_favicons, :enabled], true) + + assert %{ + pleroma: %{ + favicon: + "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png" + } + } = AccountView.render("show.json", %{user: user}) + + Config.put([:instances_favicons, :enabled], false) + + assert %{pleroma: %{favicon: nil}} = AccountView.render("show.json", %{user: user}) + end + test "Represent the user account for the account owner" do user = insert(:user) From 31fef95e35d3cbc2d65c76a57ba8f4047809ce1b Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Wed, 8 Jul 2020 06:09:39 +0200 Subject: [PATCH 6/6] Add changelog and documentation --- CHANGELOG.md | 2 ++ docs/API/differences_in_mastoapi_responses.md | 1 + lib/pleroma/web/api_spec/schemas/account.ex | 6 ++++++ 3 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92d8c3d8e..0f3447069 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Added `:reject_deletes` group to SimplePolicy - MRF (`EmojiStealPolicy`): New MRF Policy which allows to automatically download emojis from remote instances - Support pagination in emoji packs API (for packs and for files in pack) +- Support for viewing instances favicons next to posts and accounts
API Changes @@ -65,6 +66,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Mastodon API: Add support for filtering replies in public and home timelines. - Mastodon API: Support for `bot` field in `/api/v1/accounts/update_credentials`. - Mastodon API: Support irreversible property for filters. +- Mastodon API: Add pleroma.favicon field to accounts. - Admin API: endpoints for create/update/delete OAuth Apps. - Admin API: endpoint for status view. - OTP: Add command to reload emoji packs diff --git a/docs/API/differences_in_mastoapi_responses.md b/docs/API/differences_in_mastoapi_responses.md index 29141ed0c..03c7f4608 100644 --- a/docs/API/differences_in_mastoapi_responses.md +++ b/docs/API/differences_in_mastoapi_responses.md @@ -71,6 +71,7 @@ Has these additional fields under the `pleroma` object: - `unread_conversation_count`: The count of unread conversations. Only returned to the account owner. - `unread_notifications_count`: The count of unread notifications. Only returned to the account owner. - `notification_settings`: object, can be absent. See `/api/pleroma/notification_settings` for the parameters/keys returned. +- `favicon`: nullable URL string, Favicon image of the user's instance ### Source diff --git a/lib/pleroma/web/api_spec/schemas/account.ex b/lib/pleroma/web/api_spec/schemas/account.ex index 84f18f1b6..e6f163cb7 100644 --- a/lib/pleroma/web/api_spec/schemas/account.ex +++ b/lib/pleroma/web/api_spec/schemas/account.ex @@ -102,6 +102,12 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do type: :object, description: "A generic map of settings for frontends. Opaque to the backend. Only returned in `verify_credentials` and `update_credentials`" + }, + favicon: %Schema{ + type: :string, + format: :uri, + nullable: true, + description: "Favicon image of the user's instance" } } },